Paul Menzel (paulepanter@users.sourceforge.net) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8139
-gerrit
commit dcaea212bff31e53f65b37656611be6a8513033a Author: Paul Menzel paulepanter@users.sourceforge.net Date: Tue Jan 6 17:12:26 2015 +0100
intel/i82801gx: SMM: Pass the ACPI GNVS pointer via state save map
Currently on older Intel systems, during resume the coreboot table is overwritten by the code in `smm_setup_structures()` called by `acpi_resume()` in `src/arch/x86/boot/acpi.c`. As a result, `cbmem` does not work anymore.
Port commit 7978e3a3 (SMM: Pass the ACPI GNVS pointer via state save map), applied to Intel BD82x6x and the explanation below, to the other Intel southbridges too.
Instead of hijacking some random memory addresses to relay the GNVS pointer to SMM we can use EBX register during the write to APM_CNT register when the SMI is triggered.
More or less also copy
commit d396a77b4d144a89a98240541945111280106de6 Author: Duncan Laurie dlaurie@chromium.org Date: Wed Oct 3 18:22:16 2012 -0700
SMM: Extract function for finding save state node
Change-Id: I60013cc6c441ba2696ea3623722d4b0afe2dd2cc Signed-off-by: Paul Menzel paulepanter@users.sourceforge.net --- src/southbridge/intel/i82801gx/smi.c | 18 ++++++++--- src/southbridge/intel/i82801gx/smihandler.c | 49 +++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/src/southbridge/intel/i82801gx/smi.c b/src/southbridge/intel/i82801gx/smi.c index 134c232..84714af 100644 --- a/src/southbridge/intel/i82801gx/smi.c +++ b/src/southbridge/intel/i82801gx/smi.c @@ -383,9 +383,19 @@ void smm_lock(void)
void smm_setup_structures(void *gnvs, void *tcg, void *smi1) { - /* The GDT or coreboot table is going to live here. But a long time - * after we relocated the GNVS, so this is not troublesome. + /* + * 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 */ - *(u32 *)0x500 = (u32)gnvs; - outb(0xea, 0xb2); + asm volatile ( + "outb %%al, %%dx\n\t" + : /* ignore result */ + : "a" (APM_CNT_GNVS_UPDATE), + "b" ((u32)gnvs), + "d" (APM_CNT) + ); } diff --git a/src/southbridge/intel/i82801gx/smihandler.c b/src/southbridge/intel/i82801gx/smihandler.c index e2505ce..58679ff 100644 --- a/src/southbridge/intel/i82801gx/smihandler.c +++ b/src/southbridge/intel/i82801gx/smihandler.c @@ -361,10 +361,49 @@ static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *stat } }
+/* + * 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; + u32 base = smi_get_tseg_base() + SMM_EM64T101_SAVE_STATE_OFFSET; + int node; + + /* Check all nodes looking for the one that issued the IO */ + for (node = 0; node < CONFIG_MAX_CPUS; node++) { + state = (em64t101_smm_state_save_area_t *) + (base - (node * 0x400)); + + /* 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_apmc(unsigned int node, smm_state_save_area_t *state_save) { u32 pmctrl; u8 reg8; + em64t101_smm_state_save_area_t *state;
/* Emulate B2 register as the FADT / Linux expects it */
@@ -404,9 +443,13 @@ static void southbridge_smi_apmc(unsigned int node, smm_state_save_area_t *state printk(BIOS_DEBUG, "SMI#: SMM structures already initialized!\n"); return; } - gnvs = *(global_nvs_t **)0x500; - smm_initialized = 1; - printk(BIOS_DEBUG, "SMI#: Setting up structures to %p\n", gnvs); + 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; default: printk(BIOS_DEBUG, "SMI#: Unknown function APM_CNT=%02x\n", reg8);