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 pbonzini@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);