X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fsmm.c;h=72e5e88c554b1603d67d1a8c332a5269f13aeaf4;hb=refs%2Fheads%2Fcoreboot;hp=31e56d8c285bac984ed6bcec65407ac88ff1a2c8;hpb=c0693941fdb5118164a8161316fdf8e9ebb499d2;p=seabios.git diff --git a/src/smm.c b/src/smm.c index 31e56d8..72e5e88 100644 --- a/src/smm.c +++ b/src/smm.c @@ -11,7 +11,7 @@ #include "ioport.h" // outb #include "pci_ids.h" // PCI_VENDOR_ID_INTEL -ASM32( +ASM32FLAT( ".global smm_relocation_start\n" ".global smm_relocation_end\n" ".global smm_code_start\n" @@ -72,46 +72,20 @@ ASM32( extern u8 smm_relocation_start, smm_relocation_end; extern u8 smm_code_start, smm_code_end; -void -smm_init() +static 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)); - +static void +smm_relocate_and_restore(void) +{ /* init APM status port */ outb(0x01, PORT_SMI_STATUS); @@ -129,7 +103,55 @@ smm_init() memcpy((void *)BUILD_SMM_ADDR, &smm_code_start , &smm_code_end - &smm_code_start); 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_bdf, 0x72, 0x02 | 0x08); + 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), + + PCI_DEVICE_END, +}; + +void +smm_init(void) +{ + if (CONFIG_COREBOOT) + // SMM only supported on emulators. + return; + if (!CONFIG_USE_SMM) + return; + + dprintf(3, "init smm\n"); + pci_find_init_device(smm_init_tbl, NULL); }