aboutsummaryrefslogtreecommitdiff
path: root/src/cpu/x86/smm/smm_stub.S
diff options
context:
space:
mode:
authorAaron Durbin <adurbin@chromium.org>2013-01-03 17:38:47 -0600
committerRonald G. Minnich <rminnich@gmail.com>2013-03-14 05:01:50 +0100
commit50a34648cdc7fc55e1fa75d51ece608c0e27245a (patch)
tree4c0853f9500e4b01007b6c24caebbea1007ff9a0 /src/cpu/x86/smm/smm_stub.S
parent5ca4f4119bf00a1ec64358f3e6b41d696b1dc123 (diff)
x86: SMM Module Support
Add support for SMM modules by leveraging the RMODULE lib. This allows for easier dynamic SMM handler placement. The SMM module support consists of a common stub which puts the executing CPU into protected mode and calls into a pre-defined handler. This stub can then be used for SMM relocation as well as the real SMM handler. For the relocation one can call back into coreboot ramstage code to perform relocation in C code. The handler is essentially a copy of smihandler.c, but it drops the TSEG differences. It also doesn't rely on the SMM revision as the cpu code should know what processor it is supported. Ideally the CONFIG_SMM_TSEG option could be removed once the existing users of that option transitioned away from tseg_relocate() and smi_get_tseg_base(). The generic SMI callbacks are now not marked as weak in the declaration so that there aren't unlinked references. The handler has default implementations of the generic SMI callbacks which are marked as weak. If an external compilation module has a strong symbol the linker will use that instead of the link one. Additionally, the parameters to the generic callbacks are dropped as they don't seem to be used directly. The SMM runtime can provide the necessary support if needed. Change-Id: I1e2fed71a40b2eb03197697d29e9c4b246e3b25e Signed-off-by: Aaron Durbin <adurbin@chromium.org> Reviewed-on: http://review.coreboot.org/2693 Tested-by: build bot (Jenkins) Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Diffstat (limited to 'src/cpu/x86/smm/smm_stub.S')
-rw-r--r--src/cpu/x86/smm/smm_stub.S145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/cpu/x86/smm/smm_stub.S b/src/cpu/x86/smm/smm_stub.S
new file mode 100644
index 0000000000..07eb5dcb6d
--- /dev/null
+++ b/src/cpu/x86/smm/smm_stub.S
@@ -0,0 +1,145 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 ChromeOS Authors
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 of
+ * the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+/*
+ * The stub is a generic wrapper for bootstrapping a C-based SMM handler. Its
+ * primary purpose is to put the CPU into protected mode with a stack and call
+ * into the C handler.
+ *
+ * The stub_entry_params structure needs to correspond to the C structure
+ * found in smm.h.
+ */
+
+.code32
+.section ".module_parameters", "aw", @progbits
+stub_entry_params:
+stack_size:
+.long 0
+stack_top:
+.long 0
+c_handler:
+.long 0
+c_handler_arg:
+.long 0
+/* struct smm_runtime begins here. */
+smm_runtime:
+smbase:
+.long 0
+save_state_size:
+.long 0
+/* apic_to_cpu_num is a table mapping the default APIC id to cpu num. If the
+ * APIC id is found at the given index, the contiguous cpu number is index
+ * into the table. */
+apic_to_cpu_num:
+.fill CONFIG_MAX_CPUS,1,0xff
+/* end struct smm_runtime */
+
+.data
+/* Provide fallback stack to use when a valid cpu number cannot be found. */
+fallback_stack_bottom:
+.skip 128
+fallback_stack_top:
+
+.text
+.code16
+.global smm_handler_start
+smm_handler_start:
+ movl $(smm_relocate_gdt), %ebx
+ data32 lgdt (%ebx)
+
+ movl %cr0, %eax
+ andl $0x1FFAFFD1, %eax /* CD,NW,PG,AM,WP,NE,TS,EM,MP = 0 */
+ orl $0x1, %eax /* PE = 1 */
+ movl %eax, %cr0
+
+ /* Enable protected mode */
+ data32 ljmp $0x8, $smm_trampoline32
+
+.align 4
+smm_relocate_gdt:
+ /* The first GDT entry is used for the lgdt instruction. */
+ .word smm_relocate_gdt_end - smm_relocate_gdt - 1
+ .long smm_relocate_gdt
+ .word 0x0000
+
+ /* gdt selector 0x08, flat code segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x9b, 0xcf, 0x00 /* G=1 and 0x0f, 4GB limit */
+
+ /* gdt selector 0x10, flat data segment */
+ .word 0xffff, 0x0000
+ .byte 0x00, 0x93, 0xcf, 0x00
+smm_relocate_gdt_end:
+
+.align 4
+.code32
+.global smm_trampoline32
+smm_trampoline32:
+ /* Use flat data segment */
+ movw $0x10, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %ss
+ movw %ax, %fs
+ movw %ax, %gs
+
+ /* The CPU number is calculated by reading the initial APIC id. Since
+ * the OS can maniuplate the APIC id use the non-changing cpuid result
+ * for APIC id (ebx[31:24]). A table is used to handle a discontiguous
+ * APIC id space. */
+ mov $1, %eax
+ cpuid
+ bswap %ebx /* Default APIC id in bl. */
+ mov $(apic_to_cpu_num), %eax
+ xor %ecx, %ecx
+
+1:
+ cmp (%eax, %ecx, 1), %bl
+ je 1f
+ inc %ecx
+ cmp $CONFIG_MAX_CPUS, %ecx
+ jne 1b
+ /* This is bad. One cannot find a stack entry because a cpu num could
+ * not be assigned. Use the fallback stack and check this condition in
+ * C handler. */
+ movl $(fallback_stack_top), %esp
+ jmp 2f
+1:
+ movl stack_size, %eax
+ mul %ecx
+ movl stack_top, %edx
+ subl %eax, %edx
+ mov %edx, %esp
+
+2:
+ /* Call into the c-based SMM relocation function with the platform
+ * parameters. Equivalent to:
+ * c_handler(c_handler_params, cpu_num, smm_runtime);
+ */
+ push $(smm_runtime)
+ push %ecx
+ push c_handler_arg
+ mov c_handler, %eax
+ call *%eax
+
+ /* Exit from SM mode. */
+ rsm
+