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>
This commit is contained in:
Arthur Heymans 2020-12-01 18:29:13 +01:00 committed by Patrick Georgi
parent ff485f2bce
commit e69d2dfdb7
5 changed files with 92 additions and 4 deletions

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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,
};

View File

@ -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);
}