diff options
author | Subrata Banik <subrata.banik@intel.com> | 2017-12-14 18:18:34 +0530 |
---|---|---|
committer | Subrata Banik <subrata.banik@intel.com> | 2017-12-22 01:44:18 +0000 |
commit | ece173cc6fd347fdf121d1ad4518be50fb472071 (patch) | |
tree | 07f229c5043727afd39e75782f46cef6a5b2585e | |
parent | 1a274f406cd7fc484f67d5d8c8dba5b66504731e (diff) |
soc/intel/skylake: Make use of common SMM code for SKL
This patch ensures skylake soc is using common SMM code
from intel common block.
TEST=Build and boot soraka/eve
Change-Id: I8163dc7e18bb417e8c18a12628988959c128b3df
Signed-off-by: Subrata Banik <subrata.banik@intel.com>
Signed-off-by: Brandon Breitenstein <brandon.breitenstein@intel.com>
Reviewed-on: https://review.coreboot.org/22826
Reviewed-by: Furquan Shaikh <furquan@google.com>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
-rw-r--r-- | src/soc/intel/skylake/Kconfig | 2 | ||||
-rw-r--r-- | src/soc/intel/skylake/Makefile.inc | 1 | ||||
-rw-r--r-- | src/soc/intel/skylake/cpu.c | 3 | ||||
-rw-r--r-- | src/soc/intel/skylake/include/soc/nvs.h | 5 | ||||
-rw-r--r-- | src/soc/intel/skylake/include/soc/pm.h | 22 | ||||
-rw-r--r-- | src/soc/intel/skylake/include/soc/smbus.h | 3 | ||||
-rw-r--r-- | src/soc/intel/skylake/include/soc/smm.h | 17 | ||||
-rw-r--r-- | src/soc/intel/skylake/memmap.c | 2 | ||||
-rw-r--r-- | src/soc/intel/skylake/pei_data.c | 1 | ||||
-rw-r--r-- | src/soc/intel/skylake/smi.c | 92 | ||||
-rw-r--r-- | src/soc/intel/skylake/smihandler.c | 542 | ||||
-rw-r--r-- | src/soc/intel/skylake/smmrelocate.c | 3 |
12 files changed, 66 insertions, 627 deletions
diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig index 20665713d9..97ba7af7f2 100644 --- a/src/soc/intel/skylake/Kconfig +++ b/src/soc/intel/skylake/Kconfig @@ -76,6 +76,8 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_SCS select SOC_INTEL_COMMON_BLOCK_SGX select SOC_INTEL_COMMON_BLOCK_SMBUS + select SOC_INTEL_COMMON_BLOCK_SMM + select SOC_INTEL_COMMON_BLOCK_SMM_IO_TRAP select SOC_INTEL_COMMON_BLOCK_SPI select SOC_INTEL_COMMON_BLOCK_TIMER select SOC_INTEL_COMMON_BLOCK_UART diff --git a/src/soc/intel/skylake/Makefile.inc b/src/soc/intel/skylake/Makefile.inc index 16f8c065c5..ef95cf7767 100644 --- a/src/soc/intel/skylake/Makefile.inc +++ b/src/soc/intel/skylake/Makefile.inc @@ -59,7 +59,6 @@ ramstage-y += pmc.c ramstage-y += pmutil.c ramstage-$(CONFIG_PLATFORM_USES_FSP2_0) += reset.c ramstage-y += sd.c -ramstage-y += smi.c ramstage-y += smmrelocate.c ramstage-y += spi.c ramstage-y += systemagent.c diff --git a/src/soc/intel/skylake/cpu.c b/src/soc/intel/skylake/cpu.c index ca844df07c..291a40da3e 100644 --- a/src/soc/intel/skylake/cpu.c +++ b/src/soc/intel/skylake/cpu.c @@ -38,6 +38,7 @@ #include <intelblocks/fast_spi.h> #include <intelblocks/mp_init.h> #include <intelblocks/sgx.h> +#include <intelblocks/smm.h> #include <pc80/mc146818rtc.h> #include <soc/cpu.h> #include <soc/msr.h> @@ -436,7 +437,7 @@ static void post_mp_init(void) * Now that all APs have been relocated as well as the BSP let SMIs * start flowing. */ - southbridge_smm_enable_smi(); + smm_southbridge_enable(GBL_EN); /* Lock down the SMRAM space. */ #if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) diff --git a/src/soc/intel/skylake/include/soc/nvs.h b/src/soc/intel/skylake/include/soc/nvs.h index da6b2af110..8bc4d8dfe4 100644 --- a/src/soc/intel/skylake/include/soc/nvs.h +++ b/src/soc/intel/skylake/include/soc/nvs.h @@ -69,9 +69,4 @@ typedef struct global_nvs_t { } __packed global_nvs_t; check_member(global_nvs_t, chromeos, 0x100); -#if ENV_SMM -/* Used in SMM to find the ACPI GNVS address */ -global_nvs_t *smm_get_gnvs(void); -#endif - #endif diff --git a/src/soc/intel/skylake/include/soc/pm.h b/src/soc/intel/skylake/include/soc/pm.h index e904658397..b7d6446543 100644 --- a/src/soc/intel/skylake/include/soc/pm.h +++ b/src/soc/intel/skylake/include/soc/pm.h @@ -23,6 +23,7 @@ #include <soc/gpe.h> #include <soc/iomap.h> #include <soc/pmc.h> +#include <soc/smbus.h> /* ACPI_BASE_ADDRESS / PMBASE */ @@ -135,12 +136,25 @@ #define GBLRST_CAUSE0_THERMTRIP (1 << 5) +/* + * Enable SMI generation: + * - on APMC writes (io 0xb2) + * - on writes to SLP_EN (sleep states) + * - on writes to GBL_RLS (bios commands) + * - on eSPI events (does nothing on LPC systems) + * No SMIs: + * - on microcontroller writes (io 0x62/0x66) + * - on TCO events + */ +#define ENABLE_SMI_PARAMS \ + (APMC_EN | SLP_SMI_EN | GBL_SMI_EN | ESPI_SMI_EN | EOS) + /* This is defined as ETR3 in EDS. We named it as ETR here for consistency */ -#define ETR 0xac -#define CF9_LOCK (1 << 31) -#define CF9_GLB_RST (1 << 20) +#define ETR 0xac +#define CF9_LOCK (1 << 31) +#define CF9_GLB_RST (1 << 20) -#define PRSTS 0x10 +#define PRSTS 0x10 struct chipset_power_state { uint16_t pm1_sts; diff --git a/src/soc/intel/skylake/include/soc/smbus.h b/src/soc/intel/skylake/include/soc/smbus.h index ad5ae2611c..aeaf1d9ea2 100644 --- a/src/soc/intel/skylake/include/soc/smbus.h +++ b/src/soc/intel/skylake/include/soc/smbus.h @@ -4,7 +4,7 @@ * Copyright (C) 2005 Yinghai Lu <yinghailu@gmail.com> * Copyright (C) 2009 coresystems GmbH * Copyright (C) 2014 Google Inc. - * Copyright (C) 2015 Intel Corporation. + * Copyright (C) 2015-2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,7 @@ /* TCO registers and fields live behind TCOBASE I/O bar in SMBus device. */ #define TCO1_STS 0x04 +#define TCO_TIMEOUT (1 << 3) #define TCO2_STS 0x06 #define TCO2_STS_SECOND_TO 0x02 #define TCO2_STS_BOOT 0x04 diff --git a/src/soc/intel/skylake/include/soc/smm.h b/src/soc/intel/skylake/include/soc/smm.h index 06c4aacd3d..0f857e05ce 100644 --- a/src/soc/intel/skylake/include/soc/smm.h +++ b/src/soc/intel/skylake/include/soc/smm.h @@ -21,6 +21,7 @@ #include <compiler.h> #include <cpu/x86/msr.h> #include <fsp/memmap.h> +#include <intelblocks/smihandler.h> #include <soc/gpio.h> struct ied_header { @@ -48,12 +49,6 @@ struct smm_relocation_params { int smm_save_state_in_msrs; }; -/* Mainboard handler for GPI SMIs*/ -void mainboard_smi_gpi_handler(const struct gpi_status *sts); - -/* Mainboard handler for eSPI SMIs */ -void mainboard_smi_espi_handler(void); - #if IS_ENABLED(CONFIG_HAVE_SMI_HANDLER) void smm_relocation_handler(int cpu, uintptr_t curr_smbase, uintptr_t staggered_smbase); @@ -61,14 +56,6 @@ void smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, size_t *smm_save_state_size); void smm_initialize(void); void smm_relocate(void); - -/* - * The initialization of the southbridge is split into 2 compoments. One is - * for clearing the state in the SMM registers. The other is for enabling - * SMIs. - */ -void southbridge_smm_clear_state(void); -void southbridge_smm_enable_smi(void); #else /* CONFIG_HAVE_SMI_HANDLER */ static inline void smm_relocation_handler(int cpu, uintptr_t curr_smbase, uintptr_t staggered_smbase) {} @@ -77,8 +64,6 @@ static inline void smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, static inline void smm_initialize(void) {} static inline void smm_relocate(void) {} -static inline void southbridge_smm_clear_state(void) {} -static inline void southbridge_smm_enable_smi(void) {} #endif /* CONFIG_HAVE_SMI_HANDLER */ #endif diff --git a/src/soc/intel/skylake/memmap.c b/src/soc/intel/skylake/memmap.c index b7be21a9c7..c5dc8ac9af 100644 --- a/src/soc/intel/skylake/memmap.c +++ b/src/soc/intel/skylake/memmap.c @@ -21,11 +21,11 @@ #include <console/console.h> #include <device/device.h> #include <device/pci.h> +#include <fsp/memmap.h> #include <intelblocks/ebda.h> #include <intelblocks/systemagent.h> #include <soc/msr.h> #include <soc/pci_devs.h> -#include <soc/smm.h> #include <soc/systemagent.h> #include <stdlib.h> diff --git a/src/soc/intel/skylake/pei_data.c b/src/soc/intel/skylake/pei_data.c index 43409ef885..8b840c9853 100644 --- a/src/soc/intel/skylake/pei_data.c +++ b/src/soc/intel/skylake/pei_data.c @@ -25,7 +25,6 @@ #include <soc/pci_devs.h> #include <soc/pei_data.h> #include <soc/pei_wrapper.h> -#include <soc/smm.h> static void ABI_X86 send_to_console(unsigned char b) { diff --git a/src/soc/intel/skylake/smi.c b/src/soc/intel/skylake/smi.c deleted file mode 100644 index 67c3bb8e48..0000000000 --- a/src/soc/intel/skylake/smi.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of the coreboot project. - * - * Copyright (C) 2008-2009 coresystems GmbH - * Copyright (C) 2014 Google Inc. - * Copyright (C) 2015 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <bootstate.h> -#include <device/device.h> -#include <device/pci.h> -#include <console/console.h> -#include <arch/io.h> -#include <cpu/cpu.h> -#include <cpu/x86/cache.h> -#include <cpu/x86/smm.h> -#include <intelblocks/pmclib.h> -#include <string.h> -#include <soc/iomap.h> -#include <soc/pch.h> -#include <soc/pm.h> -#include <soc/smm.h> - -void southbridge_smm_clear_state(void) -{ - u32 smi_en; - - printk(BIOS_DEBUG, "Initializing Southbridge SMI..."); - printk(BIOS_SPEW, " ... pmbase = 0x%04x\n", ACPI_BASE_ADDRESS); - - smi_en = inl(ACPI_BASE_ADDRESS + SMI_EN); - if (smi_en & APMC_EN) { - printk(BIOS_INFO, "SMI# handler already enabled?\n"); - return; - } - - printk(BIOS_DEBUG, "\n"); - - /* Dump and clear status registers */ - pmc_clear_smi_status(); - pmc_clear_pm1_status(); - pmc_clear_tco_status(); - pmc_clear_all_gpe_status(); -} - -void southbridge_smm_enable_smi(void) -{ - printk(BIOS_DEBUG, "Enabling SMIs.\n"); - /* Configure events */ - pmc_enable_pm1(GBL_EN); - pmc_disable_std_gpe(PME_B0_EN); - - /* - * Enable SMI generation: - * - on APMC writes (io 0xb2) - * - on writes to SLP_EN (sleep states) - * - on writes to GBL_RLS (bios commands) - * - on eSPI events (does nothing on LPC systems) - * No SMIs: - * - on microcontroller writes (io 0x62/0x66) - * - on TCO events - */ - pmc_enable_smi(APMC_EN | SLP_SMI_EN | GBL_SMI_EN | ESPI_SMI_EN | EOS); -} - -void smm_setup_structures(void *gnvs, void *tcg, void *smi1) -{ - /* - * Issue SMI to set the gnvs pointer in SMM. - * tcg and smi1 are unused. - * - * EAX = APM_CNT_GNVS_UPDATE - * EBX = gnvs pointer - * EDX = APM_CNT - */ - asm volatile ( - "outb %%al, %%dx\n\t" - : /* ignore result */ - : "a" (APM_CNT_GNVS_UPDATE), - "b" ((u32)gnvs), - "d" (APM_CNT) - ); -} diff --git a/src/soc/intel/skylake/smihandler.c b/src/soc/intel/skylake/smihandler.c index 9ec6b87ca6..6e0054b030 100644 --- a/src/soc/intel/skylake/smihandler.c +++ b/src/soc/intel/skylake/smihandler.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008-2009 coresystems GmbH * Copyright (C) 2014 Google Inc. - * Copyright (C) 2015 Intel Corporation. + * Copyright (C) 2015-2017 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,521 +15,55 @@ * GNU General Public License for more details. */ -#include <arch/hlt.h> -#include <arch/io.h> #include <console/console.h> -#include <cpu/x86/cache.h> -#include <cpu/x86/smm.h> -#include <device/pci_def.h> -#include <elog.h> #include <intelblocks/fast_spi.h> -#include <intelblocks/pcr.h> -#include <intelblocks/uart.h> -#include <intelblocks/pmclib.h> -#include <delay.h> -#include <device/pci_def.h> -#include <elog.h> -#include <pc80/mc146818rtc.h> -#include <spi-generic.h> -#include <soc/iomap.h> -#include <soc/nvs.h> -#include <soc/pci_devs.h> -#include <soc/pch.h> -#include <soc/pcr_ids.h> +#include <intelblocks/smihandler.h> #include <soc/pm.h> -#include <soc/pmc.h> -#include <soc/smm.h> -#include <types.h> -/* IO Trap PCRs */ -/* Trap status Register */ -#define PCR_PSTH_TRPST 0x1E00 -/* Trapped cycle */ -#define PCR_PSTH_TRPC 0x1E10 -/* Trapped write data */ -#define PCR_PSTH_TRPD 0x1E18 - -static u8 smm_initialized = 0; - -/* - * GNVS needs to be updated by an 0xEA PM Trap (B2) after it has been located - * by coreboot. - */ -static global_nvs_t *gnvs; -global_nvs_t *smm_get_gnvs(void) -{ - return gnvs; -} - -int southbridge_io_trap_handler(int smif) -{ - switch (smif) { - case 0x32: - printk(BIOS_DEBUG, "OS Init\n"); - /* - * gnvs->smif: - * - On success, the IO Trap Handler returns 0 - * - On failure, the IO Trap Handler returns a value != 0 - */ - gnvs->smif = 0; - return 1; /* IO trap handled */ - } - - /* Not handled */ - return 0; -} - -/* Set the EOS bit */ -void southbridge_smi_set_eos(void) -{ - pmc_enable_smi(EOS); -} - -static void busmaster_disable_on_bus(int bus) -{ - int slot, func; - unsigned int val; - unsigned char hdr; - - for (slot = 0; slot < 0x20; slot++) { - for (func = 0; func < 8; func++) { - u32 reg32; - device_t dev = PCI_DEV(bus, slot, func); - - val = pci_read_config32(dev, PCI_VENDOR_ID); - - if (val == 0xffffffff || val == 0x00000000 || - val == 0x0000ffff || val == 0xffff0000) - continue; - - /* Disable Bus Mastering for this one device */ - reg32 = pci_read_config32(dev, PCI_COMMAND); - reg32 &= ~PCI_COMMAND_MASTER; - pci_write_config32(dev, PCI_COMMAND, reg32); - - /* If this is a bridge, then follow it. */ - hdr = pci_read_config8(dev, PCI_HEADER_TYPE); - hdr &= 0x7f; - if (hdr == PCI_HEADER_TYPE_BRIDGE || - hdr == PCI_HEADER_TYPE_CARDBUS) { - unsigned int buses; - buses = pci_read_config32(dev, PCI_PRIMARY_BUS); - busmaster_disable_on_bus((buses >> 8) & 0xff); - } - } - } -} - -static void southbridge_smi_sleep(void) -{ - u32 reg32; - u8 slp_typ; - - /* First, disable further SMIs */ - pmc_disable_smi(SLP_SMI_EN); - - /* Figure out SLP_TYP */ - reg32 = pmc_read_pm1_control(); - printk(BIOS_SPEW, "SMI#: SLP = 0x%08x\n", reg32); - slp_typ = acpi_sleep_from_pm1(reg32); - - /* Do any mainboard sleep handling */ - mainboard_smi_sleep(slp_typ); - - if (IS_ENABLED(CONFIG_ELOG_GSMI)) - /* Log S3, S4, and S5 entry */ - if (slp_typ >= ACPI_S3) - elog_add_event_byte(ELOG_TYPE_ACPI_ENTER, slp_typ); - - /* Clear pending GPE events */ - pmc_clear_all_gpe_status(); - - /* Next, do the deed. */ - switch (slp_typ) { - case ACPI_S0: - printk(BIOS_DEBUG, "SMI#: Entering S0 (On)\n"); - break; - case ACPI_S1: - printk(BIOS_DEBUG, "SMI#: Entering S1 (Assert STPCLK#)\n"); - break; - case ACPI_S3: - printk(BIOS_DEBUG, "SMI#: Entering S3 (Suspend-To-RAM)\n"); - - gnvs->uior = uart_debug_controller_is_initialized(); - - /* Invalidate the cache before going to S3 */ - wbinvd(); - break; - case ACPI_S5: - printk(BIOS_DEBUG, "SMI#: Entering S5 (Soft Power off)\n"); - /* Disable all GPE */ - pmc_disable_all_gpe(); - - pmc_soc_restore_power_failure(); - - /* also iterates over all bridges on bus 0 */ - busmaster_disable_on_bus(0); - break; - default: - printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); - break; - } - - /* - * Write back to the SLP register to cause the originally intended - * event again. We need to set BIT13 (SLP_EN) though to make the - * sleep happen. - */ - pmc_enable_pm1_control(SLP_EN); - - /* Make sure to stop executing code here for S3/S4/S5 */ - if (slp_typ >= ACPI_S3) - hlt(); - - /* - * In most sleep states, the code flow of this function ends at - * the line above. However, if we entered sleep state S1 and wake - * up again, we will continue to execute code in this function. - */ - if (pmc_read_pm1_control() & SCI_EN) { - /* The OS is not an ACPI OS, so we set the state to S0 */ - pmc_disable_pm1_control(SLP_EN | SLP_TYP); - } -} - -/* - * Look for Synchronous IO SMI and use save state from that - * core in case we are not running on the same core that - * initiated the IO transaction. - */ -static em64t101_smm_state_save_area_t *smi_apmc_find_state_save(u8 cmd) -{ - em64t101_smm_state_save_area_t *state; - int node; - - /* Check all nodes looking for the one that issued the IO */ - for (node = 0; node < CONFIG_MAX_CPUS; node++) { - state = smm_get_save_state(node); - - /* Check for Synchronous IO (bit0==1) */ - if (!(state->io_misc_info & (1 << 0))) - continue; - - /* Make sure it was a write (bit4==0) */ - if (state->io_misc_info & (1 << 4)) - continue; - - /* Check for APMC IO port */ - if (((state->io_misc_info >> 16) & 0xff) != APM_CNT) - continue; - - /* Check AX against the requested command */ - if ((state->rax & 0xff) != cmd) - continue; - - return state; - } - - return NULL; -} - -static void southbridge_smi_gsmi(void) -{ -#if IS_ENABLED(CONFIG_ELOG_GSMI) - u32 *ret, *param; - u8 sub_command; - em64t101_smm_state_save_area_t *io_smi = - smi_apmc_find_state_save(ELOG_GSMI_APM_CNT); - - if (!io_smi) - return; - - /* Command and return value in EAX */ - ret = (u32 *)&io_smi->rax; - sub_command = (u8)(*ret >> 8); - - /* Parameter buffer in EBX */ - param = (u32 *)&io_smi->rbx; - - /* drivers/elog/gsmi.c */ - *ret = gsmi_exec(sub_command, param); -#endif -} - -static void finalize(void) -{ - static int finalize_done; - - if (finalize_done) { - printk(BIOS_DEBUG, "SMM already finalized.\n"); - return; - } - finalize_done = 1; - - if (IS_ENABLED(CONFIG_SPI_FLASH_SMM)) - /* Re-init SPI driver to handle locked BAR */ - fast_spi_init(); -} - -static void southbridge_smi_apmc(void) -{ - u8 reg8; - em64t101_smm_state_save_area_t *state; - - /* Emulate B2 register as the FADT / Linux expects it */ - - reg8 = inb(APM_CNT); - switch (reg8) { - case APM_CNT_PST_CONTROL: - printk(BIOS_DEBUG, "P-state control\n"); - break; - case APM_CNT_ACPI_DISABLE: - pmc_disable_pm1_control(SCI_EN); - printk(BIOS_DEBUG, "SMI#: ACPI disabled.\n"); - break; - case APM_CNT_ACPI_ENABLE: - pmc_enable_pm1_control(SCI_EN); - printk(BIOS_DEBUG, "SMI#: ACPI enabled.\n"); - break; - case APM_CNT_FINALIZE: - finalize(); - break; - case APM_CNT_GNVS_UPDATE: - if (smm_initialized) { - printk(BIOS_DEBUG, - "SMI#: SMM structures already initialized!\n"); - return; - } - state = smi_apmc_find_state_save(reg8); - if (state) { - /* EBX in the state save contains the GNVS pointer */ - gnvs = (global_nvs_t *)((u32)state->rbx); - smm_initialized = 1; - printk(BIOS_DEBUG, "SMI#: Setting GNVS to %p\n", gnvs); - } - break; - case ELOG_GSMI_APM_CNT: - if (IS_ENABLED(CONFIG_ELOG_GSMI)) - southbridge_smi_gsmi(); - break; - } - - mainboard_smi_apmc(reg8); -} - -static void southbridge_smi_pm1(void) -{ - u16 pm1_sts = pmc_clear_pm1_status(); - u16 pm1_en = pmc_read_pm1_enable(); - - /* - * While OSPM is not active, poweroff immediately on a power button - * event. - */ - if ((pm1_sts & PWRBTN_STS) && (pm1_en & PWRBTN_EN)) { - /* power button pressed */ - if (IS_ENABLED(CONFIG_ELOG_GSMI)) - elog_add_event(ELOG_TYPE_POWER_BUTTON); - pmc_disable_pm1_control(-1UL); - pmc_enable_pm1_control(SLP_EN | (SLP_TYP_S5 << 10)); - } -} - -static void southbridge_smi_gpe0(void) -{ - pmc_clear_all_gpe_status(); -} - -void __attribute__((weak)) -mainboard_smi_gpi_handler(const struct gpi_status *sts) { } - -static void southbridge_smi_gpi(void) -{ - struct gpi_status smi_sts; - - gpi_clear_get_smi_status(&smi_sts); - mainboard_smi_gpi_handler(&smi_sts); - - /* Clear again after mainboard handler */ - gpi_clear_get_smi_status(&smi_sts); -} - -void __attribute__((weak)) mainboard_smi_espi_handler(void) { } -static void southbridge_smi_espi(void) -{ - mainboard_smi_espi_handler(); -} - -static void southbridge_smi_mc(void) -{ - u32 reg32 = inl(ACPI_BASE_ADDRESS + SMI_EN); - - /* Are microcontroller SMIs enabled? */ - if ((reg32 & MCSMI_EN) == 0) - return; - - printk(BIOS_DEBUG, "Microcontroller SMI.\n"); -} - -static void southbridge_smi_tco(void) -{ - u32 tco_sts = pmc_clear_tco_status(); - - /* Any TCO event? */ - if (!tco_sts) - return; - - if (tco_sts & (1 << 8)) { /* BIOSWR */ - if (IS_ENABLED(CONFIG_SPI_FLASH_SMM)) { - if (fast_spi_wpd_status()) { - /* - * BWE is RW, so the SMI was caused by a - * write to BWE, not by a write to the BIOS - * - * This is the place where we notice someone - * is trying to tinker with the BIOS. We are - * trying to be nice and just ignore it. A more - * resolute answer would be to power down the - * box. - */ - printk(BIOS_DEBUG, "Switching back to RO\n"); - fast_spi_enable_wp(); - } /* No else for now? */ - } - } else if (tco_sts & (1 << 3)) { /* TIMEOUT */ - /* Handle TCO timeout */ - printk(BIOS_DEBUG, "TCO Timeout.\n"); - } -} - -static void southbridge_smi_periodic(void) +const struct smm_save_state_ops *get_smm_save_state_ops(void) { - u32 reg32 = inl(ACPI_BASE_ADDRESS + SMI_EN); - - /* Are periodic SMIs enabled? */ - if ((reg32 & PERIODIC_EN) == 0) - return; - - printk(BIOS_DEBUG, "Periodic SMI.\n"); + return &em64t101_smm_ops; } -static void southbridge_smi_monitor(void) +void smihandler_check_illegal_access(uint32_t tco_sts) { -#define IOTRAP(x) (trap_sts & (1 << x)) - u32 trap_cycle; - u32 data, mask = 0; - u8 trap_sts; - int i; - /* TRSR - Trap Status Register */ - trap_sts = pcr_read8(PID_PSTH, PCR_PSTH_TRPST); - /* Clear trap(s) in TRSR */ - pcr_write8(PID_PSTH, PCR_PSTH_TRPST, trap_sts); - - /* TRPC - Trapped cycle */ - trap_cycle = pcr_read32(PID_PSTH, PCR_PSTH_TRPC); - for (i = 16; i < 20; i++) { - if (trap_cycle & (1 << i)) - mask |= (0xff << ((i - 16) << 2)); - } - - - /* IOTRAP(3) SMI function call */ - if (IOTRAP(3)) { - if (gnvs && gnvs->smif) - io_trap_handler(gnvs->smif); /* call function smif */ + if (!((tco_sts & (1 << 8)) && IS_ENABLED(CONFIG_SPI_FLASH_SMM) + && fast_spi_wpd_status())) return; - } /* - * IOTRAP(2) currently unused - * IOTRAP(1) currently unused + * BWE is RW, so the SMI was caused by a + * write to BWE, not by a write to the BIOS + * + * This is the place where we notice someone + * is trying to tinker with the BIOS. We are + * trying to be nice and just ignore it. A more + * resolute answer would be to power down the + * box. */ - - /* IOTRAP(0) SMIC */ - if (IOTRAP(0)) { - if (!(trap_cycle & (1 << 24))) { /* It's a write */ - printk(BIOS_DEBUG, "SMI1 command\n"); - /* Trapped write data */ - data = pcr_read32(PID_PSTH, PCR_PSTH_TRPD); - data &= mask; - } - } - - printk(BIOS_DEBUG, " trapped io address = 0x%x\n", - trap_cycle & 0xfffc); - for (i = 0; i < 4; i++) - if (IOTRAP(i)) - printk(BIOS_DEBUG, " TRAP = %d\n", i); - printk(BIOS_DEBUG, " AHBE = %x\n", (trap_cycle >> 16) & 0xf); - printk(BIOS_DEBUG, " MASK = 0x%08x\n", mask); - printk(BIOS_DEBUG, " read/write: %s\n", - (trap_cycle & (1 << 24)) ? "read" : "write"); - - if (!(trap_cycle & (1 << 24))) { - /* Write Cycle */ - data = pcr_read32(PID_PSTH, PCR_PSTH_TRPD); - printk(BIOS_DEBUG, " iotrap written data = 0x%08x\n", data); - } -#undef IOTRAP + printk(BIOS_DEBUG, "Switching back to RO\n"); + fast_spi_enable_wp(); } -typedef void (*smi_handler_t)(void); - -static smi_handler_t southbridge_smi[SMI_STS_BITS] = { - [SMI_ON_SLP_EN_STS_BIT] = southbridge_smi_sleep, - [APM_STS_BIT] = southbridge_smi_apmc, - [PM1_STS_BIT] = southbridge_smi_pm1, - [GPE0_STS_BIT] = southbridge_smi_gpe0, - [GPIO_STS_BIT] = southbridge_smi_gpi, - [ESPI_SMI_STS_BIT] = southbridge_smi_espi, - [MCSMI_STS_BIT] = southbridge_smi_mc, - [TCO_STS_BIT] = southbridge_smi_tco, - [PERIODIC_STS_BIT] = southbridge_smi_periodic, - [MONITOR_STS_BIT] = southbridge_smi_monitor, -}; - -#define SMI_HANDLER_SCI_EN(__bit) (1 << (__bit)) - /* SMI handlers that should be serviced in SCI mode too. */ -uint32_t smi_handler_sci_mask = - SMI_HANDLER_SCI_EN(APM_STS_BIT) | - SMI_HANDLER_SCI_EN(SMI_ON_SLP_EN_STS_BIT); - -/* - * Interrupt handler for SMI# - */ -void southbridge_smi_handler(void) -{ - int i; - u32 smi_sts; - - /* - * We need to clear the SMI status registers, or we won't see what's - * happening in the following calls. - */ - smi_sts = pmc_clear_smi_status(); - - /* - * In SCI mode, execute only those SMI handlers that have - * declared themselves as available for service in that mode - * using smi_handler_sci_mask. - */ - if (pmc_read_pm1_control() & SCI_EN) - smi_sts &= smi_handler_sci_mask; - - if (!smi_sts) - return; - - /* Call SMI sub handler for each of the status bits */ - for (i = 0; i < ARRAY_SIZE(southbridge_smi); i++) { - if (smi_sts & (1 << i)) { - if (southbridge_smi[i]) { - southbridge_smi[i](); - } else { - printk(BIOS_DEBUG, - "SMI_STS[%d] occurred, but no handler available.\n", - i); - } - } - } -} +uint32_t smi_handler_get_sci_mask(void) +{ + uint32_t sci_mask = + SMI_HANDLER_SCI_EN(APM_STS_BIT) | + SMI_HANDLER_SCI_EN(SMI_ON_SLP_EN_STS_BIT); + + return sci_mask; +} + +const smi_handler_t southbridge_smi[SMI_STS_BITS] = { + [SMI_ON_SLP_EN_STS_BIT] = smihandler_southbridge_sleep, + [APM_STS_BIT] = smihandler_southbridge_apmc, + [PM1_STS_BIT] = smihandler_southbridge_pm1, + [GPE0_STS_BIT] = smihandler_southbridge_gpe0, + [GPIO_STS_BIT] = smihandler_southbridge_gpi, + [ESPI_SMI_STS_BIT] = smihandler_southbridge_espi, + [MCSMI_STS_BIT] = smihandler_southbridge_mc, + [TCO_STS_BIT] = smihandler_southbridge_tco, + [PERIODIC_STS_BIT] = smihandler_southbridge_periodic, + [MONITOR_STS_BIT] = smihandler_southbridge_monitor, +}; diff --git a/src/soc/intel/skylake/smmrelocate.c b/src/soc/intel/skylake/smmrelocate.c index dbe0c9485b..b477b11752 100644 --- a/src/soc/intel/skylake/smmrelocate.c +++ b/src/soc/intel/skylake/smmrelocate.c @@ -26,6 +26,7 @@ #include <cpu/x86/mtrr.h> #include <cpu/x86/smm.h> #include <console/console.h> +#include <intelblocks/smm.h> #include <soc/cpu.h> #include <soc/msr.h> #include <soc/pci_devs.h> @@ -281,7 +282,7 @@ void smm_info(uintptr_t *perm_smbase, size_t *perm_smsize, void smm_initialize(void) { /* Clear the SMM state in the southbridge. */ - southbridge_smm_clear_state(); + smm_southbridge_clear_state(); /* * Run the relocation handler for on the BSP to check and set up |