Both the PIIX and ICH9 require two writes to re-enable SMIs, one for all
SMIs (EOS) and one specific to port 0xb2 SMIs (APM_STS).  Configure the
values at setup time, and perform the I/O while in SMM.  The variables
reside in SMRAM themselves, and are accessed with a CS segment override.

Signed-off-by: Paolo Bonzini <pbonz...@redhat.com>
---
 src/fw/dev-piix.h |  3 +++
 src/fw/dev-q35.h  |  3 +++
 src/fw/smm.c      | 26 ++++++++++++++++++++++++++
 3 files changed, 32 insertions(+)

diff --git a/src/fw/dev-piix.h b/src/fw/dev-piix.h
index c389f17..5df0a89 100644
--- a/src/fw/dev-piix.h
+++ b/src/fw/dev-piix.h
@@ -17,7 +17,10 @@
 /* ICH9 PM I/O registers */
 #define PIIX_GPE0_BLK            0xafe0
 #define PIIX_GPE0_BLK_LEN        4
+#define PIIX_PMIO_GLBSTS         0x18
+#define PIIX_PMIO_GLBSTS_APM_STS (1 << 5)
 #define PIIX_PMIO_GLBCTL         0x28
+#define PIIX_PMIO_GLBCTL_EOS     (1 << 16)
 #define PIIX_PMIO_GLBCTL_SMI_EN  1
 
 /* FADT ACPI_ENABLE/ACPI_DISABLE */
diff --git a/src/fw/dev-q35.h b/src/fw/dev-q35.h
index c6f8bd9..3f8b8d6 100644
--- a/src/fw/dev-q35.h
+++ b/src/fw/dev-q35.h
@@ -40,7 +40,10 @@
 #define ICH9_PMIO_GPE0_BLK_LEN         0x10
 #define ICH9_PMIO_SMI_EN               0x30
 #define ICH9_PMIO_SMI_EN_APMC_EN       (1 << 5)
+#define ICH9_PMIO_SMI_EN_EOS           (1 << 1)
 #define ICH9_PMIO_SMI_EN_GLB_SMI_EN    (1 << 0)
+#define ICH9_PMIO_SMI_STS              0x34
+#define ICH9_PMIO_SMI_STS_APM_STS      (1 << 5)
 
 /* FADT ACPI_ENABLE/ACPI_DISABLE */
 #define ICH9_APM_ACPI_ENABLE           0x2
diff --git a/src/fw/smm.c b/src/fw/smm.c
index b0cc6f5..dbb9f82 100644
--- a/src/fw/smm.c
+++ b/src/fw/smm.c
@@ -19,6 +19,10 @@
 
 extern u8 smm_code_start, smm_code_end;
 
+extern u16 smm_eos_port, smm_status_port;
+extern u32 smm_eos_value, smm_status_value;
+#define SMMVAR(x) "%cs:("__stringify(x)" - smm_code_start + 0x8000)"
+
 ASM32FLAT(
     ".global smm_code_start, smm_code_end\n"
     "  .code16gcc\n"
@@ -44,7 +48,19 @@ ASM32FLAT(
     "  movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
     "  outb %al, %dx\n"
     "smm_exit:\n"
+    "  movw "SMMVAR(smm_status_port)", %dx\n"
+    "  movl "SMMVAR(smm_status_value)", %eax\n"
+    "  outl %eax, %dx\n"     // The SMM status register is write-1-clears
+    "  movw "SMMVAR(smm_eos_port)", %dx\n"
+    "  inl %dx, %eax\n"
+    "  orl "SMMVAR(smm_eos_value)", %eax\n"
+    "  outl %eax, %dx\n"
     "  rsm\n"
+    ".align 4\n"
+    "smm_eos_port: .word 0\n"
+    "smm_status_port: .word 0\n"
+    "smm_eos_value: .long 0\n"
+    "smm_status_value: .long 0\n"
     "smm_code_end:\n"
     "  .code32\n"
     );
@@ -90,6 +106,11 @@ static void piix4_apmc_smm_setup(int isabdf, int i440_bdf)
     if (value & PIIX_DEVACTB_APMC_EN)
         return;
 
+    smm_eos_port = PORT_ACPI_PM_BASE + PIIX_PMIO_GLBCTL;
+    smm_eos_value = PIIX_PMIO_GLBCTL_EOS;
+    smm_status_port = PORT_ACPI_PM_BASE + PIIX_PMIO_GLBSTS;
+    smm_status_value = PIIX_PMIO_GLBSTS_APM_STS;
+
     /* enable the SMM memory window */
     pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48);
 
@@ -117,6 +138,11 @@ void ich9_lpc_apmc_smm_setup(int isabdf, int mch_bdf)
     if (value & ICH9_PMIO_SMI_EN_APMC_EN)
         return;
 
+    smm_eos_port = PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_EN;
+    smm_eos_value = ICH9_PMIO_SMI_EN_EOS;
+    smm_status_port = PORT_ACPI_PM_BASE + ICH9_PMIO_SMI_STS;
+    smm_status_value = ICH9_PMIO_SMI_STS_APM_STS;
+
     /* enable the SMM memory window */
     pci_config_writeb(mch_bdf, Q35_HOST_BRIDGE_SMRAM, 0x02 | 0x48);
 
-- 
1.9.0


_______________________________________________
SeaBIOS mailing list
SeaBIOS@seabios.org
http://www.seabios.org/mailman/listinfo/seabios

Reply via email to