2 * This file is part of the coreboot project.
4 * Copyright (C) 2012 ChromeOS Authors
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
18 * The stub is a generic wrapper for bootstrapping a C-based SMM handler. Its
19 * primary purpose is to put the CPU into protected mode with a stack and call
22 * The stub_entry_params structure needs to correspond to the C structure
26 #include <cpu/x86/cr.h>
29 .section ".module_parameters", "aw", @progbits
43 /* struct smm_runtime begins here. */
49 /* apic_to_cpu_num is a table mapping the default APIC id to CPU num. If the
50 * APIC id is found at the given index, the contiguous CPU number is index
53 .fill CONFIG_MAX_CPUS,1,0xff
54 /* end struct smm_runtime */
57 /* Provide fallback stack to use when a valid CPU number cannot be found. */
58 fallback_stack_bottom:
62 #define CR0_CLEAR_FLAGS \
63 (CR0_CD | CR0_NW | CR0_PG | CR0_AM | CR0_WP | \
64 CR0_NE | CR0_TS | CR0_EM | CR0_MP)
70 movl $(smm_relocate_gdt), %ebx
74 andl $~CR0_CLEAR_FLAGS, %eax
78 /* Enable protected mode */
79 ljmpl $0x8, $smm_trampoline32
83 /* The first GDT entry is used for the lgdt instruction. */
84 .word smm_relocate_gdt_end - smm_relocate_gdt - 1
85 .long smm_relocate_gdt
88 /* gdt selector 0x08, flat code segment */
90 .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, 4GB limit */
92 /* gdt selector 0x10, flat data segment */
94 .byte 0x00, 0x93, 0xcf, 0x00
99 .global smm_trampoline32
101 /* Use flat data segment */
109 /* The CPU number is calculated by reading the initial APIC id. Since
110 * the OS can maniuplate the APIC id use the non-changing cpuid result
111 * for APIC id (ebx[31:24]). A table is used to handle a discontiguous
115 bswap %ebx /* Default APIC id in bl. */
116 mov $(apic_to_cpu_num), %eax
120 cmp (%eax, %ecx, 1), %bl
123 cmp $CONFIG_MAX_CPUS, %ecx
125 /* This is bad. One cannot find a stack entry because a CPU num could
126 * not be assigned. Use the fallback stack and check this condition in
128 movl $(fallback_stack_top), %esp
129 /* Clear fxsave location as there will be no saving/restoring. */
133 movl stack_size, %eax
134 mul %ecx /* %eax(stack_size) * %ecx(cpu) = %eax(offset) */
136 subl %eax, %ebx /* global_stack_top - offset = stack_top */
139 /* Write canary to the bottom of the stack */
140 movl stack_size, %eax
141 subl %eax, %ebx /* %ebx(stack_top) - size = %ebx(stack_bottom) */
144 /* Create stack frame by pushing a NULL stack base pointer */
148 /* Allocate locals (fxsave) */
151 /* calculate fxsave location */
152 mov fxsave_area, %edi
155 movl fxsave_area_size, %eax
160 /* Save location of fxsave area. */
165 /* Enable sse instructions. */
167 orl $(CR4_OSFXSR | CR4_OSXMMEXCPT), %eax
174 /* Align stack to 16 bytes. Another 32 bytes are pushed below. */
175 andl $0xfffffff0, %esp
177 /* Call into the c-based SMM relocation function with the platform
178 * parameters. Equivalent to:
179 * struct arg = { c_handler_params, cpu_num, smm_runtime, canary };
182 push $0x0 /* Padding */
183 push $0x0 /* Padding */
184 push $0x0 /* Padding */
185 push %ebx /* uintptr_t *canary */
187 push %ecx /* int cpu */
188 push c_handler_arg /* void *arg */
189 push %esp /* smm_module_params *arg (allocated on stack). */
193 /* Retrieve fxsave location. */
198 /* Restore FP state. */
202 /* Exit from SM mode. */