[coreboot-gerrit] Patch set updated for coreboot: dcaea21 intel/i82801gx: SMM: Pass the ACPI GNVS pointer via state save map

Paul Menzel (paulepanter@users.sourceforge.net) gerrit at coreboot.org
Tue Jan 6 18:10:28 CET 2015


Paul Menzel (paulepanter at 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 at 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 at 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 at 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);



More information about the coreboot-gerrit mailing list