diff options
author | Aaron Durbin <adurbin@chromium.org> | 2013-01-03 17:38:47 -0600 |
---|---|---|
committer | Ronald G. Minnich <rminnich@gmail.com> | 2013-03-14 05:01:50 +0100 |
commit | 50a34648cdc7fc55e1fa75d51ece608c0e27245a (patch) | |
tree | 4c0853f9500e4b01007b6c24caebbea1007ff9a0 /src/cpu/x86/smm/smm_module_handler.c | |
parent | 5ca4f4119bf00a1ec64358f3e6b41d696b1dc123 (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_module_handler.c')
-rw-r--r-- | src/cpu/x86/smm/smm_module_handler.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/cpu/x86/smm/smm_module_handler.c b/src/cpu/x86/smm/smm_module_handler.c new file mode 100644 index 0000000000..67802d6431 --- /dev/null +++ b/src/cpu/x86/smm/smm_module_handler.c @@ -0,0 +1,171 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2013 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 + */ + +#include <arch/io.h> +#include <arch/romcc_io.h> +#include <console/console.h> +#include <cpu/x86/smm.h> + +typedef enum { SMI_LOCKED, SMI_UNLOCKED } smi_semaphore; + +/* SMI multiprocessing semaphore */ +static volatile +smi_semaphore smi_handler_status __attribute__ ((aligned (4))) = SMI_UNLOCKED; + +static int smi_obtain_lock(void) +{ + u8 ret = SMI_LOCKED; + + asm volatile ( + "movb %2, %%al\n" + "xchgb %%al, %1\n" + "movb %%al, %0\n" + : "=g" (ret), "=m" (smi_handler_status) + : "g" (SMI_LOCKED) + : "eax" + ); + + return (ret == SMI_UNLOCKED); +} + +static void smi_release_lock(void) +{ + asm volatile ( + "movb %1, %%al\n" + "xchgb %%al, %0\n" + : "=m" (smi_handler_status) + : "g" (SMI_UNLOCKED) + : "eax" + ); +} + +void io_trap_handler(int smif) +{ + /* If a handler function handled a given IO trap, it + * shall return a non-zero value + */ + printk(BIOS_DEBUG, "SMI function trap 0x%x: ", smif); + + if (southbridge_io_trap_handler(smif)) + return; + + if (mainboard_io_trap_handler(smif)) + return; + + printk(BIOS_DEBUG, "Unknown function\n"); +} + +/** + * @brief Set the EOS bit + */ +static void smi_set_eos(void) +{ + southbridge_smi_set_eos(); +} + + +static u32 pci_orig; + +/** + * @brief Backup PCI address to make sure we do not mess up the OS + */ +static void smi_backup_pci_address(void) +{ + pci_orig = inl(0xcf8); +} + +/** + * @brief Restore PCI address previously backed up + */ +static void smi_restore_pci_address(void) +{ + outl(pci_orig, 0xcf8); +} + + +static const struct smm_runtime *smm_runtime; + +void *smm_get_save_state(int cpu) +{ + char *base; + + /* This function assumes all save states start at top of default + * SMRAM size space and are staggered down by save state size. */ + base = (void *)smm_runtime->smbase; + base += SMM_DEFAULT_SIZE; + base -= (cpu + 1) * smm_runtime->save_state_size; + + return base; +} + +void smm_handler_start(void *arg, int cpu, const struct smm_runtime *runtime) +{ + /* Make sure to set the global runtime. It's OK to race as the value + * will be the same across CPUs as well as multiple SMIs. */ + if (smm_runtime == NULL) + smm_runtime = runtime; + + if (cpu >= CONFIG_MAX_CPUS) { + console_init(); + printk(BIOS_CRIT, + "Invalid CPU number assigned in SMM stub: %d\n", cpu); + return; + } + + /* Are we ok to execute the handler? */ + if (!smi_obtain_lock()) { + /* For security reasons we don't release the other CPUs + * until the CPU with the lock is actually done */ + while (smi_handler_status == SMI_LOCKED) { + asm volatile ( + ".byte 0xf3, 0x90\n" /* PAUSE */ + ); + } + return; + } + + smi_backup_pci_address(); + + console_init(); + + printk(BIOS_SPEW, "\nSMI# #%d\n", cpu); + + cpu_smi_handler(); + northbridge_smi_handler(); + southbridge_smi_handler(); + + smi_restore_pci_address(); + + smi_release_lock(); + + /* De-assert SMI# signal to allow another SMI */ + smi_set_eos(); +} + +/* Provide a default implementation for all weak handlers so that relocation + * entries in the modules make sense. Without default implementations the + * weak relocations w/o a symbol have a 0 address which is where the modules + * are linked at. */ +int __attribute__((weak)) mainboard_io_trap_handler(int smif) { return 0; } +void __attribute__((weak)) cpu_smi_handler(void) {} +void __attribute__((weak)) northbridge_smi_handler() {} +void __attribute__((weak)) southbridge_smi_handler() {} +void __attribute__((weak)) mainboard_smi_gpi(u16 gpi_sts) {} +int __attribute__((weak)) mainboard_smi_apmc(u8 data) { return 0; } +void __attribute__((weak)) mainboard_smi_sleep(u8 slp_typ) {} |