Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the coreboot project. |
| 3 | * |
| 4 | * Copyright (C) 2012 ChromeOS Authors |
| 5 | * |
| 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 |
| 9 | * the License. |
| 10 | * |
| 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. |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | /* |
| 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 |
| 20 | * into the C handler. |
| 21 | * |
| 22 | * The stub_entry_params structure needs to correspond to the C structure |
| 23 | * found in smm.h. |
| 24 | */ |
| 25 | |
| 26 | .code32 |
| 27 | .section ".module_parameters", "aw", @progbits |
| 28 | stub_entry_params: |
| 29 | stack_size: |
| 30 | .long 0 |
| 31 | stack_top: |
| 32 | .long 0 |
| 33 | c_handler: |
| 34 | .long 0 |
| 35 | c_handler_arg: |
| 36 | .long 0 |
| 37 | /* struct smm_runtime begins here. */ |
| 38 | smm_runtime: |
| 39 | smbase: |
| 40 | .long 0 |
| 41 | save_state_size: |
| 42 | .long 0 |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 43 | /* apic_to_cpu_num is a table mapping the default APIC id to CPU num. If the |
| 44 | * 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] | 45 | * into the table. */ |
| 46 | apic_to_cpu_num: |
| 47 | .fill CONFIG_MAX_CPUS,1,0xff |
| 48 | /* end struct smm_runtime */ |
| 49 | |
| 50 | .data |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 51 | /* 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] | 52 | fallback_stack_bottom: |
| 53 | .skip 128 |
| 54 | fallback_stack_top: |
| 55 | |
| 56 | .text |
| 57 | .code16 |
Aaron Durbin | dde7629 | 2015-09-05 12:59:26 -0500 | [diff] [blame] | 58 | .global _start |
| 59 | _start: |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 60 | movl $(smm_relocate_gdt), %ebx |
| 61 | data32 lgdt (%ebx) |
| 62 | |
| 63 | movl %cr0, %eax |
| 64 | andl $0x1FFAFFD1, %eax /* CD,NW,PG,AM,WP,NE,TS,EM,MP = 0 */ |
| 65 | orl $0x1, %eax /* PE = 1 */ |
| 66 | movl %eax, %cr0 |
| 67 | |
| 68 | /* Enable protected mode */ |
| 69 | data32 ljmp $0x8, $smm_trampoline32 |
| 70 | |
| 71 | .align 4 |
| 72 | smm_relocate_gdt: |
| 73 | /* The first GDT entry is used for the lgdt instruction. */ |
| 74 | .word smm_relocate_gdt_end - smm_relocate_gdt - 1 |
| 75 | .long smm_relocate_gdt |
| 76 | .word 0x0000 |
| 77 | |
| 78 | /* gdt selector 0x08, flat code segment */ |
| 79 | .word 0xffff, 0x0000 |
| 80 | .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, 4GB limit */ |
| 81 | |
| 82 | /* gdt selector 0x10, flat data segment */ |
| 83 | .word 0xffff, 0x0000 |
| 84 | .byte 0x00, 0x93, 0xcf, 0x00 |
| 85 | smm_relocate_gdt_end: |
| 86 | |
| 87 | .align 4 |
| 88 | .code32 |
| 89 | .global smm_trampoline32 |
| 90 | smm_trampoline32: |
| 91 | /* Use flat data segment */ |
| 92 | movw $0x10, %ax |
| 93 | movw %ax, %ds |
| 94 | movw %ax, %es |
| 95 | movw %ax, %ss |
| 96 | movw %ax, %fs |
| 97 | movw %ax, %gs |
| 98 | |
| 99 | /* The CPU number is calculated by reading the initial APIC id. Since |
| 100 | * the OS can maniuplate the APIC id use the non-changing cpuid result |
| 101 | * for APIC id (ebx[31:24]). A table is used to handle a discontiguous |
| 102 | * APIC id space. */ |
| 103 | mov $1, %eax |
| 104 | cpuid |
| 105 | bswap %ebx /* Default APIC id in bl. */ |
| 106 | mov $(apic_to_cpu_num), %eax |
| 107 | xor %ecx, %ecx |
| 108 | |
| 109 | 1: |
| 110 | cmp (%eax, %ecx, 1), %bl |
| 111 | je 1f |
| 112 | inc %ecx |
| 113 | cmp $CONFIG_MAX_CPUS, %ecx |
| 114 | jne 1b |
Elyes HAOUAS | d82be92 | 2016-07-28 18:58:27 +0200 | [diff] [blame] | 115 | /* 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] | 116 | * not be assigned. Use the fallback stack and check this condition in |
| 117 | * C handler. */ |
| 118 | movl $(fallback_stack_top), %esp |
| 119 | jmp 2f |
| 120 | 1: |
| 121 | movl stack_size, %eax |
| 122 | mul %ecx |
| 123 | movl stack_top, %edx |
| 124 | subl %eax, %edx |
| 125 | mov %edx, %esp |
| 126 | |
| 127 | 2: |
| 128 | /* Call into the c-based SMM relocation function with the platform |
| 129 | * parameters. Equivalent to: |
Aaron Durbin | 3eb8eb7 | 2014-03-10 16:13:58 -0500 | [diff] [blame] | 130 | * struct arg = { c_handler_params, cpu_num, smm_runtime {; |
| 131 | * c_handler(&arg) |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 132 | */ |
| 133 | push $(smm_runtime) |
| 134 | push %ecx |
| 135 | push c_handler_arg |
Aaron Durbin | 3eb8eb7 | 2014-03-10 16:13:58 -0500 | [diff] [blame] | 136 | push %esp |
Aaron Durbin | 50a3464 | 2013-01-03 17:38:47 -0600 | [diff] [blame] | 137 | mov c_handler, %eax |
| 138 | call *%eax |
| 139 | |
| 140 | /* Exit from SM mode. */ |
| 141 | rsm |