SMM: don't overwrite SMM memory on resume
authorSven Schnelle <svens@stackframe.org>
Tue, 14 Jun 2011 18:55:54 +0000 (20:55 +0200)
committerSven Schnelle <svens@stackframe.org>
Wed, 15 Jun 2011 21:11:44 +0000 (23:11 +0200)
Overwriting the SMM Area on resume leaves us with
all variables cleared out, i.e., the GNVS pointer
is no longer available, which makes SMIF function
calls impossible.

Change-Id: I08ab4ffd41df0922d63c017822de1f89a3ff254d
Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-on: http://review.coreboot.org/34
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
src/cpu/x86/smm/smihandler.c
src/include/cpu/x86/smm.h
src/southbridge/intel/i82801gx/smi.c
src/southbridge/intel/i82801gx/smihandler.c

index bdaedf8dbcf9ad504c0955c82a21a06b7803cd5e..d44a3eae1b8b9f219f7bdfa51c69ecd67ff818d9 100644 (file)
@@ -46,7 +46,7 @@ static int smi_obtain_lock(void)
        return (ret == SMI_UNLOCKED);
 }
 
-static void smi_release_lock(void)
+void smi_release_lock(void)
 {
        asm volatile (
                "movb %1, %%al\n"
index 5605453eabd6d8d29f27b01754dc8ccd3cfc7537..07a9cae30ecfc339d8b301cd54bb2c534cd1bd54 100644 (file)
@@ -272,3 +272,4 @@ void __attribute__((weak)) southbridge_smi_handler(unsigned int node, smm_state_
 
 void __attribute__((weak)) mainboard_smi_gpi(u16 gpi_sts);
 int __attribute__((weak)) mainboard_apm_cnt(u8 data);
+void smi_release_lock(void);
index 95ec1129a3f4d1d038ca78782854319946b04006..5be24049be10d5ebf7303c6670bfb39082052ca1 100644 (file)
@@ -320,6 +320,16 @@ static void smm_relocate(void)
 
 static int smm_handler_copied = 0;
 
+static int is_wakeup(void)
+{
+       device_t dev0 = dev_find_slot(0, PCI_DEVFN(0,0));
+
+       if (!dev0)
+               return 0;
+
+       return pci_read_config32(dev0, 0xdc) == SKPAD_ACPI_S3_MAGIC;
+}
+
 static void smm_install(void)
 {
        /* The first CPU running this gets to copy the SMM handler. But not all
@@ -329,13 +339,19 @@ static void smm_install(void)
                return;
        smm_handler_copied = 1;
 
-       /* enable the SMM memory window */
-       pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
-                               D_OPEN | G_SMRAME | C_BASE_SEG);
 
-       /* copy the real SMM handler */
-       memcpy((void *)0xa0000, &_binary_smm_start, (size_t)&_binary_smm_size);
-       wbinvd();
+       /* if we're resuming from S3, the SMM code is already in place,
+        * so don't copy it again to keep the current SMM state */
+
+       if (!is_wakeup()) {
+               /* enable the SMM memory window */
+               pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
+                                       D_OPEN | G_SMRAME | C_BASE_SEG);
+
+               /* copy the real SMM handler */
+               memcpy((void *)0xa0000, &_binary_smm_start, (size_t)&_binary_smm_size);
+               wbinvd();
+       }
 
        /* close the SMM memory window and enable normal SMM */
        pci_write_config8(dev_find_slot(0, PCI_DEVFN(0, 0)), SMRAM,
index 9befbf9ac18b3497fd3d3c5a3ada174f663bb881..434bfebc18826565e90931159f0e4cb858970628 100644 (file)
@@ -328,6 +328,13 @@ static void southbridge_smi_sleep(unsigned int node, smm_state_save_area_t *stat
        default: printk(BIOS_DEBUG, "SMI#: ERROR: SLP_TYP reserved\n"); break;
        }
 
+       /* Unlock the SMI semaphore. We're currently in SMM, and the semaphore
+        * will never be unlocked because the next outl will switch off the CPU.
+        * This might open a small race between the smi_release_lock() and the outl()
+        * for other SMI handlers. Not sure if this could cause trouble. */
+        if (slp_typ == 5)
+               smi_release_lock();
+
        /* 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.