SMM: don't overwrite SMM memory on resume
[coreboot.git] / src / southbridge / intel / i82801gx / smi.c
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,