blob: 45f634d0c9f6a3d2eb02be3059e5f30adc5b7836 [file] [log] [blame]
Angel Ponsf23ae0b2020-04-02 23:48:12 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Aaron Durbin50a34642013-01-03 17:38:47 -06002
3/*
4 * The stub is a generic wrapper for bootstrapping a C-based SMM handler. Its
5 * primary purpose is to put the CPU into protected mode with a stack and call
6 * into the C handler.
7 *
8 * The stub_entry_params structure needs to correspond to the C structure
9 * found in smm.h.
10 */
11
Aaron Durbin9e01a0b2017-06-16 14:12:55 -050012#include <cpu/x86/cr.h>
Patrick Rudolph24bb8032019-12-01 07:04:04 +010013#include <cpu/x86/msr.h>
Aaron Durbin9e01a0b2017-06-16 14:12:55 -050014
Aaron Durbin50a34642013-01-03 17:38:47 -060015.code32
16.section ".module_parameters", "aw", @progbits
17stub_entry_params:
18stack_size:
19.long 0
20stack_top:
21.long 0
22c_handler:
23.long 0
24c_handler_arg:
25.long 0
Aaron Durbin8ade68a2017-06-16 15:16:13 -050026fxsave_area:
27.long 0
28fxsave_area_size:
29.long 0
Aaron Durbin50a34642013-01-03 17:38:47 -060030/* struct smm_runtime begins here. */
31smm_runtime:
32smbase:
33.long 0
Arthur Heymansa3eb3df2019-11-27 16:21:46 +010034smm_size:
35.long 0
Aaron Durbin50a34642013-01-03 17:38:47 -060036save_state_size:
37.long 0
Eugene Myersae438be2020-01-21 17:01:47 -050038num_cpus:
39.long 0
Kyösti Mälkkie769bce2020-06-16 21:37:05 +030040gnvs_ptr:
41.long 0
Eugene Myersae438be2020-01-21 17:01:47 -050042/* allows the STM to bring up SMM in 32-bit mode */
43start32_offset:
44.long smm_trampoline32 - _start
Elyes HAOUASd82be922016-07-28 18:58:27 +020045/* apic_to_cpu_num is a table mapping the default APIC id to CPU num. If the
46 * APIC id is found at the given index, the contiguous CPU number is index
Aaron Durbin50a34642013-01-03 17:38:47 -060047 * into the table. */
48apic_to_cpu_num:
49.fill CONFIG_MAX_CPUS,1,0xff
50/* end struct smm_runtime */
51
52.data
Elyes HAOUASd82be922016-07-28 18:58:27 +020053/* Provide fallback stack to use when a valid CPU number cannot be found. */
Aaron Durbin50a34642013-01-03 17:38:47 -060054fallback_stack_bottom:
55.skip 128
56fallback_stack_top:
57
Aaron Durbin9e01a0b2017-06-16 14:12:55 -050058#define CR0_CLEAR_FLAGS \
59 (CR0_CD | CR0_NW | CR0_PG | CR0_AM | CR0_WP | \
60 CR0_NE | CR0_TS | CR0_EM | CR0_MP)
61
Aaron Durbin50a34642013-01-03 17:38:47 -060062.text
63.code16
Aaron Durbindde76292015-09-05 12:59:26 -050064.global _start
65_start:
Aaron Durbin50a34642013-01-03 17:38:47 -060066 movl $(smm_relocate_gdt), %ebx
Edward O'Callaghan4e2294b2017-01-08 19:14:42 +110067 lgdtl (%ebx)
Aaron Durbin50a34642013-01-03 17:38:47 -060068
69 movl %cr0, %eax
Aaron Durbin9e01a0b2017-06-16 14:12:55 -050070 andl $~CR0_CLEAR_FLAGS, %eax
71 orl $CR0_PE, %eax
Aaron Durbin50a34642013-01-03 17:38:47 -060072 movl %eax, %cr0
73
74 /* Enable protected mode */
Edward O'Callaghan4e2294b2017-01-08 19:14:42 +110075 ljmpl $0x8, $smm_trampoline32
Aaron Durbin50a34642013-01-03 17:38:47 -060076
77.align 4
78smm_relocate_gdt:
79 /* The first GDT entry is used for the lgdt instruction. */
80 .word smm_relocate_gdt_end - smm_relocate_gdt - 1
81 .long smm_relocate_gdt
82 .word 0x0000
83
84 /* gdt selector 0x08, flat code segment */
85 .word 0xffff, 0x0000
86 .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, 4GB limit */
87
88 /* gdt selector 0x10, flat data segment */
89 .word 0xffff, 0x0000
90 .byte 0x00, 0x93, 0xcf, 0x00
Eugene Myersae438be2020-01-21 17:01:47 -050091
92 /* gdt selector 0x18, flat code segment (64-bit) */
93 .word 0xffff, 0x0000
Patrick Rudolph9e7497e2020-12-01 16:14:31 +010094 .byte 0x00, 0x9b, 0xaf, 0x00
Eugene Myersae438be2020-01-21 17:01:47 -050095
96 /* gdt selector 0x20 tss segment */
97 .word 0xffff, 0x0000
98 .byte 0x00, 0x8b, 0x80, 0x00
Aaron Durbin50a34642013-01-03 17:38:47 -060099smm_relocate_gdt_end:
100
101.align 4
102.code32
103.global smm_trampoline32
104smm_trampoline32:
105 /* Use flat data segment */
106 movw $0x10, %ax
107 movw %ax, %ds
108 movw %ax, %es
109 movw %ax, %ss
110 movw %ax, %fs
111 movw %ax, %gs
112
113 /* The CPU number is calculated by reading the initial APIC id. Since
114 * the OS can maniuplate the APIC id use the non-changing cpuid result
115 * for APIC id (ebx[31:24]). A table is used to handle a discontiguous
116 * APIC id space. */
117 mov $1, %eax
118 cpuid
119 bswap %ebx /* Default APIC id in bl. */
120 mov $(apic_to_cpu_num), %eax
121 xor %ecx, %ecx
122
1231:
124 cmp (%eax, %ecx, 1), %bl
125 je 1f
126 inc %ecx
127 cmp $CONFIG_MAX_CPUS, %ecx
128 jne 1b
Elyes HAOUASd82be922016-07-28 18:58:27 +0200129 /* This is bad. One cannot find a stack entry because a CPU num could
Aaron Durbin50a34642013-01-03 17:38:47 -0600130 * not be assigned. Use the fallback stack and check this condition in
131 * C handler. */
132 movl $(fallback_stack_top), %esp
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500133 /* Clear fxsave location as there will be no saving/restoring. */
134 xor %edi, %edi
Aaron Durbin50a34642013-01-03 17:38:47 -0600135 jmp 2f
1361:
137 movl stack_size, %eax
Raul E Rangel01405412018-06-25 14:22:27 -0600138 mul %ecx /* %eax(stack_size) * %ecx(cpu) = %eax(offset) */
Raul E Rangele18e5ab2018-06-25 14:22:27 -0600139 movl stack_top, %ebx
140 subl %eax, %ebx /* global_stack_top - offset = stack_top */
141 mov %ebx, %esp
Raul E Rangel87115682018-06-25 14:22:27 -0600142
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600143 /* Write canary to the bottom of the stack */
144 movl stack_size, %eax
145 subl %eax, %ebx /* %ebx(stack_top) - size = %ebx(stack_bottom) */
146 movl %ebx, (%ebx)
Patrick Rudolph484adee2020-12-01 16:35:30 +0100147#if ENV_X86_64
148 movl $0, 4(%ebx)
149#endif
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600150
Raul E Rangel87115682018-06-25 14:22:27 -0600151 /* Create stack frame by pushing a NULL stack base pointer */
152 pushl $0x0
Raul E Rangel01405412018-06-25 14:22:27 -0600153 mov %esp, %ebp
154
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100155 /* Allocate locals (fxsave, efer_backup) */
156 subl $0xc, %esp
Aaron Durbin50a34642013-01-03 17:38:47 -0600157
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500158 /* calculate fxsave location */
159 mov fxsave_area, %edi
160 test %edi, %edi
161 jz 2f
162 movl fxsave_area_size, %eax
163 mul %ecx
164 add %eax, %edi
165
Aaron Durbin50a34642013-01-03 17:38:47 -06001662:
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500167 /* Save location of fxsave area. */
Raul E Rangel01405412018-06-25 14:22:27 -0600168 mov %edi, -4(%ebp)
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500169 test %edi, %edi
170 jz 1f
171
172 /* Enable sse instructions. */
173 mov %cr4, %eax
174 orl $(CR4_OSFXSR | CR4_OSXMMEXCPT), %eax
175 mov %eax, %cr4
176
177 /* Save FP state. */
178 fxsave (%edi)
179
1801:
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600181 /* Align stack to 16 bytes. Another 32 bytes are pushed below. */
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500182 andl $0xfffffff0, %esp
183
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100184#ifdef __x86_64__
185 mov %ecx, %edi
186 /* Backup IA32_EFER. Preserves ebx. */
187 movl $(IA32_EFER), %ecx
188 rdmsr
189 movl %eax, -0x8(%ebp)
190 movl %edx, -0xc(%ebp)
191
192 /* entry64.inc preserves ebx, esi, edi */
193#include <cpu/x86/64bit/entry64.inc>
194 mov %edi, %ecx
195
196#endif
197
Aaron Durbin50a34642013-01-03 17:38:47 -0600198 /* Call into the c-based SMM relocation function with the platform
199 * parameters. Equivalent to:
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600200 * struct arg = { c_handler_params, cpu_num, smm_runtime, canary };
Aaron Durbin3eb8eb72014-03-10 16:13:58 -0500201 * c_handler(&arg)
Aaron Durbin50a34642013-01-03 17:38:47 -0600202 */
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100203#ifdef __x86_64__
204 push %rbx /* uintptr_t *canary */
205 push $(smm_runtime)
206 push %rcx /* size_t cpu */
207 push c_handler_arg /* void *arg */
208
209 mov %rsp, %rdi /* *arg */
210
211 movl c_handler, %eax
212 call *%rax
213
214 /*
215 * The only reason to go back to protected mode is that RSM doesn't restore
216 * MSR registers and MSR IA32_EFER was modified by entering long mode.
217 * Drop to protected mode to safely operate on the IA32_EFER MSR.
218 */
219
220 /* Disable long mode. */
221 #include <cpu/x86/64bit/exit32.inc>
222
223 /* Restore IA32_EFER as RSM doesn't restore MSRs. */
224 movl $(IA32_EFER), %ecx
225 rdmsr
226 movl -0x8(%ebp), %eax
227 movl -0xc(%ebp), %edx
228
229 wrmsr
230
231#else
Raul E Rangeleb5d76a2018-06-25 14:22:27 -0600232 push $0x0 /* Padding */
233 push $0x0 /* Padding */
234 push $0x0 /* Padding */
235 push %ebx /* uintptr_t *canary */
Aaron Durbin50a34642013-01-03 17:38:47 -0600236 push $(smm_runtime)
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100237 push %ecx /* size_t cpu */
Raul E Rangel01405412018-06-25 14:22:27 -0600238 push c_handler_arg /* void *arg */
239 push %esp /* smm_module_params *arg (allocated on stack). */
Aaron Durbin50a34642013-01-03 17:38:47 -0600240 mov c_handler, %eax
241 call *%eax
Patrick Rudolph24bb8032019-12-01 07:04:04 +0100242#endif
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500243 /* Retrieve fxsave location. */
Raul E Rangel01405412018-06-25 14:22:27 -0600244 mov -4(%ebp), %edi
Aaron Durbin8ade68a2017-06-16 15:16:13 -0500245 test %edi, %edi
246 jz 1f
247
248 /* Restore FP state. */
249 fxrstor (%edi)
250
2511:
Aaron Durbin50a34642013-01-03 17:38:47 -0600252 /* Exit from SM mode. */
253 rsm