soc/intel/xeon_sp: Enable SMI handler

SMI handler was not installed for Xeon_sp platforms. This enables SMM
relocation and SMI handling.

TESTED:
- SMRR are correctly set
- The save state revision is correct (0x00030101)
- SMI's are properly generated and handled
- SMM MSR save state are not supported, so relocate SMM on all cores
in series
- Verified on OCP/Deltalake mainboard.

NOTE:
- Code for accessing a CPU save state is not working for SMMLOADERV2,
so some SMM features like GSMI, SMMSTORE, updating the ACPI GNVS
pointer are not supported.
- This hooks up to some soc/intel/common like TCO and ACPI GNVS. GNVS
is broken and needs to be fixed separately. It is unknown if TCO is
supported. This might require a cleanup in the future.

Change-Id: Iabee5c72f0245ab988d477ac8df3d8d655a2a506
Signed-off-by: Rocky Phagura <rphagura@fb.com>
Signed-off-by: Christian Walter <christian.walter@9elements.com>
Signed-off-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/46231
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Rocky Phagura 2020-10-08 13:32:41 -07:00 committed by Arthur Heymans
parent f4721246db
commit 17a798b68c
12 changed files with 205 additions and 19 deletions

View File

@ -52,6 +52,7 @@ config CPU_SPECIFIC_OPTIONS
select SOC_INTEL_COMMON_BLOCK_P2SB select SOC_INTEL_COMMON_BLOCK_P2SB
select SOC_INTEL_COMMON_BLOCK_PMC select SOC_INTEL_COMMON_BLOCK_PMC
select SOC_INTEL_COMMON_BLOCK_PMC_DISCOVERABLE select SOC_INTEL_COMMON_BLOCK_PMC_DISCOVERABLE
select SOC_INTEL_COMMON_BLOCK_SMM
select SOC_INTEL_COMMON_BLOCK_TCO select SOC_INTEL_COMMON_BLOCK_TCO
select TSC_MONOTONIC_TIMER select TSC_MONOTONIC_TIMER
select UDELAY_TSC select UDELAY_TSC
@ -59,8 +60,11 @@ config CPU_SPECIFIC_OPTIONS
select MICROCODE_BLOB_NOT_HOOKED_UP select MICROCODE_BLOB_NOT_HOOKED_UP
select CPU_INTEL_FIRMWARE_INTERFACE_TABLE select CPU_INTEL_FIRMWARE_INTERFACE_TABLE
select FSP_CAR select FSP_CAR
select NO_SMM select CPU_INTEL_COMMON_SMM
select ACPI_INTEL_HARDWARE_SLEEP_VALUES select ACPI_INTEL_HARDWARE_SLEEP_VALUES
select SMM_TSEG
select HAVE_SMI_HANDLER
select X86_SMM_LOADER_VERSION2
select REG_SCRIPT select REG_SCRIPT
config MAINBOARD_USES_FSP2_0 config MAINBOARD_USES_FSP2_0

View File

@ -12,6 +12,8 @@ ramstage-y += uncore.c reset.c util.c lpc.c spi.c gpio.c nb_acpi.c ramstage.c ch
ramstage-y += memmap.c pch.c ramstage-y += memmap.c pch.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PMC) += pmc.c ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_PMC) += pmc.c
ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smmrelocate.c
smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c pmc.c
postcar-y += spi.c postcar-y += spi.c
CPPFLAGS_common += -I$(src)/soc/intel/xeon_sp/include CPPFLAGS_common += -I$(src)/soc/intel/xeon_sp/include

View File

@ -78,6 +78,10 @@ config FSP_TEMP_RAM_SIZE
documentation says this needs to be at least 128KiB, but practice documentation says this needs to be at least 128KiB, but practice
show this needs to be 256KiB or more. show this needs to be 256KiB or more.
config IED_REGION_SIZE
hex
default 0x400000
config SOC_INTEL_COMMON_BLOCK_P2SB config SOC_INTEL_COMMON_BLOCK_P2SB
def_bool y def_bool y

View File

@ -5,6 +5,7 @@ ifeq ($(CONFIG_SOC_INTEL_COOPERLAKE_SP),y)
subdirs-y += ../../../../cpu/intel/turbo subdirs-y += ../../../../cpu/intel/turbo
subdirs-y += ../../../../cpu/x86/lapic subdirs-y += ../../../../cpu/x86/lapic
subdirs-y += ../../../../cpu/x86/mtrr subdirs-y += ../../../../cpu/x86/mtrr
subdirs-y += ../../../../cpu/x86/smm
subdirs-y += ../../../../cpu/x86/tsc subdirs-y += ../../../../cpu/x86/tsc
subdirs-y += ../../../../cpu/intel/microcode subdirs-y += ../../../../cpu/intel/microcode

View File

@ -7,7 +7,9 @@
#include <console/debug.h> #include <console/debug.h>
#include <cpu/cpu.h> #include <cpu/cpu.h>
#include <cpu/intel/common/common.h> #include <cpu/intel/common/common.h>
#include <cpu/intel/em64t101_save_state.h>
#include <cpu/intel/microcode.h> #include <cpu/intel/microcode.h>
#include <cpu/intel/smm_reloc.h>
#include <cpu/intel/turbo.h> #include <cpu/intel/turbo.h>
#include <cpu/x86/lapic.h> #include <cpu/x86/lapic.h>
#include <cpu/x86/mp.h> #include <cpu/x86/mp.h>
@ -17,6 +19,7 @@
#include <soc/cpu.h> #include <soc/cpu.h>
#include <soc/msr.h> #include <soc/msr.h>
#include <soc/soc_util.h> #include <soc/soc_util.h>
#include <soc/smmrelocate.h>
#include <soc/util.h> #include <soc/util.h>
#include "chip.h" #include "chip.h"
@ -172,16 +175,16 @@ static void post_mp_init(void)
/* Set Max Ratio */ /* Set Max Ratio */
set_max_turbo_freq(); set_max_turbo_freq();
/* if (CONFIG(HAVE_SMI_HANDLER))
* TODO: Now that all APs have been relocated as well as the BSP let SMIs global_smi_enable();
* start flowing.
*/
if (0) global_smi_enable();
} }
static const struct mp_ops mp_ops = { static const struct mp_ops mp_ops = {
.pre_mp_init = pre_mp_init, .pre_mp_init = pre_mp_init,
.get_cpu_count = get_thread_count, .get_cpu_count = get_thread_count,
.get_smm_info = get_smm_info,
.pre_mp_smm_init = smm_initialize,
.relocation_handler = smm_relocation_handler,
.get_microcode_info = get_microcode_info, .get_microcode_info = get_microcode_info,
.post_mp_init = post_mp_init, .post_mp_init = post_mp_init,
}; };

View File

@ -8,10 +8,13 @@
/* TODO - this requires xeon sp, server board support */ /* TODO - this requires xeon sp, server board support */
/* NOTE: We do not use intelblocks/nvs.h since it includes /* NOTE: We do not use intelblocks/nvs.h since it includes
mostly client specific attributes */ mostly client specific attributes */
/* TODO: This is not aligned with the ACPI asl code */
struct __packed global_nvs { struct __packed global_nvs {
uint8_t pcnt; /* 0x00 - Processor Count */ uint8_t pcnt; /* 0x00 - Processor Count */
uint32_t cbmc; /* 0x01 - coreboot memconsole */ uint32_t cbmc; /* 0x01 - coreboot memconsole */
uint8_t rsvd3[251]; uint8_t uior;
uint8_t rsvd3[250];
}; };
#endif /* _SOC_NVS_H_ */ #endif /* _SOC_NVS_H_ */

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#ifndef _SOC_SMMRELOCATE_H_
#define _SOC_SMMRELOCATE_H_
void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize,
size_t *smm_save_state_size);
#endif

View File

@ -59,4 +59,8 @@ config HEAP_SIZE
hex hex
default 0x80000 default 0x80000
config IED_REGION_SIZE
hex
default 0x400000
endif endif

View File

@ -8,7 +8,7 @@ subdirs-y += ../../../../cpu/x86/lapic
subdirs-y += ../../../../cpu/x86/mtrr subdirs-y += ../../../../cpu/x86/mtrr
subdirs-y += ../../../../cpu/x86/tsc subdirs-y += ../../../../cpu/x86/tsc
subdirs-y += ../../../../cpu/x86/cache subdirs-y += ../../../../cpu/x86/cache
subdirs-$(CONFIG_HAVE_SMI_HANDLER) += ../../../cpu/x86/smm subdirs-$(CONFIG_HAVE_SMI_HANDLER) += ../../../../cpu/x86/smm
postcar-y += soc_util.c postcar-y += soc_util.c

View File

@ -10,9 +10,13 @@
#include <soc/msr.h> #include <soc/msr.h>
#include <soc/cpu.h> #include <soc/cpu.h>
#include <soc/soc_util.h> #include <soc/soc_util.h>
#include <soc/smmrelocate.h>
#include <soc/util.h> #include <soc/util.h>
#include <assert.h> #include <assert.h>
#include "chip.h" #include "chip.h"
#include <cpu/intel/smm_reloc.h>
#include <cpu/intel/em64t101_save_state.h>
static const config_t *chip_config = NULL; static const config_t *chip_config = NULL;
@ -197,11 +201,8 @@ static void post_mp_init(void)
/* Set Max Ratio */ /* Set Max Ratio */
set_max_turbo_freq(); set_max_turbo_freq();
/* if (CONFIG(HAVE_SMI_HANDLER))
* TODO: Now that all APs have been relocated as well as the BSP let SMIs global_smi_enable();
* start flowing.
*/
if (0) global_smi_enable();
} }
/* /*
@ -214,12 +215,9 @@ static void post_mp_init(void)
static const struct mp_ops mp_ops = { static const struct mp_ops mp_ops = {
.pre_mp_init = pre_mp_init, .pre_mp_init = pre_mp_init,
.get_cpu_count = get_platform_thread_count, .get_cpu_count = get_platform_thread_count,
//.get_smm_info = get_smm_info, /* TODO */ .get_smm_info = get_smm_info,
.get_smm_info = NULL, .pre_mp_smm_init = smm_initialize,
//.pre_mp_smm_init = southcluster_smm_clear_state, /* TODO */ .relocation_handler = smm_relocation_handler,
.pre_mp_smm_init = NULL,
//.relocation_handler = relocation_handler, /* TODO */
.relocation_handler = NULL,
.post_mp_init = post_mp_init, .post_mp_init = post_mp_init,
}; };

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <intelblocks/smihandler.h>
#include <soc/pm.h>
#include <cpu/x86/smm.h>
/* This is needed by common SMM code */
const smi_handler_t southbridge_smi[SMI_STS_BITS] = {
[APM_STS_BIT] = smihandler_southbridge_apmc,
[PM1_STS_BIT] = smihandler_southbridge_pm1,
#if CONFIG(SOC_INTEL_COMMON_BLOCK_SMM_TCO_ENABLE)
[TCO_STS_BIT] = smihandler_southbridge_tco,
#endif
};

View File

@ -0,0 +1,144 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <assert.h>
#include <string.h>
#include <cpu/x86/mp.h>
#include <cpu/intel/em64t101_save_state.h>
#include <cpu/intel/smm_reloc.h>
#include <console/console.h>
#include <smp/node.h>
#include <soc/msr.h>
#include <soc/smmrelocate.h>
static void fill_in_relocation_params(struct smm_relocation_params *params)
{
uintptr_t tseg_base;
size_t tseg_size;
smm_region(&tseg_base, &tseg_size);
if (!IS_ALIGNED(tseg_base, tseg_size)) {
/*
* Note SMRR2 is supported which might support base/size combinations.
* For now it looks like FSP-M always uses aligned base/size, so let's
* not care about that.
*/
printk(BIOS_WARNING,
"TSEG base not aligned with TSEG SIZE! Not setting SMRR\n");
return;
}
/* SMRR has 32-bits of valid address aligned to 4KiB. */
if (!IS_ALIGNED(tseg_size, 4 * KiB)) {
printk(BIOS_WARNING,
"TSEG size not aligned to the minimum 4KiB! Not setting SMRR\n");
return;
}
smm_subregion(SMM_SUBREGION_CHIPSET, &params->ied_base, &params->ied_size);
params->smrr_base.lo = tseg_base | MTRR_TYPE_WRBACK;
params->smrr_base.hi = 0;
params->smrr_mask.lo = ~(tseg_size - 1) | MTRR_PHYS_MASK_VALID;
params->smrr_mask.hi = 0;
}
static void setup_ied_area(struct smm_relocation_params *params)
{
char *ied_base;
const struct ied_header ied = {
.signature = "INTEL RSVD",
.size = params->ied_size,
.reserved = {0},
};
ied_base = (void *)params->ied_base;
printk(BIOS_DEBUG, "IED base = 0x%08x\n", (u32)params->ied_base);
printk(BIOS_DEBUG, "IED size = 0x%08x\n", (u32)params->ied_size);
/* Place IED header at IEDBASE. */
memcpy(ied_base, &ied, sizeof(ied));
assert(params->ied_size > 1 * MiB + 32 * KiB);
/* Zero out 32KiB at IEDBASE + 1MiB */
memset(ied_base + 1 * MiB, 0, 32 * KiB);
}
void get_smm_info(uintptr_t *perm_smbase, size_t *perm_smsize,
size_t *smm_save_state_size)
{
fill_in_relocation_params(&smm_reloc_params);
smm_subregion(SMM_SUBREGION_HANDLER, perm_smbase, perm_smsize);
if (smm_reloc_params.ied_size)
setup_ied_area(&smm_reloc_params);
*smm_save_state_size = sizeof(em64t101_smm_state_save_area_t);
}
static void update_save_state(int cpu, uintptr_t curr_smbase,
uintptr_t staggered_smbase,
struct smm_relocation_params *relo_params)
{
u32 smbase;
u32 iedbase;
int apic_id;
em64t101_smm_state_save_area_t *save_state;
/*
* The relocated handler runs with all CPUs concurrently. Therefore
* stagger the entry points adjusting SMBASE downwards by save state
* size * CPU num.
*/
smbase = staggered_smbase;
iedbase = relo_params->ied_base;
apic_id = cpuid_ebx(1) >> 24;
printk(BIOS_DEBUG, "New SMBASE=0x%08x IEDBASE=0x%08x\n apic_id=0x%x\n",
smbase, iedbase, apic_id);
save_state = (void *)(curr_smbase + SMM_DEFAULT_SIZE - sizeof(*save_state));
save_state->smbase = smbase;
save_state->iedbase = iedbase;
}
/*
* 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.
*/
void smm_relocation_handler(int cpu, uintptr_t curr_smbase,
uintptr_t staggered_smbase)
{
msr_t mtrr_cap;
struct smm_relocation_params *relo_params = &smm_reloc_params;
printk(BIOS_DEBUG, "%s : CPU %d\n", __func__, cpu);
/* Make appropriate changes to the save state map. */
update_save_state(cpu, curr_smbase, staggered_smbase, relo_params);
/* Write SMRR MSRs based on indicated support. */
mtrr_cap = rdmsr(MTRR_CAP_MSR);
if (mtrr_cap.lo & SMRR_SUPPORTED)
write_smrr(relo_params);
}
void smm_initialize(void)
{
/* Clear the SMM state in the southbridge. */
smm_southbridge_clear_state();
/* Run the relocation handler for on the BSP . */
smm_initiate_relocation();
}
void smm_relocate(void)
{
/* Save states via MSR does not seem to be supported on CPX */
if (!boot_cpu())
smm_initiate_relocation();
}