| /** @file | |
| Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php. | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include "DmaProtection.h" | |
| #pragma pack(1) | |
| typedef struct { | |
| EFI_ACPI_DESCRIPTION_HEADER Header; | |
| UINT32 Entry; | |
| } RSDT_TABLE; | |
| typedef struct { | |
| EFI_ACPI_DESCRIPTION_HEADER Header; | |
| UINT64 Entry; | |
| } XSDT_TABLE; | |
| #pragma pack() | |
| EFI_ACPI_DMAR_HEADER *mAcpiDmarTable = NULL; | |
| /** | |
| Dump DMAR DeviceScopeEntry. | |
| @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry | |
| **/ | |
| VOID | |
| DumpDmarDeviceScopeEntry ( | |
| IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry | |
| ) | |
| { | |
| UINTN PciPathNumber; | |
| UINTN PciPathIndex; | |
| EFI_ACPI_DMAR_PCI_PATH *PciPath; | |
| if (DmarDeviceScopeEntry == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " *************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * DMA-Remapping Device Scope Entry Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " *************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " DMAR Device Scope Entry address ...................... 0x%016lx\n" : | |
| " DMAR Device Scope Entry address ...................... 0x%08x\n", | |
| DmarDeviceScopeEntry | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Device Scope Entry Type ............................ 0x%02x\n", | |
| DmarDeviceScopeEntry->Type | |
| )); | |
| switch (DmarDeviceScopeEntry->Type) { | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: | |
| DEBUG ((DEBUG_INFO, | |
| " PCI Endpoint Device\n" | |
| )); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: | |
| DEBUG ((DEBUG_INFO, | |
| " PCI Sub-hierachy\n" | |
| )); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC: | |
| DEBUG ((DEBUG_INFO, | |
| " IOAPIC\n" | |
| )); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET: | |
| DEBUG ((DEBUG_INFO, | |
| " MSI Capable HPET\n" | |
| )); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE: | |
| DEBUG ((DEBUG_INFO, | |
| " ACPI Namespace Device\n" | |
| )); | |
| break; | |
| default: | |
| break; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................. 0x%02x\n", | |
| DmarDeviceScopeEntry->Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Enumeration ID ..................................... 0x%02x\n", | |
| DmarDeviceScopeEntry->EnumerationId | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Starting Bus Number ................................ 0x%02x\n", | |
| DmarDeviceScopeEntry->StartBusNumber | |
| )); | |
| PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH); | |
| PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1); | |
| for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) { | |
| DEBUG ((DEBUG_INFO, | |
| " Device ............................................. 0x%02x\n", | |
| PciPath[PciPathIndex].Device | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Function ........................................... 0x%02x\n", | |
| PciPath[PciPathIndex].Function | |
| )); | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " *************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR ANDD table. | |
| @param[in] Andd DMAR ANDD table | |
| **/ | |
| VOID | |
| DumpDmarAndd ( | |
| IN EFI_ACPI_DMAR_ANDD_HEADER *Andd | |
| ) | |
| { | |
| if (Andd == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * ACPI Name-space Device Declaration Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " ANDD address ........................................... 0x%016lx\n" : | |
| " ANDD address ........................................... 0x%08x\n", | |
| Andd | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Type ................................................. 0x%04x\n", | |
| Andd->Header.Type | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................... 0x%04x\n", | |
| Andd->Header.Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ACPI Device Number ................................... 0x%02x\n", | |
| Andd->AcpiDeviceNumber | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ACPI Object Name ..................................... '%a'\n", | |
| (Andd + 1) | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR RHSA table. | |
| @param[in] Rhsa DMAR RHSA table | |
| **/ | |
| VOID | |
| DumpDmarRhsa ( | |
| IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa | |
| ) | |
| { | |
| if (Rhsa == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * Remapping Hardware Status Affinity Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " RHSA address ........................................... 0x%016lx\n" : | |
| " RHSA address ........................................... 0x%08x\n", | |
| Rhsa | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Type ................................................. 0x%04x\n", | |
| Rhsa->Header.Type | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................... 0x%04x\n", | |
| Rhsa->Header.Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Register Base Address ................................ 0x%016lx\n", | |
| Rhsa->RegisterBaseAddress | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Proximity Domain ..................................... 0x%08x\n", | |
| Rhsa->ProximityDomain | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR ATSR table. | |
| @param[in] Atsr DMAR ATSR table | |
| **/ | |
| VOID | |
| DumpDmarAtsr ( | |
| IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr | |
| ) | |
| { | |
| EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; | |
| INTN AtsrLen; | |
| if (Atsr == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * Root Port ATS Capability Reporting Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " ATSR address ........................................... 0x%016lx\n" : | |
| " ATSR address ........................................... 0x%08x\n", | |
| Atsr | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Type ................................................. 0x%04x\n", | |
| Atsr->Header.Type | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................... 0x%04x\n", | |
| Atsr->Header.Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Flags ................................................ 0x%02x\n", | |
| Atsr->Flags | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ALL_PORTS .......................................... 0x%02x\n", | |
| Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Segment Number ....................................... 0x%04x\n", | |
| Atsr->SegmentNumber | |
| )); | |
| AtsrLen = Atsr->Header.Length - sizeof(EFI_ACPI_DMAR_ATSR_HEADER); | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Atsr + 1); | |
| while (AtsrLen > 0) { | |
| DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); | |
| AtsrLen -= DmarDeviceScopeEntry->Length; | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR RMRR table. | |
| @param[in] Rmrr DMAR RMRR table | |
| **/ | |
| VOID | |
| DumpDmarRmrr ( | |
| IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr | |
| ) | |
| { | |
| EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; | |
| INTN RmrrLen; | |
| if (Rmrr == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * Reserved Memory Region Reporting Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " RMRR address ........................................... 0x%016lx\n" : | |
| " RMRR address ........................................... 0x%08x\n", | |
| Rmrr | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Type ................................................. 0x%04x\n", | |
| Rmrr->Header.Type | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................... 0x%04x\n", | |
| Rmrr->Header.Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Segment Number ....................................... 0x%04x\n", | |
| Rmrr->SegmentNumber | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Reserved Memory Region Base Address .................. 0x%016lx\n", | |
| Rmrr->ReservedMemoryRegionBaseAddress | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Reserved Memory Region Limit Address ................. 0x%016lx\n", | |
| Rmrr->ReservedMemoryRegionLimitAddress | |
| )); | |
| RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER); | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1); | |
| while (RmrrLen > 0) { | |
| DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); | |
| RmrrLen -= DmarDeviceScopeEntry->Length; | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR DRHD table. | |
| @param[in] Drhd DMAR DRHD table | |
| **/ | |
| VOID | |
| DumpDmarDrhd ( | |
| IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd | |
| ) | |
| { | |
| EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; | |
| INTN DrhdLen; | |
| if (Drhd == NULL) { | |
| return; | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " * DMA-Remapping Hardware Definition Structure *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| " DRHD address ........................................... 0x%016lx\n" : | |
| " DRHD address ........................................... 0x%08x\n", | |
| Drhd | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Type ................................................. 0x%04x\n", | |
| Drhd->Header.Type | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Length ............................................... 0x%04x\n", | |
| Drhd->Header.Length | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Flags ................................................ 0x%02x\n", | |
| Drhd->Flags | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " INCLUDE_PCI_ALL .................................... 0x%02x\n", | |
| Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Segment Number ....................................... 0x%04x\n", | |
| Drhd->SegmentNumber | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Register Base Address ................................ 0x%016lx\n", | |
| Drhd->RegisterBaseAddress | |
| )); | |
| DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER); | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1); | |
| while (DrhdLen > 0) { | |
| DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry); | |
| DrhdLen -= DmarDeviceScopeEntry->Length; | |
| DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| " ***************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR ACPI table. | |
| @param[in] Dmar DMAR ACPI table | |
| **/ | |
| VOID | |
| DumpAcpiDMAR ( | |
| IN EFI_ACPI_DMAR_HEADER *Dmar | |
| ) | |
| { | |
| EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; | |
| INTN DmarLen; | |
| if (Dmar == NULL) { | |
| return; | |
| } | |
| // | |
| // Dump Dmar table | |
| // | |
| DEBUG ((DEBUG_INFO, | |
| "*****************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| "* DMAR Table *\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| "*****************************************************************************\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| (sizeof(UINTN) == sizeof(UINT64)) ? | |
| "DMAR address ............................................. 0x%016lx\n" : | |
| "DMAR address ............................................. 0x%08x\n", | |
| Dmar | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Table Contents:\n" | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Host Address Width ................................... 0x%02x\n", | |
| Dmar->HostAddressWidth | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " Flags ................................................ 0x%02x\n", | |
| Dmar->Flags | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " INTR_REMAP ......................................... 0x%02x\n", | |
| Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP | |
| )); | |
| DEBUG ((DEBUG_INFO, | |
| " X2APIC_OPT_OUT_SET ................................. 0x%02x\n", | |
| Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT | |
| )); | |
| DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER); | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1); | |
| while (DmarLen > 0) { | |
| switch (DmarHeader->Type) { | |
| case EFI_ACPI_DMAR_TYPE_DRHD: | |
| DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); | |
| break; | |
| case EFI_ACPI_DMAR_TYPE_RMRR: | |
| DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); | |
| break; | |
| case EFI_ACPI_DMAR_TYPE_ATSR: | |
| DumpDmarAtsr ((EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader); | |
| break; | |
| case EFI_ACPI_DMAR_TYPE_RHSA: | |
| DumpDmarRhsa ((EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader); | |
| break; | |
| case EFI_ACPI_DMAR_TYPE_ANDD: | |
| DumpDmarAndd ((EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader); | |
| break; | |
| default: | |
| break; | |
| } | |
| DmarLen -= DmarHeader->Length; | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); | |
| } | |
| DEBUG ((DEBUG_INFO, | |
| "*****************************************************************************\n\n" | |
| )); | |
| return; | |
| } | |
| /** | |
| Dump DMAR ACPI table. | |
| **/ | |
| VOID | |
| VtdDumpDmarTable ( | |
| VOID | |
| ) | |
| { | |
| DumpAcpiDMAR ((EFI_ACPI_DMAR_HEADER *)(UINTN)mAcpiDmarTable); | |
| } | |
| /** | |
| Get PCI device information from DMAR DevScopeEntry. | |
| @param[in] Segment The segment number. | |
| @param[in] DmarDevScopeEntry DMAR DevScopeEntry | |
| @param[out] Bus The bus number. | |
| @param[out] Device The device number. | |
| @param[out] Function The function number. | |
| @retval EFI_SUCCESS The PCI device information is returned. | |
| **/ | |
| EFI_STATUS | |
| GetPciBusDeviceFunction ( | |
| IN UINT16 Segment, | |
| IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry, | |
| OUT UINT8 *Bus, | |
| OUT UINT8 *Device, | |
| OUT UINT8 *Function | |
| ) | |
| { | |
| EFI_ACPI_DMAR_PCI_PATH *DmarPciPath; | |
| UINT8 MyBus; | |
| UINT8 MyDevice; | |
| UINT8 MyFunction; | |
| DmarPciPath = (EFI_ACPI_DMAR_PCI_PATH *)((UINTN)(DmarDevScopeEntry + 1)); | |
| MyBus = DmarDevScopeEntry->StartBusNumber; | |
| MyDevice = DmarPciPath->Device; | |
| MyFunction = DmarPciPath->Function; | |
| switch (DmarDevScopeEntry->Type) { | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: | |
| while ((UINTN)DmarPciPath + sizeof(EFI_ACPI_DMAR_PCI_PATH) < (UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length) { | |
| MyBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, MyBus, MyDevice, MyFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); | |
| DmarPciPath ++; | |
| MyDevice = DmarPciPath->Device; | |
| MyFunction = DmarPciPath->Function; | |
| } | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC: | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET: | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE: | |
| break; | |
| } | |
| *Bus = MyBus; | |
| *Device = MyDevice; | |
| *Function = MyFunction; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Process DMAR DHRD table. | |
| @param[in] VtdIndex The index of VTd engine. | |
| @param[in] DmarDrhd The DRHD table. | |
| @retval EFI_SUCCESS The DRHD table is processed. | |
| **/ | |
| EFI_STATUS | |
| ProcessDhrd ( | |
| IN UINTN VtdIndex, | |
| IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd | |
| ) | |
| { | |
| EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry; | |
| UINT8 Bus; | |
| UINT8 Device; | |
| UINT8 Function; | |
| UINT8 SecondaryBusNumber; | |
| EFI_STATUS Status; | |
| VTD_SOURCE_ID SourceId; | |
| mVtdUnitInformation[VtdIndex].VtdUnitBaseAddress = (UINTN)DmarDrhd->RegisterBaseAddress; | |
| DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress)); | |
| mVtdUnitInformation[VtdIndex].Segment = DmarDrhd->SegmentNumber; | |
| if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) { | |
| mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = TRUE; | |
| DEBUG ((DEBUG_INFO," ProcessDhrd: with INCLUDE ALL\n")); | |
| Status = ScanPciBus((VOID *)VtdIndex, DmarDrhd->SegmentNumber, 0, ScanBusCallbackRegisterPciDevice); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| } else { | |
| mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag = FALSE; | |
| DEBUG ((DEBUG_INFO," ProcessDhrd: without INCLUDE ALL\n")); | |
| } | |
| DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1)); | |
| while ((UINTN)DmarDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) { | |
| Status = GetPciBusDeviceFunction (DmarDrhd->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| DEBUG ((DEBUG_INFO," ProcessDhrd: ")); | |
| switch (DmarDevScopeEntry->Type) { | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: | |
| DEBUG ((DEBUG_INFO,"PCI Endpoint")); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: | |
| DEBUG ((DEBUG_INFO,"PCI-PCI bridge")); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC: | |
| DEBUG ((DEBUG_INFO,"IOAPIC")); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET: | |
| DEBUG ((DEBUG_INFO,"MSI Capable HPET")); | |
| break; | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE: | |
| DEBUG ((DEBUG_INFO,"ACPI Namespace Device")); | |
| break; | |
| } | |
| DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", DmarDrhd->SegmentNumber, Bus, Device, Function)); | |
| SourceId.Bits.Bus = Bus; | |
| SourceId.Bits.Device = Device; | |
| SourceId.Bits.Function = Function; | |
| Status = RegisterPciDevice (VtdIndex, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE); | |
| if (EFI_ERROR (Status)) { | |
| // | |
| // There might be duplication for special device other than standard PCI device. | |
| // | |
| switch (DmarDevScopeEntry->Type) { | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: | |
| return Status; | |
| } | |
| } | |
| switch (DmarDevScopeEntry->Type) { | |
| case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: | |
| SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DmarDrhd->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET)); | |
| Status = ScanPciBus ((VOID *)VtdIndex, DmarDrhd->SegmentNumber, SecondaryBusNumber, ScanBusCallbackRegisterPciDevice); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Process DMAR RMRR table. | |
| @param[in] DmarRmrr The RMRR table. | |
| @retval EFI_SUCCESS The RMRR table is processed. | |
| **/ | |
| EFI_STATUS | |
| ProcessRmrr ( | |
| IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr | |
| ) | |
| { | |
| EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry; | |
| UINT8 Bus; | |
| UINT8 Device; | |
| UINT8 Function; | |
| EFI_STATUS Status; | |
| VTD_SOURCE_ID SourceId; | |
| DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress)); | |
| DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1)); | |
| while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) { | |
| if (DmarDevScopeEntry->Type != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) { | |
| DEBUG ((DEBUG_INFO,"RMRR DevScopeEntryType is not endpoint, type[0x%x] \n", DmarDevScopeEntry->Type)); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| DEBUG ((DEBUG_INFO,"RMRR S%04x B%02x D%02x F%02x\n", DmarRmrr->SegmentNumber, Bus, Device, Function)); | |
| SourceId.Bits.Bus = Bus; | |
| SourceId.Bits.Device = Device; | |
| SourceId.Bits.Function = Function; | |
| Status = SetAccessAttribute ( | |
| DmarRmrr->SegmentNumber, | |
| SourceId, | |
| DmarRmrr->ReservedMemoryRegionBaseAddress, | |
| DmarRmrr->ReservedMemoryRegionLimitAddress + 1 - DmarRmrr->ReservedMemoryRegionBaseAddress, | |
| EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length); | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Get VTd engine number. | |
| **/ | |
| UINTN | |
| GetVtdEngineNumber ( | |
| VOID | |
| ) | |
| { | |
| EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; | |
| UINTN VtdIndex; | |
| VtdIndex = 0; | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); | |
| while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { | |
| switch (DmarHeader->Type) { | |
| case EFI_ACPI_DMAR_TYPE_DRHD: | |
| VtdIndex++; | |
| break; | |
| default: | |
| break; | |
| } | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); | |
| } | |
| return VtdIndex ; | |
| } | |
| /** | |
| Parse DMAR DRHD table. | |
| @return EFI_SUCCESS The DMAR DRHD table is parsed. | |
| **/ | |
| EFI_STATUS | |
| ParseDmarAcpiTableDrhd ( | |
| VOID | |
| ) | |
| { | |
| EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; | |
| EFI_STATUS Status; | |
| UINTN VtdIndex; | |
| mVtdUnitNumber = GetVtdEngineNumber (); | |
| DEBUG ((DEBUG_INFO," VtdUnitNumber - %d\n", mVtdUnitNumber)); | |
| ASSERT (mVtdUnitNumber > 0); | |
| if (mVtdUnitNumber == 0) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| mVtdUnitInformation = AllocateZeroPool (sizeof(*mVtdUnitInformation) * mVtdUnitNumber); | |
| ASSERT (mVtdUnitInformation != NULL); | |
| if (mVtdUnitInformation == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| VtdIndex = 0; | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); | |
| while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { | |
| switch (DmarHeader->Type) { | |
| case EFI_ACPI_DMAR_TYPE_DRHD: | |
| ASSERT (VtdIndex < mVtdUnitNumber); | |
| Status = ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| VtdIndex++; | |
| break; | |
| default: | |
| break; | |
| } | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); | |
| } | |
| ASSERT (VtdIndex == mVtdUnitNumber); | |
| for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) { | |
| DumpPciDeviceInfo (VtdIndex); | |
| } | |
| return EFI_SUCCESS ; | |
| } | |
| /** | |
| Parse DMAR DRHD table. | |
| @return EFI_SUCCESS The DMAR DRHD table is parsed. | |
| **/ | |
| EFI_STATUS | |
| ParseDmarAcpiTableRmrr ( | |
| VOID | |
| ) | |
| { | |
| EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; | |
| EFI_STATUS Status; | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1)); | |
| while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) { | |
| switch (DmarHeader->Type) { | |
| case EFI_ACPI_DMAR_TYPE_RMRR: | |
| Status = ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); | |
| } | |
| return EFI_SUCCESS ; | |
| } | |
| /** | |
| This function scan ACPI table in RSDT. | |
| @param[in] Rsdt ACPI RSDT | |
| @param[in] Signature ACPI table signature | |
| @return ACPI table | |
| **/ | |
| VOID * | |
| ScanTableInRSDT ( | |
| IN RSDT_TABLE *Rsdt, | |
| IN UINT32 Signature | |
| ) | |
| { | |
| UINTN Index; | |
| UINT32 EntryCount; | |
| UINT32 *EntryPtr; | |
| EFI_ACPI_DESCRIPTION_HEADER *Table; | |
| EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32); | |
| EntryPtr = &Rsdt->Entry; | |
| for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) { | |
| Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr)); | |
| if ((Table != NULL) && (Table->Signature == Signature)) { | |
| return Table; | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| This function scan ACPI table in XSDT. | |
| @param[in] Xsdt ACPI XSDT | |
| @param[in] Signature ACPI table signature | |
| @return ACPI table | |
| **/ | |
| VOID * | |
| ScanTableInXSDT ( | |
| IN XSDT_TABLE *Xsdt, | |
| IN UINT32 Signature | |
| ) | |
| { | |
| UINTN Index; | |
| UINT32 EntryCount; | |
| UINT64 EntryPtr; | |
| UINTN BasePtr; | |
| EFI_ACPI_DESCRIPTION_HEADER *Table; | |
| EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64); | |
| BasePtr = (UINTN)(&(Xsdt->Entry)); | |
| for (Index = 0; Index < EntryCount; Index ++) { | |
| CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64)); | |
| Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr)); | |
| if ((Table != NULL) && (Table->Signature == Signature)) { | |
| return Table; | |
| } | |
| } | |
| return NULL; | |
| } | |
| /** | |
| This function scan ACPI table in RSDP. | |
| @param[in] Rsdp ACPI RSDP | |
| @param[in] Signature ACPI table signature | |
| @return ACPI table | |
| **/ | |
| VOID * | |
| FindAcpiPtr ( | |
| IN EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp, | |
| IN UINT32 Signature | |
| ) | |
| { | |
| EFI_ACPI_DESCRIPTION_HEADER *AcpiTable; | |
| RSDT_TABLE *Rsdt; | |
| XSDT_TABLE *Xsdt; | |
| AcpiTable = NULL; | |
| // | |
| // Check ACPI2.0 table | |
| // | |
| Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress; | |
| Xsdt = NULL; | |
| if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) { | |
| Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress; | |
| } | |
| // | |
| // Check Xsdt | |
| // | |
| if (Xsdt != NULL) { | |
| AcpiTable = ScanTableInXSDT (Xsdt, Signature); | |
| } | |
| // | |
| // Check Rsdt | |
| // | |
| if ((AcpiTable == NULL) && (Rsdt != NULL)) { | |
| AcpiTable = ScanTableInRSDT (Rsdt, Signature); | |
| } | |
| return AcpiTable; | |
| } | |
| /** | |
| Get the DMAR ACPI table. | |
| @retval EFI_SUCCESS The DMAR ACPI table is got. | |
| @retval EFI_ALREADY_STARTED The DMAR ACPI table has been got previously. | |
| @retval EFI_NOT_FOUND The DMAR ACPI table is not found. | |
| **/ | |
| EFI_STATUS | |
| GetDmarAcpiTable ( | |
| VOID | |
| ) | |
| { | |
| VOID *AcpiTable; | |
| EFI_STATUS Status; | |
| if (mAcpiDmarTable != NULL) { | |
| return EFI_ALREADY_STARTED; | |
| } | |
| AcpiTable = NULL; | |
| Status = EfiGetSystemConfigurationTable ( | |
| &gEfiAcpi20TableGuid, | |
| &AcpiTable | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| Status = EfiGetSystemConfigurationTable ( | |
| &gEfiAcpi10TableGuid, | |
| &AcpiTable | |
| ); | |
| } | |
| if (EFI_ERROR (Status)) { | |
| return EFI_NOT_FOUND; | |
| } | |
| ASSERT (AcpiTable != NULL); | |
| mAcpiDmarTable = FindAcpiPtr ( | |
| (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable, | |
| EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE | |
| ); | |
| if (mAcpiDmarTable == NULL) { | |
| return EFI_NOT_FOUND; | |
| } | |
| DEBUG ((DEBUG_INFO,"DMAR Table - 0x%08x\n", mAcpiDmarTable)); | |
| VtdDumpDmarTable(); | |
| return EFI_SUCCESS; | |
| } |