move out piix4 specific smram logic to dev-i440fx.c.
Signed-off-by: Isaku Yamahata yamahata@valinux.co.jp --- changes v2 -> v3. - abstract device level and simplified it. - factor out smm ram relocation. --- src/dev-i440fx.c | 32 +++++++++++++++++++++++++++++ src/dev-i440fx.h | 1 + src/smm.c | 58 +++++++++++++++++++++++------------------------------ src/util.h | 4 +++ 4 files changed, 62 insertions(+), 33 deletions(-)
diff --git a/src/dev-i440fx.c b/src/dev-i440fx.c index 366a2db..346f6d0 100644 --- a/src/dev-i440fx.c +++ b/src/dev-i440fx.c @@ -13,6 +13,7 @@ #include "util.h" // dprintf #include "ioport.h" // outb #include "pci.h" // pci_config_writeb +#include "pci_ids.h" #include "pci_regs.h" // PCI_INTERRUPT_LINE #include "acpi.h" #include "dev-i440fx.h" @@ -82,3 +83,34 @@ void piix4_fadt_init(u16 bdf, void *arg) fadt->gpe0_blk = cpu_to_le32(PIIX4_GPE0_BLK); fadt->gpe0_blk_len = PIIX4_GPE0_BLK_LEN; } + +#define I440FX_SMRAM 0x72 +#define PIIX_DEVACTB 0x58 +#define PIIX_APMC_EN (1 << 25) + +// This code is hardcoded for PIIX4 Power Management device. +void piix4_apmc_smm_init(u16 bdf, void *arg) +{ + int i440_bdf = pci_find_device(PCI_VENDOR_ID_INTEL + , PCI_DEVICE_ID_INTEL_82441); + if (i440_bdf < 0) + return; + + /* check if SMM init is already done */ + u32 value = pci_config_readl(bdf, PIIX_DEVACTB); + if (value & PIIX_APMC_EN) + return; + + /* enable the SMM memory window */ + pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x48); + + smm_save_and_copy(); + + /* enable SMI generation when writing to the APMC register */ + pci_config_writel(bdf, PIIX_DEVACTB, value | PIIX_APMC_EN); + + smm_relocate_and_restore(); + + /* close the SMM memory window and enable normal SMM */ + pci_config_writeb(i440_bdf, I440FX_SMRAM, 0x02 | 0x08); +} diff --git a/src/dev-i440fx.h b/src/dev-i440fx.h index 6d1b687..ab5a4d1 100644 --- a/src/dev-i440fx.h +++ b/src/dev-i440fx.h @@ -9,5 +9,6 @@ void piix_isa_bridge_init(u16 bdf, void *arg); void piix_ide_init(u16 bdf, void *arg); void piix4_pm_init(u16 bdf, void *arg); void piix4_fadt_init(u16 bdf, void *arg); +void piix4_apmc_smm_init(u16 bdf, void *arg);
#endif // __I440FX_H diff --git a/src/smm.c b/src/smm.c index 3f53ef9..7e52892 100644 --- a/src/smm.c +++ b/src/smm.c @@ -10,6 +10,7 @@ #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,45 +74,19 @@ extern u8 smm_relocation_start, smm_relocation_end; extern u8 smm_code_start, smm_code_end;
void -smm_init(void) +smm_save_and_copy(void) { - if (CONFIG_COREBOOT) - // SMM only supported on emulators. - return; - if (!CONFIG_USE_SMM) - return; - - dprintf(3, "init smm\n"); - - // This code is hardcoded for PIIX4 Power Management device. - int bdf = pci_find_device(PCI_VENDOR_ID_INTEL - , PCI_DEVICE_ID_INTEL_82371AB_3); - if (bdf < 0) - // Device not found - return; - int i440_bdf = pci_find_device(PCI_VENDOR_ID_INTEL - , PCI_DEVICE_ID_INTEL_82441); - if (i440_bdf < 0) - return; - - /* check if SMM init is already done */ - u32 value = pci_config_readl(bdf, 0x58); - if (value & (1 << 25)) - return; - - /* enable the SMM memory window */ - pci_config_writeb(i440_bdf, 0x72, 0x02 | 0x48); - /* save original memory content */ memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
/* copy the SMM relocation code */ memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_relocation_start, &smm_relocation_end - &smm_relocation_start); +}
- /* enable SMI generation when writing to the APMC register */ - pci_config_writel(bdf, 0x58, value | (1 << 25)); - +void +smm_relocate_and_restore(void) +{ /* init APM status port */ outb(0x01, PORT_SMI_STATUS);
@@ -129,7 +104,24 @@ smm_init(void) memcpy((void *)BUILD_SMM_ADDR, &smm_code_start , &smm_code_end - &smm_code_start); wbinvd(); +} + +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), + + PCI_DEVICE_END, +}; + +void +smm_init(void) +{ + if (CONFIG_COREBOOT) + // SMM only supported on emulators. + return; + if (!CONFIG_USE_SMM) + return;
- /* close the SMM memory window and enable normal SMM */ - pci_config_writeb(i440_bdf, 0x72, 0x02 | 0x08); + dprintf(3, "init smm\n"); + pci_find_init_device(smm_init_tbl, NULL); } diff --git a/src/util.h b/src/util.h index 96f4ff7..85cf3f5 100644 --- a/src/util.h +++ b/src/util.h @@ -335,6 +335,10 @@ void make_bios_readonly(void); void make_bios_writable_intel(u16 bdf, u32 pam0); void make_bios_readonly_intel(u16 bdf, u32 pam0);
+// smm.c +void smm_save_and_copy(void); +void smm_relocate_and_restore(void); + // pciinit.c extern const u8 pci_irqs[4]; void pci_bios_allocate_regions(u16 bdf, void *arg);