smm: Add canary to end of stack and die() if a stack overflow occurs
[coreboot.git] / src / cpu / x86 / smm / smm_stub.S
blobeb890df15003b781cce12f834c5712be2a3dce2d
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.
15  */
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  */
26 #include <cpu/x86/cr.h>
28 .code32
29 .section ".module_parameters", "aw", @progbits
30 stub_entry_params:
31 stack_size:
32 .long 0
33 stack_top:
34 .long 0
35 c_handler:
36 .long 0
37 c_handler_arg:
38 .long 0
39 fxsave_area:
40 .long 0
41 fxsave_area_size:
42 .long 0
43 /* struct smm_runtime begins here. */
44 smm_runtime:
45 smbase:
46 .long 0
47 save_state_size:
48 .long 0
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
51  * into the table. */
52 apic_to_cpu_num:
53 .fill CONFIG_MAX_CPUS,1,0xff
54 /* end struct smm_runtime */
56 .data
57 /* Provide fallback stack to use when a valid CPU number cannot be found. */
58 fallback_stack_bottom:
59 .skip 128
60 fallback_stack_top:
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)
66 .text
67 .code16
68 .global _start
69 _start:
70         movl    $(smm_relocate_gdt), %ebx
71         lgdtl   (%ebx)
73         movl    %cr0, %eax
74         andl    $~CR0_CLEAR_FLAGS, %eax
75         orl     $CR0_PE, %eax
76         movl    %eax, %cr0
78         /* Enable protected mode */
79         ljmpl   $0x8, $smm_trampoline32
81 .align 4
82 smm_relocate_gdt:
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
86         .word   0x0000
88         /* gdt selector 0x08, flat code segment */
89         .word   0xffff, 0x0000
90         .byte   0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, 4GB limit */
92         /* gdt selector 0x10, flat data segment */
93         .word   0xffff, 0x0000
94         .byte   0x00, 0x93, 0xcf, 0x00
95 smm_relocate_gdt_end:
97 .align 4
98 .code32
99 .global smm_trampoline32
100 smm_trampoline32:
101         /* Use flat data segment */
102         movw    $0x10, %ax
103         movw    %ax, %ds
104         movw    %ax, %es
105         movw    %ax, %ss
106         movw    %ax, %fs
107         movw    %ax, %gs
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
112          * APIC id space.  */
113         mov     $1, %eax
114         cpuid
115         bswap   %ebx    /* Default APIC id in bl. */
116         mov     $(apic_to_cpu_num), %eax
117         xor     %ecx, %ecx
120         cmp     (%eax, %ecx, 1), %bl
121         je      1f
122         inc     %ecx
123         cmp     $CONFIG_MAX_CPUS, %ecx
124         jne     1b
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
127          * C handler. */
128         movl    $(fallback_stack_top), %esp
129         /* Clear fxsave location as there will be no saving/restoring. */
130         xor     %edi, %edi
131         jmp     2f
133         movl    stack_size, %eax
134         mul     %ecx /* %eax(stack_size) * %ecx(cpu) = %eax(offset) */
135         movl    stack_top, %ebx
136         subl    %eax, %ebx /* global_stack_top - offset = stack_top */
137         mov     %ebx, %esp
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) */
142         movl    %ebx, (%ebx)
144         /* Create stack frame by pushing a NULL stack base pointer */
145         pushl   $0x0
146         mov     %esp, %ebp
148         /* Allocate locals (fxsave) */
149         subl    $0x4, %esp
151         /* calculate fxsave location */
152         mov     fxsave_area, %edi
153         test    %edi, %edi
154         jz      2f
155         movl    fxsave_area_size, %eax
156         mul     %ecx
157         add     %eax, %edi
160         /* Save location of fxsave area. */
161         mov     %edi, -4(%ebp)
162         test    %edi, %edi
163         jz      1f
165         /* Enable sse instructions. */
166         mov     %cr4, %eax
167         orl     $(CR4_OSFXSR | CR4_OSXMMEXCPT), %eax
168         mov     %eax, %cr4
170         /* Save FP state. */
171         fxsave  (%edi)
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 };
180          *   c_handler(&arg)
181          */
182         push    $0x0 /* Padding */
183         push    $0x0 /* Padding */
184         push    $0x0 /* Padding */
185         push    %ebx /* uintptr_t *canary */
186         push    $(smm_runtime)
187         push    %ecx /* int cpu */
188         push    c_handler_arg /* void *arg */
189         push    %esp /* smm_module_params *arg (allocated on stack). */
190         mov     c_handler, %eax
191         call    *%eax
193         /* Retrieve fxsave location. */
194         mov     -4(%ebp), %edi
195         test    %edi, %edi
196         jz      1f
198         /* Restore FP state. */
199         fxrstor (%edi)
202         /* Exit from SM mode. */
203         rsm