diff --git a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf index 04eb495cac..acc224728e 100644 --- a/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf +++ b/OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf @@ -35,6 +35,8 @@ MdePkg/MdePkg.dec MdeModulePkg/MdeModulePkg.dec OvmfPkg/OvmfPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec [LibraryClasses] UefiLib @@ -58,6 +60,8 @@ [Pcd] gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiTableStorageFile + gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress + gPcAtChipsetPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel [Depex] gEfiAcpiTableProtocolGuid diff --git a/OvmfPkg/AcpiPlatformDxe/Qemu.c b/OvmfPkg/AcpiPlatformDxe/Qemu.c index 4c88c32ec8..1ac443f3f2 100644 --- a/OvmfPkg/AcpiPlatformDxe/Qemu.c +++ b/OvmfPkg/AcpiPlatformDxe/Qemu.c @@ -17,7 +17,8 @@ #include #include #include - +#include +#include BOOLEAN QemuDetected ( @@ -32,6 +33,27 @@ QemuDetected ( } +STATIC +UINTN +CountBits16 ( + UINT16 Mask + ) +{ + // + // For all N >= 1, N bits are enough to represent the number of bits set + // among N bits. It's true for N == 1. When adding a new bit (N := N+1), + // the maximum number of possibly set bits increases by one, while the + // representable maximum doubles. + // + Mask = ((Mask & 0xAAAA) >> 1) + (Mask & 0x5555); + Mask = ((Mask & 0xCCCC) >> 2) + (Mask & 0x3333); + Mask = ((Mask & 0xF0F0) >> 4) + (Mask & 0x0F0F); + Mask = ((Mask & 0xFF00) >> 8) + (Mask & 0x00FF); + + return Mask; +} + + STATIC EFI_STATUS EFIAPI @@ -42,58 +64,120 @@ QemuInstallAcpiMadtTable ( OUT UINTN *TableKey ) { - EFI_STATUS Status; - UINTN Count; - UINTN Loop; - EFI_ACPI_DESCRIPTION_HEADER *Hdr; - UINTN NewBufferSize; - EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic; + UINTN CpuCount; + UINTN PciLinkIsoCount; + UINTN NewBufferSize; + EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt; + EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic; + EFI_ACPI_1_0_IO_APIC_STRUCTURE *IoApic; + EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *Iso; + EFI_ACPI_1_0_LOCAL_APIC_NMI_STRUCTURE *LocalApicNmi; + VOID *Ptr; + UINTN Loop; + EFI_STATUS Status; + + ASSERT (AcpiTableBufferSize >= sizeof (EFI_ACPI_DESCRIPTION_HEADER)); QemuFwCfgSelectItem (QemuFwCfgItemSmpCpuCount); - Count = (UINTN) QemuFwCfgRead16 (); - ASSERT (Count >= 1); + CpuCount = QemuFwCfgRead16 (); + ASSERT (CpuCount >= 1); - if (Count == 1) { - // - // The pre-built MADT table covers the single CPU case - // - return InstallAcpiTable ( - AcpiProtocol, - AcpiTableBuffer, - AcpiTableBufferSize, - TableKey - ); + // + // Set Level-tiggered, Active High for these identity mapped IRQs. The bitset + // corresponds to the union of all possible interrupt assignments for the LNKA, + // LNKB, LNKC, LNKD PCI interrupt lines. See the DSDT. + // + PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel)); + + NewBufferSize = 1 * sizeof (*Madt) + + CpuCount * sizeof (*LocalApic) + + 1 * sizeof (*IoApic) + + (1 + PciLinkIsoCount) * sizeof (*Iso) + + 1 * sizeof (*LocalApicNmi); + + Madt = AllocatePool (NewBufferSize); + if (Madt == NULL) { + return EFI_OUT_OF_RESOURCES; } - // - // We need to add additional Local APIC entries to the MADT - // - NewBufferSize = AcpiTableBufferSize + ((Count - 1) * sizeof (*LocalApic)); - Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AllocatePool (NewBufferSize); - ASSERT (Hdr != NULL); + Madt->Header = *(EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer; + Madt->Header.Length = NewBufferSize; + Madt->LocalApicAddress = PcdGet32 (PcdCpuLocalApicBaseAddress); + Madt->Flags = EFI_ACPI_1_0_PCAT_COMPAT; + Ptr = Madt + 1; - CopyMem (Hdr, AcpiTableBuffer, AcpiTableBufferSize); - - LocalApic = (EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE*) - (((UINT8*) Hdr) + AcpiTableBufferSize); - - // - // Add Local APIC entries for the APs to the MADT - // - for (Loop = 1; Loop < Count; Loop++) { - LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC; - LocalApic->Length = sizeof (*LocalApic); - LocalApic->AcpiProcessorId = (UINT8) Loop; - LocalApic->ApicId = (UINT8) Loop; - LocalApic->Flags = 1; - LocalApic++; + LocalApic = Ptr; + for (Loop = 0; Loop < CpuCount; ++Loop) { + LocalApic->Type = EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC; + LocalApic->Length = sizeof (*LocalApic); + LocalApic->AcpiProcessorId = Loop; + LocalApic->ApicId = Loop; + LocalApic->Flags = 1; // enabled + ++LocalApic; } + Ptr = LocalApic; - Hdr->Length = (UINT32) NewBufferSize; + IoApic = Ptr; + IoApic->Type = EFI_ACPI_1_0_IO_APIC; + IoApic->Length = sizeof (*IoApic); + IoApic->IoApicId = CpuCount; + IoApic->Reserved = EFI_ACPI_RESERVED_BYTE; + IoApic->IoApicAddress = 0xFEC00000; + IoApic->SystemVectorBase = 0x00000000; + Ptr = IoApic + 1; - Status = InstallAcpiTable (AcpiProtocol, Hdr, NewBufferSize, TableKey); + // + // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure + // + Iso = Ptr; + Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE; + Iso->Length = sizeof (*Iso); + Iso->Bus = 0x00; // ISA + Iso->Source = 0x00; // IRQ0 + Iso->GlobalSystemInterruptVector = 0x00000002; + Iso->Flags = 0x0000; // Conforms to specs of the bus + ++Iso; - FreePool (Hdr); + // + // Set Level-tiggered, Active High for all possible PCI link targets. + // + for (Loop = 0; Loop < 16; ++Loop) { + if ((PcdGet16 (Pcd8259LegacyModeEdgeLevel) & (1 << Loop)) == 0) { + continue; + } + Iso->Type = EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE; + Iso->Length = sizeof (*Iso); + Iso->Bus = 0x00; // ISA + Iso->Source = Loop; + Iso->GlobalSystemInterruptVector = Loop; + Iso->Flags = 0x000D; // Level-tiggered, Active High + ++Iso; + } + ASSERT ( + Iso - (EFI_ACPI_1_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE *)Ptr == + 1 + PciLinkIsoCount + ); + Ptr = Iso; + + LocalApicNmi = Ptr; + LocalApicNmi->Type = EFI_ACPI_1_0_LOCAL_APIC_NMI; + LocalApicNmi->Length = sizeof (*LocalApicNmi); + LocalApicNmi->AcpiProcessorId = 0xFF; // applies to all processors + // + // polarity and trigger mode of the APIC I/O input signals conform to the + // specifications of the bus + // + LocalApicNmi->Flags = 0x0000; + // + // Local APIC interrupt input LINTn to which NMI is connected. + // + LocalApicNmi->LocalApicInti = 0x01; + Ptr = LocalApicNmi + 1; + + ASSERT ((UINT8 *)Ptr - (UINT8 *)Madt == NewBufferSize); + Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey); + + FreePool (Madt); return Status; } diff --git a/OvmfPkg/AcpiTables/Madt.aslc b/OvmfPkg/AcpiTables/Madt.aslc index f5b71a6e0c..62bf2c7fd2 100644 --- a/OvmfPkg/AcpiTables/Madt.aslc +++ b/OvmfPkg/AcpiTables/Madt.aslc @@ -16,11 +16,7 @@ **/ #include - -// -// MADT Definitions -// -#define EFI_ACPI_OEM_MADT_REVISION 0x00000000 // TBD +#include // // Local APIC address @@ -74,21 +70,12 @@ EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE Madt = { EFI_ACPI_1_0_APIC_SIGNATURE, sizeof (EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE), EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION, - - // - // Checksum will be updated at runtime - // - 0x00, - - // - // It is expected that these values will be programmed at runtime - // - ' ', ' ', ' ', ' ', ' ', ' ', - - 0, - EFI_ACPI_OEM_MADT_REVISION, - 0, - 0, + 0x00, // Checksum will be updated at runtime + EFI_ACPI_OEM_ID, + EFI_ACPI_OEM_TABLE_ID, + EFI_ACPI_OEM_REVISION, + EFI_ACPI_CREATOR_ID, + EFI_ACPI_CREATOR_REVISION, // // MADT specific fields diff --git a/OvmfPkg/AcpiTables/Platform.h b/OvmfPkg/AcpiTables/Platform.h index 4b03897614..e8fae3c839 100644 --- a/OvmfPkg/AcpiTables/Platform.h +++ b/OvmfPkg/AcpiTables/Platform.h @@ -23,9 +23,9 @@ // #define EFI_ACPI_OEM_ID 'O','V','M','F',' ',' ' // OEMID 6 bytes long #define EFI_ACPI_OEM_TABLE_ID SIGNATURE_64('O','V','M','F','E','D','K','2') // OEM table id 8 bytes long -#define EFI_ACPI_OEM_REVISION 0x02000820 +#define EFI_ACPI_OEM_REVISION 0x20120804 #define EFI_ACPI_CREATOR_ID SIGNATURE_32('O','V','M','F') -#define EFI_ACPI_CREATOR_REVISION 0x00000097 +#define EFI_ACPI_CREATOR_REVISION 0x00000098 #define INT_MODEL 0x01 #define SCI_INT_VECTOR 0x0009 diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc index ffedcbf6de..453a5788cb 100644 --- a/OvmfPkg/OvmfPkgIa32.dsc +++ b/OvmfPkg/OvmfPkgIa32.dsc @@ -302,6 +302,9 @@ !endif !endif + # IRQs 5, 9, 10, 11 are level-triggered + gPcAtChipsetPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel|0x0E20 + !if $(SECURE_BOOT_ENABLE) == TRUE # override the default values from SecurityPkg to ensure images from all sources are verified in secure boot gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x05 diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc index 123ac31e01..73e8c987b5 100644 --- a/OvmfPkg/OvmfPkgIa32X64.dsc +++ b/OvmfPkg/OvmfPkgIa32X64.dsc @@ -302,6 +302,9 @@ !endif !endif + # IRQs 5, 9, 10, 11 are level-triggered + gPcAtChipsetPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel|0x0E20 + [PcdsFixedAtBuild.X64] !if $(SECURE_BOOT_ENABLE) == TRUE # override the default values from SecurityPkg to ensure images from all sources are verified in secure boot diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc index 1fce7a7e8c..1c2aec0cdc 100644 --- a/OvmfPkg/OvmfPkgX64.dsc +++ b/OvmfPkg/OvmfPkgX64.dsc @@ -302,6 +302,9 @@ !endif !endif + # IRQs 5, 9, 10, 11 are level-triggered + gPcAtChipsetPkgTokenSpaceGuid.Pcd8259LegacyModeEdgeLevel|0x0E20 + !if $(SECURE_BOOT_ENABLE) == TRUE # override the default values from SecurityPkg to ensure images from all sources are verified in secure boot gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy|0x05