summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cpu/qemu-x86/Kconfig7
-rw-r--r--src/mainboard/emulation/qemu-i440fx/northbridge.c6
-rw-r--r--src/mainboard/emulation/qemu-q35/Makefile.inc1
-rw-r--r--src/mainboard/emulation/qemu-q35/cpu.c58
-rw-r--r--src/mainboard/emulation/qemu-q35/memmap.c24
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);
+}