grml...
[seabios.git] / src / smm.c
index 7e5289206855a8727575065ca1645bcf53022e33..72e5e88c554b1603d67d1a8c332a5269f13aeaf4 100644 (file)
--- a/src/smm.c
+++ b/src/smm.c
@@ -10,7 +10,6 @@
 #include "config.h" // CONFIG_*
 #include "ioport.h" // outb
 #include "pci_ids.h" // PCI_VENDOR_ID_INTEL
-#include "dev-i440fx.h"
 
 ASM32FLAT(
     ".global smm_relocation_start\n"
@@ -73,7 +72,7 @@ ASM32FLAT(
 extern u8 smm_relocation_start, smm_relocation_end;
 extern u8 smm_code_start, smm_code_end;
 
-void
+static void
 smm_save_and_copy(void)
 {
     /* save original memory content */
@@ -84,7 +83,7 @@ smm_save_and_copy(void)
            &smm_relocation_end - &smm_relocation_start);
 }
 
-void
+static void
 smm_relocate_and_restore(void)
 {
     /* init APM status port */
@@ -106,6 +105,37 @@ smm_relocate_and_restore(void)
     wbinvd();
 }
 
+#define I440FX_SMRAM    0x72
+#define PIIX_DEVACTB    0x58
+#define PIIX_APMC_EN    (1 << 25)
+
+// This code is hardcoded for PIIX4 Power Management device.
+static void piix4_apmc_smm_init(struct pci_device *pci, void *arg)
+{
+    struct pci_device *i440_pci = pci_find_device(PCI_VENDOR_ID_INTEL
+                                                  , PCI_DEVICE_ID_INTEL_82441);
+    if (!i440_pci)
+        return;
+
+    /* check if SMM init is already done */
+    u32 value = pci_config_readl(pci->bdf, PIIX_DEVACTB);
+    if (value & PIIX_APMC_EN)
+        return;
+
+    /* enable the SMM memory window */
+    pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x48);
+
+    smm_save_and_copy();
+
+    /* enable SMI generation when writing to the APMC register */
+    pci_config_writel(pci->bdf, PIIX_DEVACTB, value | PIIX_APMC_EN);
+
+    smm_relocate_and_restore();
+
+    /* close the SMM memory window and enable normal SMM */
+    pci_config_writeb(i440_pci->bdf, I440FX_SMRAM, 0x02 | 0x08);
+}
+
 static const struct pci_device_id smm_init_tbl[] = {
     PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
                piix4_apmc_smm_init),