summaryrefslogtreecommitdiff
path: root/OvmfPkg/AcpiPlatformDxe
diff options
context:
space:
mode:
authorjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-08-13 15:42:07 +0000
committerjljusten <jljusten@6f19259b-4bc3-4df7-8a09-765794883524>2012-08-13 15:42:07 +0000
commit498f7d8ddd4f60c8c8226bb6e672be04ab4c18e0 (patch)
tree9ebcdf2f06407107ee0a5e469704d8c28ddc95f1 /OvmfPkg/AcpiPlatformDxe
parent05c89c7f0cd8417d7131d9714ed561f398972512 (diff)
downloadedk2-platforms-498f7d8ddd4f60c8c8226bb6e672be04ab4c18e0.tar.xz
OvmfPkg: generate full MADT dynamically, synchronize contents with qemu
Represent the set of possible PCI link target IRQs with Pcd8259LegacyModeEdgeLevel. This ensures that the 8259 Interrupt Controller code in PcAtChipsetPkg will treat them as level-triggered too. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13628 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'OvmfPkg/AcpiPlatformDxe')
-rw-r--r--OvmfPkg/AcpiPlatformDxe/AcpiPlatformDxe.inf4
-rw-r--r--OvmfPkg/AcpiPlatformDxe/Qemu.c164
2 files changed, 128 insertions, 40 deletions
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 <Library/MemoryAllocationLib.h>
#include <Library/QemuFwCfgLib.h>
#include <Library/DxeServicesTableLib.h>
-
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Acpi.h>
BOOLEAN
QemuDetected (
@@ -33,6 +34,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
QemuInstallAcpiMadtTable (
@@ -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);
-
- if (Count == 1) {
- //
- // The pre-built MADT table covers the single CPU case
- //
- return InstallAcpiTable (
- AcpiProtocol,
- AcpiTableBuffer,
- AcpiTableBufferSize,
- TableKey
- );
- }
+ CpuCount = QemuFwCfgRead16 ();
+ ASSERT (CpuCount >= 1);
//
- // We need to add additional Local APIC entries to the MADT
+ // 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.
//
- NewBufferSize = AcpiTableBufferSize + ((Count - 1) * sizeof (*LocalApic));
- Hdr = (EFI_ACPI_DESCRIPTION_HEADER*) AllocatePool (NewBufferSize);
- ASSERT (Hdr != NULL);
+ PciLinkIsoCount = CountBits16 (PcdGet16 (Pcd8259LegacyModeEdgeLevel));
+
+ NewBufferSize = 1 * sizeof (*Madt) +
+ CpuCount * sizeof (*LocalApic) +
+ 1 * sizeof (*IoApic) +
+ (1 + PciLinkIsoCount) * sizeof (*Iso) +
+ 1 * sizeof (*LocalApicNmi);
- CopyMem (Hdr, AcpiTableBuffer, AcpiTableBufferSize);
+ Madt = AllocatePool (NewBufferSize);
+ if (Madt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ 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;
+
+ 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;
- LocalApic = (EFI_ACPI_1_0_PROCESSOR_LOCAL_APIC_STRUCTURE*)
- (((UINT8*) Hdr) + AcpiTableBufferSize);
+ 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;
//
- // Add Local APIC entries for the APs to the MADT
+ // IRQ0 (8254 Timer) => IRQ2 (PIC) Interrupt Source Override Structure
//
- 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++;
- }
+ 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;
- Hdr->Length = (UINT32) NewBufferSize;
+ //
+ // 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;
- Status = InstallAcpiTable (AcpiProtocol, Hdr, NewBufferSize, TableKey);
+ ASSERT ((UINT8 *)Ptr - (UINT8 *)Madt == NewBufferSize);
+ Status = InstallAcpiTable (AcpiProtocol, Madt, NewBufferSize, TableKey);
- FreePool (Hdr);
+ FreePool (Madt);
return Status;
}