diff options
-rw-r--r-- | src/cpu/qemu-x86/Kconfig | 7 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-i440fx/northbridge.c | 6 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-q35/Makefile.inc | 1 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-q35/cpu.c | 58 | ||||
-rw-r--r-- | src/mainboard/emulation/qemu-q35/memmap.c | 24 |
5 files changed, 92 insertions, 4 deletions
diff --git a/src/cpu/qemu-x86/Kconfig b/src/cpu/qemu-x86/Kconfig index a22d7f9eab..85f99e9cb6 100644 --- a/src/cpu/qemu-x86/Kconfig +++ b/src/cpu/qemu-x86/Kconfig @@ -36,9 +36,10 @@ config CPU_QEMU_X86_ASEG_SMM depends on !PARALLEL_MP select SMM_ASEG -#config CPU_QEMU_X86_TSEG_SMM -# bool "SMM in TSEG" -# select SMM_TSEG +config CPU_QEMU_X86_TSEG_SMM + bool "SMM in TSEG" + select SMM_TSEG + depends on PARALLEL_MP endchoice diff --git a/src/mainboard/emulation/qemu-i440fx/northbridge.c b/src/mainboard/emulation/qemu-i440fx/northbridge.c index 80fba1de07..fcff7bcf7f 100644 --- a/src/mainboard/emulation/qemu-i440fx/northbridge.c +++ b/src/mainboard/emulation/qemu-i440fx/northbridge.c @@ -249,9 +249,13 @@ static const struct mp_ops mp_ops_no_smm = { .get_cpu_count = fw_cfg_max_cpus, }; +extern const struct mp_ops mp_ops_with_smm; + void mp_init_cpus(struct bus *cpu_bus) { - if (mp_init_with_smm(cpu_bus, &mp_ops_no_smm)) + const struct mp_ops *ops = CONFIG(SMM_TSEG) ? &mp_ops_with_smm : &mp_ops_no_smm; + + if (mp_init_with_smm(cpu_bus, ops)) printk(BIOS_ERR, "MP initialization failure.\n"); } diff --git a/src/mainboard/emulation/qemu-q35/Makefile.inc b/src/mainboard/emulation/qemu-q35/Makefile.inc index 99980e3248..9179e9e424 100644 --- a/src/mainboard/emulation/qemu-q35/Makefile.inc +++ b/src/mainboard/emulation/qemu-q35/Makefile.inc @@ -14,6 +14,7 @@ ramstage-y += ../qemu-i440fx/fw_cfg.c ramstage-y += ../qemu-i440fx/memmap.c ramstage-y += ../qemu-i440fx/northbridge.c ramstage-y += memmap.c +ramstage-y += cpu.c verstage-$(CONFIG_CHROMEOS) += chromeos.c verstage-$(CONFIG_CHROMEOS) += ../qemu-i440fx/fw_cfg.c diff --git a/src/mainboard/emulation/qemu-q35/cpu.c b/src/mainboard/emulation/qemu-q35/cpu.c new file mode 100644 index 0000000000..b30d7298ec --- /dev/null +++ b/src/mainboard/emulation/qemu-q35/cpu.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <console/console.h> +#include <cpu/x86/mp.h> +#include <stdint.h> +#include <cpu/intel/smm_reloc.h> +#include <cpu/amd/amd64_save_state.h> +#include <mainboard/emulation/qemu-i440fx/fw_cfg.h> + +static void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, + size_t *smm_save_state_size) +{ + printk(BIOS_DEBUG, "Setting up SMI for CPU\n"); + + smm_subregion(SMM_SUBREGION_HANDLER, perm_smbase, perm_smsize); + + /* FIXME: on X86_64 the save state size is smaller than the size of the SMM stub */ + *smm_save_state_size = sizeof(amd64_smm_state_save_area_t); + printk(BIOS_DEBUG, "Save state size: 0x%lx bytes\n", *smm_save_state_size); +} + +/* + * The relocation work is actually performed in SMM context, but the code + * resides in the ramstage module. This occurs by trampolining from the default + * SMRAM entry point to here. + */ +static void relocation_handler(int cpu, uintptr_t curr_smbase, + uintptr_t staggered_smbase) +{ + /* The em64t101 save state is sufficiently compatible with older + save states with regards of smbase, smm_revision. */ + amd64_smm_state_save_area_t *save_state; + u32 smbase = staggered_smbase; + + save_state = (void *)(curr_smbase + SMM_DEFAULT_SIZE - sizeof(*save_state)); + save_state->smbase = smbase; + + printk(BIOS_DEBUG, "In relocation handler: cpu %d\n", cpu); + printk(BIOS_DEBUG, "SMM revision: 0x%08x\n", save_state->smm_revision); + printk(BIOS_DEBUG, "New SMBASE=0x%08x\n", smbase); +} + +static void post_mp_init(void) +{ + /* Now that all APs have been relocated as well as the BSP let SMIs start flowing. */ + global_smi_enable(); + + /* Lock down the SMRAM space. */ + smm_lock(); +} + +const struct mp_ops mp_ops_with_smm = { + .get_cpu_count = fw_cfg_max_cpus, + .get_smm_info = get_smm_info, + .pre_mp_smm_init = smm_southbridge_clear_state, + .relocation_handler = relocation_handler, + .post_mp_init = post_mp_init, +}; diff --git a/src/mainboard/emulation/qemu-q35/memmap.c b/src/mainboard/emulation/qemu-q35/memmap.c index f3ce42c485..5c4292138d 100644 --- a/src/mainboard/emulation/qemu-q35/memmap.c +++ b/src/mainboard/emulation/qemu-q35/memmap.c @@ -8,6 +8,7 @@ #include <device/pci_ops.h> #include <mainboard/emulation/qemu-i440fx/memory.h> #include <mainboard/emulation/qemu-i440fx/fw_cfg.h> +#include <cpu/intel/smm_reloc.h> #include "q35.h" @@ -35,6 +36,16 @@ void mainboard_machine_check(void) /* QEMU-specific register */ #define EXT_TSEG_MBYTES 0x50 +#define SMRAMC 0x9d +#define C_BASE_SEG ((0 << 2) | (1 << 1) | (0 << 0)) +#define G_SMRAME (1 << 3) +#define D_LCK (1 << 4) +#define D_CLS (1 << 5) +#define D_OPEN (1 << 6) +#define ESMRAMC 0x9e +#define T_EN (1 << 0) +#define TSEG_SZ_MASK (3 << 1) +#define H_SMRAME (1 << 7) void smm_region(uintptr_t *start, size_t *size) { @@ -57,3 +68,16 @@ void smm_region(uintptr_t *start, size_t *size) *start = qemu_get_memory_size() * KiB - *size; printk(BIOS_SPEW, "SMM_BASE: 0x%08lx, SMM_SIZE: %zu MiB\n", *start, *size / MiB); } + +void smm_lock(void) +{ + /* + * LOCK the SMM memory window and enable normal SMM. + * After running this function, only a full reset can + * make the SMM registers writable again. + */ + printk(BIOS_DEBUG, "Locking SMM.\n"); + + pci_or_config8(PCI_DEV(0, 0, 0), ESMRAMC, T_EN); + pci_write_config8(PCI_DEV(0, 0, 0), SMRAMC, D_LCK | G_SMRAME | C_BASE_SEG); +} |