Angel Pons | f23ae0b | 2020-04-02 23:48:12 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 2 | |
| 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 Durbin | 9e01a0b | 2017-06-16 14:12:55 -0500 | [diff] [blame] | 12 | #include <cpu/x86/cr.h> |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 13 | #include <cpu/x86/msr.h> |
Aaron Durbin | 9e01a0b | 2017-06-16 14:12:55 -0500 | [diff] [blame] | 14 | |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 15 | .code32 |
| 16 | .section ".module_parameters", "aw", @progbits |
| 17 | stub_entry_params: |
| 18 | stack_size: |
| 19 | .long 0 |
| 20 | stack_top: |
| 21 | .long 0 |
| 22 | c_handler: |
| 23 | .long 0 |
| 24 | c_handler_arg: |
| 25 | .long 0 |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 26 | fxsave_area: |
| 27 | .long 0 |
| 28 | fxsave_area_size: |
| 29 | .long 0 |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 30 | /* struct smm_runtime begins here. */ |
| 31 | smm_runtime: |
| 32 | smbase: |
| 33 | .long 0 |
Arthur Heymans | a3eb3df | 2019-11-27 16:21:46 +0100 | [diff] [blame] | 34 | smm_size: |
| 35 | .long 0 |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 36 | save_state_size: |
| 37 | .long 0 |
Eugene Myers | ae438be | 2020-01-21 17:01:47 -0500 | [diff] [blame] | 38 | num_cpus: |
| 39 | .long 0 |
Kyösti Mälkki | e769bce | 2020-06-16 21:37:05 +0300 | [diff] [blame] | 40 | gnvs_ptr: |
| 41 | .long 0 |
Eugene Myers | ae438be | 2020-01-21 17:01:47 -0500 | [diff] [blame] | 42 | /* allows the STM to bring up SMM in 32-bit mode */ |
| 43 | start32_offset: |
| 44 | .long smm_trampoline32 - _start |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 45 | /* 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 Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 47 | * into the table. */ |
| 48 | apic_to_cpu_num: |
| 49 | .fill CONFIG_MAX_CPUS,1,0xff |
| 50 | /* end struct smm_runtime */ |
| 51 | |
| 52 | .data |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 53 | /* Provide fallback stack to use when a valid CPU number cannot be found. */ |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 54 | fallback_stack_bottom: |
| 55 | .skip 128 |
| 56 | fallback_stack_top: |
| 57 | |
Aaron Durbin | 9e01a0b | 2017-06-16 14:12:55 -0500 | [diff] [blame] | 58 | #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 Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 62 | .text |
| 63 | .code16 |
Aaron Durbin | dde7629 | 2015-09-05 12:59:26 -0500 | [diff] [blame] | 64 | .global _start |
| 65 | _start: |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 66 | movl $(smm_relocate_gdt), %ebx |
Edward O'Callaghan | 4e2294b | 2017-01-08 19:14:42 +1100 | [diff] [blame] | 67 | lgdtl (%ebx) |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 68 | |
| 69 | movl %cr0, %eax |
Aaron Durbin | 9e01a0b | 2017-06-16 14:12:55 -0500 | [diff] [blame] | 70 | andl $~CR0_CLEAR_FLAGS, %eax |
| 71 | orl $CR0_PE, %eax |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 72 | movl %eax, %cr0 |
| 73 | |
| 74 | /* Enable protected mode */ |
Edward O'Callaghan | 4e2294b | 2017-01-08 19:14:42 +1100 | [diff] [blame] | 75 | ljmpl $0x8, $smm_trampoline32 |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 76 | |
| 77 | .align 4 |
| 78 | smm_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 Myers | ae438be | 2020-01-21 17:01:47 -0500 | [diff] [blame] | 91 | |
| 92 | /* gdt selector 0x18, flat code segment (64-bit) */ |
| 93 | .word 0xffff, 0x0000 |
Patrick Rudolph | 9e7497e | 2020-12-01 16:14:31 +0100 | [diff] [blame] | 94 | .byte 0x00, 0x9b, 0xaf, 0x00 |
Eugene Myers | ae438be | 2020-01-21 17:01:47 -0500 | [diff] [blame] | 95 | |
| 96 | /* gdt selector 0x20 tss segment */ |
| 97 | .word 0xffff, 0x0000 |
| 98 | .byte 0x00, 0x8b, 0x80, 0x00 |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 99 | smm_relocate_gdt_end: |
| 100 | |
| 101 | .align 4 |
| 102 | .code32 |
| 103 | .global smm_trampoline32 |
| 104 | smm_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 | |
| 123 | 1: |
| 124 | cmp (%eax, %ecx, 1), %bl |
| 125 | je 1f |
| 126 | inc %ecx |
| 127 | cmp $CONFIG_MAX_CPUS, %ecx |
| 128 | jne 1b |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 129 | /* This is bad. One cannot find a stack entry because a CPU num could |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 130 | * not be assigned. Use the fallback stack and check this condition in |
| 131 | * C handler. */ |
| 132 | movl $(fallback_stack_top), %esp |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 133 | /* Clear fxsave location as there will be no saving/restoring. */ |
| 134 | xor %edi, %edi |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 135 | jmp 2f |
| 136 | 1: |
| 137 | movl stack_size, %eax |
Raul E Rangel | 0140541 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 138 | mul %ecx /* %eax(stack_size) * %ecx(cpu) = %eax(offset) */ |
Raul E Rangel | e18e5ab | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 139 | movl stack_top, %ebx |
| 140 | subl %eax, %ebx /* global_stack_top - offset = stack_top */ |
| 141 | mov %ebx, %esp |
Raul E Rangel | 8711568 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 142 | |
Raul E Rangel | eb5d76a | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 143 | /* 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 Rudolph | 484adee | 2020-12-01 16:35:30 +0100 | [diff] [blame^] | 147 | #if ENV_X86_64 |
| 148 | movl $0, 4(%ebx) |
| 149 | #endif |
Raul E Rangel | eb5d76a | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 150 | |
Raul E Rangel | 8711568 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 151 | /* Create stack frame by pushing a NULL stack base pointer */ |
| 152 | pushl $0x0 |
Raul E Rangel | 0140541 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 153 | mov %esp, %ebp |
| 154 | |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 155 | /* Allocate locals (fxsave, efer_backup) */ |
| 156 | subl $0xc, %esp |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 157 | |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 158 | /* 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 Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 166 | 2: |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 167 | /* Save location of fxsave area. */ |
Raul E Rangel | 0140541 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 168 | mov %edi, -4(%ebp) |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 169 | 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 | |
| 180 | 1: |
Raul E Rangel | eb5d76a | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 181 | /* Align stack to 16 bytes. Another 32 bytes are pushed below. */ |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 182 | andl $0xfffffff0, %esp |
| 183 | |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 184 | #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 Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 198 | /* Call into the c-based SMM relocation function with the platform |
| 199 | * parameters. Equivalent to: |
Raul E Rangel | eb5d76a | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 200 | * struct arg = { c_handler_params, cpu_num, smm_runtime, canary }; |
Aaron Durbin | 3eb8eb7 | 2014-03-10 16:13:58 -0500 | [diff] [blame] | 201 | * c_handler(&arg) |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 202 | */ |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 203 | #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 Rangel | eb5d76a | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 232 | push $0x0 /* Padding */ |
| 233 | push $0x0 /* Padding */ |
| 234 | push $0x0 /* Padding */ |
| 235 | push %ebx /* uintptr_t *canary */ |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 236 | push $(smm_runtime) |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 237 | push %ecx /* size_t cpu */ |
Raul E Rangel | 0140541 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 238 | push c_handler_arg /* void *arg */ |
| 239 | push %esp /* smm_module_params *arg (allocated on stack). */ |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 240 | mov c_handler, %eax |
| 241 | call *%eax |
Patrick Rudolph | 24bb803 | 2019-12-01 07:04:04 +0100 | [diff] [blame] | 242 | #endif |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 243 | /* Retrieve fxsave location. */ |
Raul E Rangel | 0140541 | 2018-06-25 14:22:27 -0600 | [diff] [blame] | 244 | mov -4(%ebp), %edi |
Aaron Durbin | 8ade68a | 2017-06-16 15:16:13 -0500 | [diff] [blame] | 245 | test %edi, %edi |
| 246 | jz 1f |
| 247 | |
| 248 | /* Restore FP state. */ |
| 249 | fxrstor (%edi) |
| 250 | |
| 251 | 1: |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 252 | /* Exit from SM mode. */ |
| 253 | rsm |