Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/48262 )
Change subject: mb/emulation/qemu-q35: Add support for SMM_TSEG with parallel MP init ......................................................................
mb/emulation/qemu-q35: Add support for SMM_TSEG with parallel MP init
Tested with and without -enable-kvm, with -smp 1 2 and 32.
Change-Id: I612cebcd2ddef809434eb9bfae9d8681cda112ef Signed-off-by: Arthur Heymans arthur@aheymans.xyz Reviewed-on: https://review.coreboot.org/c/coreboot/+/48262 Reviewed-by: Angel Pons th3fanbus@gmail.com Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M src/cpu/qemu-x86/Kconfig M src/mainboard/emulation/qemu-i440fx/northbridge.c M src/mainboard/emulation/qemu-q35/Makefile.inc A src/mainboard/emulation/qemu-q35/cpu.c M src/mainboard/emulation/qemu-q35/memmap.c 5 files changed, 92 insertions(+), 4 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved
diff --git a/src/cpu/qemu-x86/Kconfig b/src/cpu/qemu-x86/Kconfig index a22d7f9..85f99e9 100644 --- a/src/cpu/qemu-x86/Kconfig +++ b/src/cpu/qemu-x86/Kconfig @@ -36,9 +36,10 @@ 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 80fba1d..fcff7bc 100644 --- a/src/mainboard/emulation/qemu-i440fx/northbridge.c +++ b/src/mainboard/emulation/qemu-i440fx/northbridge.c @@ -249,9 +249,13 @@ .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 99980e3..9179e9e 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/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 0000000..b30d729 --- /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 f3ce42c..5c42921 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 @@
/* 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 @@ *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); +}