/** @file Source code file for Intel VTd PEI DXE library. Copyright (c) 2023, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include // // Define the maximum message length that this library supports // #define MAX_STRING_LENGTH (0x100) #define VTD_64BITS_ADDRESS(Lo, Hi) (LShiftU64 (Lo, 12) | LShiftU64 (Hi, 32)) /** Produces a Null-terminated ASCII string in an output buffer based on a Null-terminated ASCII format string and variable argument list. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] ErrorLevel The error level of the debug message. @param[in] FormatString A Null-terminated ASCII format string. @param[in] ... Variable argument list whose contents are accessed based on the format string specified by FormatString. @return The number of ASCII characters in the produced output buffer not including the Null-terminator. **/ UINTN EFIAPI VtdLogEventCallback ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN UINTN ErrorLevel, IN CONST CHAR8 *FormatString, ... ) { CHAR8 Buffer[MAX_STRING_LENGTH]; VA_LIST Marker; UINTN NumberOfPrinted; if ((CallbackHandle == NULL) || (FormatString == NULL)) { return 0; } VA_START (Marker, FormatString); NumberOfPrinted = AsciiVSPrint (Buffer, sizeof (Buffer), FormatString, Marker); VA_END (Marker); if (NumberOfPrinted > 0) { CallbackHandle (Context, ErrorLevel, Buffer); } return NumberOfPrinted; } /** Dump DMAR DeviceScopeEntry. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry **/ VOID VtdLibDumpDmarDeviceScopeEntry ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry ) { UINTN PciPathNumber; UINTN PciPathIndex; EFI_ACPI_DMAR_PCI_PATH *PciPath; if (DmarDeviceScopeEntry == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " *************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * DMA-Remapping Device Scope Entry Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " *************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " DMAR Device Scope Entry address ...................... 0x%016lx\n" : " DMAR Device Scope Entry address ...................... 0x%08x\n", DmarDeviceScopeEntry )); VTDLIB_DEBUG ((DEBUG_INFO, " Device Scope Entry Type ............................ 0x%02x\n", DmarDeviceScopeEntry->Type )); switch (DmarDeviceScopeEntry->Type) { case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT: VTDLIB_DEBUG ((DEBUG_INFO, " PCI Endpoint Device\n" )); break; case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE: VTDLIB_DEBUG ((DEBUG_INFO, " PCI Sub-hierachy\n" )); break; case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_IOAPIC: VTDLIB_DEBUG ((DEBUG_INFO, " IOAPIC\n" )); break; case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_MSI_CAPABLE_HPET: VTDLIB_DEBUG ((DEBUG_INFO, " MSI Capable HPET\n" )); break; case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_ACPI_NAMESPACE_DEVICE: VTDLIB_DEBUG ((DEBUG_INFO, " ACPI Namespace Device\n" )); break; default: break; } VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................. 0x%02x\n", DmarDeviceScopeEntry->Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Flags .............................................. 0x%02x\n", DmarDeviceScopeEntry->Flags )); VTDLIB_DEBUG ((DEBUG_INFO, " Enumeration ID ..................................... 0x%02x\n", DmarDeviceScopeEntry->EnumerationId )); VTDLIB_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++) { VTDLIB_DEBUG ((DEBUG_INFO, " Device ............................................. 0x%02x\n", PciPath[PciPathIndex].Device )); VTDLIB_DEBUG ((DEBUG_INFO, " Function ........................................... 0x%02x\n", PciPath[PciPathIndex].Function )); } VTDLIB_DEBUG ((DEBUG_INFO, " *************************************************************************\n\n" )); } /** Dump DMAR SIDP table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Sidp DMAR SIDP table **/ VOID VtdLibDumpDmarSidp ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_SIDP_HEADER *Sidp ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; INTN SidpLen; if (Sidp == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * SoC Integrated Device Property Reporting Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " SIDP address ........................................... 0x%016lx\n" : " SIDP address ........................................... 0x%08x\n", Sidp )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Sidp->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Sidp->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Segment Number ....................................... 0x%04x\n", Sidp->SegmentNumber )); SidpLen = Sidp->Header.Length - sizeof(EFI_ACPI_DMAR_SIDP_HEADER); DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Sidp + 1); while (SidpLen > 0) { VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceScopeEntry); SidpLen -= DmarDeviceScopeEntry->Length; DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR SATC table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Satc DMAR SATC table **/ VOID VtdLibDumpDmarSatc ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_SATC_HEADER *Satc ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; INTN SatcLen; if (Satc == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * ACPI Soc Integrated Address Translation Cache reporting Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " SATC address ........................................... 0x%016lx\n" : " SATC address ........................................... 0x%08x\n", Satc )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Satc->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Satc->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Flags ................................................ 0x%02x\n", Satc->Flags )); VTDLIB_DEBUG ((DEBUG_INFO, " Segment Number ....................................... 0x%04x\n", Satc->SegmentNumber )); SatcLen = Satc->Header.Length - sizeof(EFI_ACPI_DMAR_SATC_HEADER); DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Satc + 1); while (SatcLen > 0) { VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceScopeEntry); SatcLen -= DmarDeviceScopeEntry->Length; DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR ANDD table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Andd DMAR ANDD table **/ VOID VtdLibDumpDmarAndd ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_ANDD_HEADER *Andd ) { if (Andd == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * ACPI Name-space Device Declaration Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " ANDD address ........................................... 0x%016lx\n" : " ANDD address ........................................... 0x%08x\n", Andd )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Andd->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Andd->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " ACPI Device Number ................................... 0x%02x\n", Andd->AcpiDeviceNumber )); VTDLIB_DEBUG ((DEBUG_INFO, " ACPI Object Name ..................................... '%a'\n", (Andd + 1) )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR RHSA table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Rhsa DMAR RHSA table **/ VOID VtdLibDumpDmarRhsa ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_RHSA_HEADER *Rhsa ) { if (Rhsa == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * Remapping Hardware Status Affinity Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " RHSA address ........................................... 0x%016lx\n" : " RHSA address ........................................... 0x%08x\n", Rhsa )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Rhsa->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Rhsa->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Register Base Address ................................ 0x%016lx\n", Rhsa->RegisterBaseAddress )); VTDLIB_DEBUG ((DEBUG_INFO, " Proximity Domain ..................................... 0x%08x\n", Rhsa->ProximityDomain )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR ATSR table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Atsr DMAR ATSR table **/ VOID VtdLibDumpDmarAtsr ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_ATSR_HEADER *Atsr ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; INTN AtsrLen; if (Atsr == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * Root Port ATS Capability Reporting Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " ATSR address ........................................... 0x%016lx\n" : " ATSR address ........................................... 0x%08x\n", Atsr )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Atsr->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Atsr->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Flags ................................................ 0x%02x\n", Atsr->Flags )); VTDLIB_DEBUG ((DEBUG_INFO, " ALL_PORTS .......................................... 0x%02x\n", Atsr->Flags & EFI_ACPI_DMAR_ATSR_FLAGS_ALL_PORTS )); VTDLIB_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) { VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceScopeEntry); AtsrLen -= DmarDeviceScopeEntry->Length; DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR RMRR table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Rmrr DMAR RMRR table **/ VOID VtdLibDumpDmarRmrr ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; INTN RmrrLen; if (Rmrr == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * Reserved Memory Region Reporting Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " RMRR address ........................................... 0x%016lx\n" : " RMRR address ........................................... 0x%08x\n", Rmrr )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Rmrr->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Rmrr->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Segment Number ....................................... 0x%04x\n", Rmrr->SegmentNumber )); VTDLIB_DEBUG ((DEBUG_INFO, " Reserved Memory Region Base Address .................. 0x%016lx\n", Rmrr->ReservedMemoryRegionBaseAddress )); VTDLIB_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) { VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceScopeEntry); RmrrLen -= DmarDeviceScopeEntry->Length; DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump DMAR DRHD table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Drhd DMAR DRHD table **/ VOID VtdLibDumpDmarDrhd ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry; INTN DrhdLen; if (Drhd == NULL) { return; } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " * DMA-Remapping Hardware Definition Structure *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? " DRHD address ........................................... 0x%016lx\n" : " DRHD address ........................................... 0x%08x\n", Drhd )); VTDLIB_DEBUG ((DEBUG_INFO, " Type ................................................. 0x%04x\n", Drhd->Header.Type )); VTDLIB_DEBUG ((DEBUG_INFO, " Length ............................................... 0x%04x\n", Drhd->Header.Length )); VTDLIB_DEBUG ((DEBUG_INFO, " Flags ................................................ 0x%02x\n", Drhd->Flags )); VTDLIB_DEBUG ((DEBUG_INFO, " INCLUDE_PCI_ALL .................................... 0x%02x\n", Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL )); VTDLIB_DEBUG ((DEBUG_INFO, " Size ................................................. 0x%02x\n", Drhd->Size )); VTDLIB_DEBUG ((DEBUG_INFO, " Segment Number ....................................... 0x%04x\n", Drhd->SegmentNumber )); VTDLIB_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) { VtdLibDumpDmarDeviceScopeEntry (Context, CallbackHandle, DmarDeviceScopeEntry); DrhdLen -= DmarDeviceScopeEntry->Length; DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length); } VTDLIB_DEBUG ((DEBUG_INFO, " ***************************************************************************\n\n" )); } /** Dump Header of DMAR ACPI table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Dmar DMAR ACPI table **/ VOID VtdLibDumpAcpiDmarHeader ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_HEADER *Dmar ) { // // Dump Dmar table // VTDLIB_DEBUG ((DEBUG_INFO, "*****************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, "* DMAR Table *\n" )); VTDLIB_DEBUG ((DEBUG_INFO, "*****************************************************************************\n" )); VTDLIB_DEBUG ((DEBUG_INFO, (sizeof(UINTN) == sizeof(UINT64)) ? "DMAR address ............................................. 0x%016lx\n" : "DMAR address ............................................. 0x%08x\n", Dmar )); VTDLIB_DEBUG ((DEBUG_INFO, " Table Contents:\n" )); VTDLIB_DEBUG ((DEBUG_INFO, " Host Address Width ................................... 0x%02x\n", Dmar->HostAddressWidth )); VTDLIB_DEBUG ((DEBUG_INFO, " Flags ................................................ 0x%02x\n", Dmar->Flags )); VTDLIB_DEBUG ((DEBUG_INFO, " INTR_REMAP ......................................... 0x%02x\n", Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP )); VTDLIB_DEBUG ((DEBUG_INFO, " X2APIC_OPT_OUT_SET ................................. 0x%02x\n", Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT )); VTDLIB_DEBUG ((DEBUG_INFO, " DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n", Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG )); } /** Dump DMAR ACPI table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Dmar DMAR ACPI table **/ VOID VtdLibDumpAcpiDmar ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_HEADER *Dmar ) { EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; INTN DmarLen; if (Dmar == NULL) { return; } // // Dump Dmar table // VtdLibDumpAcpiDmarHeader (Context, CallbackHandle, Dmar); 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: VtdLibDumpDmarDrhd (Context, CallbackHandle, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_RMRR: VtdLibDumpDmarRmrr (Context, CallbackHandle, (EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_ATSR: VtdLibDumpDmarAtsr (Context, CallbackHandle, (EFI_ACPI_DMAR_ATSR_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_RHSA: VtdLibDumpDmarRhsa (Context, CallbackHandle, (EFI_ACPI_DMAR_RHSA_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_ANDD: VtdLibDumpDmarAndd (Context, CallbackHandle, (EFI_ACPI_DMAR_ANDD_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_SATC: VtdLibDumpDmarSatc (Context, CallbackHandle, (EFI_ACPI_DMAR_SATC_HEADER *)DmarHeader); break; case EFI_ACPI_DMAR_TYPE_SIDP: VtdLibDumpDmarSidp (Context, CallbackHandle, (EFI_ACPI_DMAR_SIDP_HEADER *)DmarHeader); break; default: break; } DmarLen -= DmarHeader->Length; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); } VTDLIB_DEBUG ((DEBUG_INFO, "*****************************************************************************\n\n" )); } /** Dump DRHD DMAR ACPI table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Dmar DMAR ACPI table **/ VOID VtdLibDumpAcpiDmarDrhd ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN EFI_ACPI_DMAR_HEADER *Dmar ) { EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; INTN DmarLen; if (Dmar == NULL) { return; } // // Dump Dmar table // VtdLibDumpAcpiDmarHeader (Context, CallbackHandle, Dmar); 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: VtdLibDumpDmarDrhd (Context, CallbackHandle, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader); break; default: break; } DmarLen -= DmarHeader->Length; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length); } VTDLIB_DEBUG ((DEBUG_INFO, "*****************************************************************************\n\n" )); } /** Dump the PCI device information managed by this VTd engine. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] PciDeviceInfo VTd Unit Information **/ VOID VtdLibDumpPciDeviceInfo ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN PCI_DEVICE_INFORMATION *PciDeviceInfo ) { UINTN Index; if (PciDeviceInfo != NULL) { VTDLIB_DEBUG ((DEBUG_INFO, "PCI Device Information (Number 0x%x, IncludeAll - %d):\n", PciDeviceInfo->PciDeviceDataNumber, PciDeviceInfo->IncludeAllFlag )); for (Index = 0; Index < PciDeviceInfo->PciDeviceDataNumber; Index++) { VTDLIB_DEBUG ((DEBUG_INFO, " S%04x B%02x D%02x F%02x\n", PciDeviceInfo->Segment, PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Bus, PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Device, PciDeviceInfo->PciDeviceData[Index].PciSourceId.Bits.Function )); } } } /** Dump DMAR second level paging entry. @param[in] Context Event context @param[in] CallbackHandle Callback handler @param[in] SecondLevelPagingEntry The second level paging entry. @param[in] Is5LevelPaging If it is the 5 level paging. **/ VOID VtdLibDumpSecondLevelPagingEntry ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VOID *SecondLevelPagingEntry, IN BOOLEAN Is5LevelPaging ) { UINTN Index5; UINTN Index4; UINTN Index3; UINTN Index2; UINTN Index1; UINTN Lvl5IndexEnd; VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl5PtEntry; VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl4PtEntry; VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl3PtEntry; VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl2PtEntry; VTD_SECOND_LEVEL_PAGING_ENTRY *Lvl1PtEntry; VTDLIB_DEBUG ((DEBUG_VERBOSE, "================\n")); VTDLIB_DEBUG ((DEBUG_VERBOSE, "DMAR Second Level Page Table:\n")); VTDLIB_DEBUG ((DEBUG_VERBOSE, "SecondLevelPagingEntry Base - 0x%x, Is5LevelPaging - %d\n", SecondLevelPagingEntry, Is5LevelPaging)); Lvl5IndexEnd = Is5LevelPaging ? SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY) : 1; Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry; Lvl5PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)SecondLevelPagingEntry; for (Index5 = 0; Index5 < Lvl5IndexEnd; Index5++) { if (Is5LevelPaging) { if (Lvl5PtEntry[Index5].Uint64 != 0) { VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl5Pt Entry(0x%03x) - 0x%016lx\n", Index5, Lvl5PtEntry[Index5].Uint64)); } if (Lvl5PtEntry[Index5].Uint64 == 0) { continue; } Lvl4PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl5PtEntry[Index5].Bits.AddressLo, Lvl5PtEntry[Index5].Bits.AddressHi); } for (Index4 = 0; Index4 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index4++) { if (Lvl4PtEntry[Index4].Uint64 != 0) { VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl4Pt Entry(0x%03x) - 0x%016lx\n", Index4, Lvl4PtEntry[Index4].Uint64)); } if (Lvl4PtEntry[Index4].Uint64 == 0) { continue; } Lvl3PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl4PtEntry[Index4].Bits.AddressLo, Lvl4PtEntry[Index4].Bits.AddressHi); for (Index3 = 0; Index3 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index3++) { if (Lvl3PtEntry[Index3].Uint64 != 0) { VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl3Pt Entry(0x%03x) - 0x%016lx\n", Index3, Lvl3PtEntry[Index3].Uint64)); } if (Lvl3PtEntry[Index3].Uint64 == 0) { continue; } Lvl2PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl3PtEntry[Index3].Bits.AddressLo, Lvl3PtEntry[Index3].Bits.AddressHi); for (Index2 = 0; Index2 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index2++) { if (Lvl2PtEntry[Index2].Uint64 != 0) { VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl2Pt Entry(0x%03x) - 0x%016lx\n", Index2, Lvl2PtEntry[Index2].Uint64)); } if (Lvl2PtEntry[Index2].Uint64 == 0) { continue; } if (Lvl2PtEntry[Index2].Bits.PageSize == 0) { Lvl1PtEntry = (VTD_SECOND_LEVEL_PAGING_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(Lvl2PtEntry[Index2].Bits.AddressLo, Lvl2PtEntry[Index2].Bits.AddressHi); for (Index1 = 0; Index1 < SIZE_4KB/sizeof(VTD_SECOND_LEVEL_PAGING_ENTRY); Index1++) { if (Lvl1PtEntry[Index1].Uint64 != 0) { VTDLIB_DEBUG ((DEBUG_VERBOSE, " Lvl1Pt Entry(0x%03x) - 0x%016lx\n", Index1, Lvl1PtEntry[Index1].Uint64)); } } } } } } } VTDLIB_DEBUG ((DEBUG_VERBOSE, "================\n")); } /** Dump DMAR context entry table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] RootEntry DMAR root entry. @param[in] Is5LevelPaging If it is the 5 level paging. **/ VOID VtdLibDumpDmarContextEntryTable ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTD_ROOT_ENTRY *RootEntry, IN BOOLEAN Is5LevelPaging ) { UINTN Index; UINTN Index2; VTD_CONTEXT_ENTRY *ContextEntry; VTDLIB_DEBUG ((DEBUG_INFO, "=========================\n")); VTDLIB_DEBUG ((DEBUG_INFO, "DMAR Context Entry Table:\n")); VTDLIB_DEBUG ((DEBUG_INFO, "RootEntry Address - 0x%x\n", RootEntry)); for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) { if ((RootEntry[Index].Uint128.Uint64Lo != 0) || (RootEntry[Index].Uint128.Uint64Hi != 0)) { VTDLIB_DEBUG ((DEBUG_INFO, " RootEntry(0x%02x) B%02x - 0x%016lx %016lx\n", Index, Index, RootEntry[Index].Uint128.Uint64Hi, RootEntry[Index].Uint128.Uint64Lo)); } if (RootEntry[Index].Bits.Present == 0) { continue; } ContextEntry = (VTD_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRESS (RootEntry[Index].Bits.ContextTablePointerLo, RootEntry[Index].Bits.ContextTablePointerHi); for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER; Index2++) { if ((ContextEntry[Index2].Uint128.Uint64Lo != 0) || (ContextEntry[Index2].Uint128.Uint64Hi != 0)) { VTDLIB_DEBUG ((DEBUG_INFO, " ContextEntry(0x%02x) D%02xF%02x - 0x%016lx %016lx\n", Index2, Index2 >> 3, Index2 & 0x7, ContextEntry[Index2].Uint128.Uint64Hi, ContextEntry[Index2].Uint128.Uint64Lo)); } if (ContextEntry[Index2].Bits.Present == 0) { continue; } VtdLibDumpSecondLevelPagingEntry (Context, CallbackHandle, (VOID *) (UINTN) VTD_64BITS_ADDRESS (ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi), Is5LevelPaging); } } VTDLIB_DEBUG ((DEBUG_INFO, "=========================\n")); } /** Dump DMAR extended context entry table. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] ExtRootEntry DMAR extended root entry. @param[in] Is5LevelPaging If it is the 5 level paging. **/ VOID VtdLibDumpDmarExtContextEntryTable ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTD_EXT_ROOT_ENTRY *ExtRootEntry, IN BOOLEAN Is5LevelPaging ) { UINTN Index; UINTN Index2; VTD_EXT_CONTEXT_ENTRY *ExtContextEntry; VTDLIB_DEBUG ((DEBUG_INFO, "=========================\n")); VTDLIB_DEBUG ((DEBUG_INFO, "DMAR ExtContext Entry Table:\n")); VTDLIB_DEBUG ((DEBUG_INFO, "ExtRootEntry Address - 0x%x\n", ExtRootEntry)); for (Index = 0; Index < VTD_ROOT_ENTRY_NUMBER; Index++) { if ((ExtRootEntry[Index].Uint128.Uint64Lo != 0) || (ExtRootEntry[Index].Uint128.Uint64Hi != 0)) { VTDLIB_DEBUG ((DEBUG_INFO, " ExtRootEntry(0x%02x) B%02x - 0x%016lx %016lx\n", Index, Index, ExtRootEntry[Index].Uint128.Uint64Hi, ExtRootEntry[Index].Uint128.Uint64Lo)); } if (ExtRootEntry[Index].Bits.LowerPresent == 0) { continue; } ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRESS (ExtRootEntry[Index].Bits.LowerContextTablePointerLo, ExtRootEntry[Index].Bits.LowerContextTablePointerHi); for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) { if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) { VTDLIB_DEBUG ((DEBUG_INFO, " ExtContextEntryLower(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n", Index2, Index2 >> 3, Index2 & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1)); } if (ExtContextEntry[Index2].Bits.Present == 0) { continue; } VtdLibDumpSecondLevelPagingEntry (Context, CallbackHandle, (VOID *) (UINTN) VTD_64BITS_ADDRESS (ExtContextEntry[Index2].Bits.SecondLevelPageTranslationPointerLo, ExtContextEntry[Index2].Bits.SecondLevelPageTranslationPointerHi), Is5LevelPaging); } if (ExtRootEntry[Index].Bits.UpperPresent == 0) { continue; } ExtContextEntry = (VTD_EXT_CONTEXT_ENTRY *) (UINTN) VTD_64BITS_ADDRESS (ExtRootEntry[Index].Bits.UpperContextTablePointerLo, ExtRootEntry[Index].Bits.UpperContextTablePointerHi); for (Index2 = 0; Index2 < VTD_CONTEXT_ENTRY_NUMBER/2; Index2++) { if ((ExtContextEntry[Index2].Uint256.Uint64_1 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_2 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_3 != 0) || (ExtContextEntry[Index2].Uint256.Uint64_4 != 0)) { VTDLIB_DEBUG ((DEBUG_INFO, " ExtContextEntryUpper(0x%02x) D%02xF%02x - 0x%016lx %016lx %016lx %016lx\n", Index2, (Index2 + 128) >> 3, (Index2 + 128) & 0x7, ExtContextEntry[Index2].Uint256.Uint64_4, ExtContextEntry[Index2].Uint256.Uint64_3, ExtContextEntry[Index2].Uint256.Uint64_2, ExtContextEntry[Index2].Uint256.Uint64_1)); } if (ExtContextEntry[Index2].Bits.Present == 0) { continue; } } } VTDLIB_DEBUG ((DEBUG_INFO, "=========================\n")); } /** Dump VTd FRCD register. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] FrcdRegNum FRCD Register Number @param[in] FrcdRegTab FRCD Register Table **/ VOID VtdLibDumpVtdFrcdRegs ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN UINT16 FrcdRegNum, IN VTD_UINT128 *FrcdRegTab ) { UINT16 Index; VTD_FRCD_REG FrcdReg; VTD_SOURCE_ID SourceId; for (Index = 0; Index < FrcdRegNum; Index++) { FrcdReg.Uint64[0] = FrcdRegTab[Index].Uint64Lo; FrcdReg.Uint64[1] = FrcdRegTab[Index].Uint64Hi; VTDLIB_DEBUG ((DEBUG_INFO, " FRCD_REG[%d] - 0x%016lx %016lx\n", Index, FrcdReg.Uint64[1], FrcdReg.Uint64[0])); if (FrcdReg.Uint64[1] != 0 || FrcdReg.Uint64[0] != 0) { VTDLIB_DEBUG ((DEBUG_INFO, " Fault Info - 0x%016lx\n", VTD_64BITS_ADDRESS(FrcdReg.Bits.FILo, FrcdReg.Bits.FIHi))); VTDLIB_DEBUG ((DEBUG_INFO, " Fault Bit - %d\n", FrcdReg.Bits.F)); SourceId.Uint16 = (UINT16)FrcdReg.Bits.SID; VTDLIB_DEBUG ((DEBUG_INFO, " Source - B%02x D%02x F%02x\n", SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function)); VTDLIB_DEBUG ((DEBUG_INFO, " Type - 0x%02x\n", (FrcdReg.Bits.T1 << 1) | FrcdReg.Bits.T2)); VTDLIB_DEBUG ((DEBUG_INFO, " Reason - %x (Refer to VTd Spec, Appendix A)\n", FrcdReg.Bits.FR)); } } } /** Dump VTd registers. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] VtdRegInfo Registers information **/ VOID VtdLibDumpVtdRegsAll ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTD_REGESTER_INFO *VtdRegInfo ) { if (VtdRegInfo != NULL) { VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->BaseAddress)); VTDLIB_DEBUG ((DEBUG_INFO, " VER_REG - 0x%08x\n", VtdRegInfo->VerReg)); VTDLIB_DEBUG ((DEBUG_INFO, " CAP_REG - 0x%016lx\n", VtdRegInfo->CapReg)); VTDLIB_DEBUG ((DEBUG_INFO, " ECAP_REG - 0x%016lx\n", VtdRegInfo->EcapReg)); VTDLIB_DEBUG ((DEBUG_INFO, " GSTS_REG - 0x%08x \n", VtdRegInfo->GstsReg)); VTDLIB_DEBUG ((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", VtdRegInfo->RtaddrReg)); VTDLIB_DEBUG ((DEBUG_INFO, " CCMD_REG - 0x%016lx\n", VtdRegInfo->CcmdReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->FstsReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FECTL_REG - 0x%08x\n", VtdRegInfo->FectlReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FEDATA_REG - 0x%08x\n", VtdRegInfo->FedataReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FEADDR_REG - 0x%08x\n", VtdRegInfo->FeaddrReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FEUADDR_REG - 0x%08x\n", VtdRegInfo->FeuaddrReg)); VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->IqercdReg)); VtdLibDumpVtdFrcdRegs (Context, CallbackHandle, VtdRegInfo->FrcdRegNum, VtdRegInfo->FrcdReg); VTDLIB_DEBUG ((DEBUG_INFO, " IVA_REG - 0x%016lx\n", VtdRegInfo->IvaReg)); VTDLIB_DEBUG ((DEBUG_INFO, " IOTLB_REG - 0x%016lx\n", VtdRegInfo->IotlbReg)); } } /** Dump VTd registers. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] VtdRegInfo Registers information **/ VOID VtdLibDumpVtdRegsThin ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTD_REGESTER_THIN_INFO *VtdRegInfo ) { if (VtdRegInfo != NULL) { VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->BaseAddress)); VTDLIB_DEBUG ((DEBUG_INFO, " GSTS_REG - 0x%08x \n", VtdRegInfo->GstsReg)); VTDLIB_DEBUG ((DEBUG_INFO, " RTADDR_REG - 0x%016lx\n", VtdRegInfo->RtaddrReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->FstsReg)); VTDLIB_DEBUG ((DEBUG_INFO, " FECTL_REG - 0x%08x\n", VtdRegInfo->FectlReg)); VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->IqercdReg)); VtdLibDumpVtdFrcdRegs (Context, CallbackHandle, VtdRegInfo->FrcdRegNum, VtdRegInfo->FrcdReg); } } /** Dump VTd registers. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] VtdRegInfo Registers information **/ VOID VtdLibDumpVtdRegsQi ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTD_REGESTER_QI_INFO *VtdRegInfo ) { if (VtdRegInfo != NULL) { VTDLIB_DEBUG ((DEBUG_INFO, "VTd Engine: [0x%016lx]\n", VtdRegInfo->BaseAddress)); VTDLIB_DEBUG ((DEBUG_INFO, " FSTS_REG - 0x%08x\n", VtdRegInfo->FstsReg)); VTDLIB_DEBUG ((DEBUG_INFO, " IQERCD_REG - 0x%016lx\n", VtdRegInfo->IqercdReg)); } } /** Dump Vtd PEI pre-mem event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_2PARAM event **/ VOID VtdLibDumpPeiPreMemInfo ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_2PARAM *Event ) { UINT64 VtdBarAddress; UINT64 Mode; UINT64 Status; VtdBarAddress = Event->Data1; Mode = Event->Data2 & 0xFF; Status = (Event->Data2>>8) & 0xFF; switch (Mode) { case VTD_LOG_PEI_PRE_MEM_DISABLE: VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Disabled [0x%016lx] 0x%x\n", VtdBarAddress, Status)); break; case VTD_LOG_PEI_PRE_MEM_ADM: VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable Abort DMA Mode [0x%016lx] 0x%x\n", VtdBarAddress, Status)); break; case VTD_LOG_PEI_PRE_MEM_TE: VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable NULL Root Entry Table [0x%016lx] 0x%x\n", VtdBarAddress, Status)); break; case VTD_LOG_PEI_PRE_MEM_PMR: VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Enable PMR [0x%016lx] 0x%x\n", VtdBarAddress, Status)); break; case VTD_LOG_PEI_PRE_MEM_NOT_USED: // // Not used // break; default: VTDLIB_DEBUG ((DEBUG_INFO, "PEI (pre-memory): Unknown [0x%016lx] 0x%x\n", VtdBarAddress, Status)); break; } } /** Dump Vtd Queued Invaildation event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_2PARAM event **/ VOID VtdLibDumpQueuedInvaildation ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_2PARAM *Event ) { switch (Event->Data1) { case VTD_LOG_QI_DISABLE: VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] Disable\n", Event->Data2)); break; case VTD_LOG_QI_ENABLE: VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] Enable\n", Event->Data2)); break; case VTD_LOG_QI_ERROR_OUT_OF_RESOURCES: VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] error - Out of resources\n", Event->Data2)); break; default: VTDLIB_DEBUG ((DEBUG_INFO, " [0x%016lx] error - (0x%x)\n", Event->Data2, Event->Data1)); break; } } /** Dump Vtd registers event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_CONTEXT event **/ VOID VtdLibDumpRegisters ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_CONTEXT *Event ) { switch (Event->Param) { case VTDLOG_REGISTER_ALL: VtdLibDumpVtdRegsAll (Context, CallbackHandle, (VTD_REGESTER_INFO *) Event->Data); break; case VTDLOG_REGISTER_THIN: VtdLibDumpVtdRegsThin (Context, CallbackHandle, (VTD_REGESTER_THIN_INFO *) Event->Data); break; case VTDLOG_REGISTER_QI: VtdLibDumpVtdRegsQi (Context, CallbackHandle, (VTD_REGESTER_QI_INFO *) Event->Data); break; default: VTDLIB_DEBUG ((DEBUG_INFO, " Unknown format (%d)\n", Event->Param)); break; } } /** Dump Vtd PEI Error event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_2PARAM event **/ VOID VtdLibDumpPeiError ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_2PARAM *Event ) { UINT64 Timestamp; Timestamp = Event->Header.Timestamp; switch (Event->Data1) { case VTD_LOG_PEI_VTD_ERROR_PPI_ALLOC: VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - PPI alloc length [0x%016lx]\n", Timestamp, Event->Data2)); break; case VTD_LOG_PEI_VTD_ERROR_PPI_MAP: VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - PPI map length [0x%016lx]\n", Timestamp, Event->Data2)); break; default: VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Error - Unknown (%d) 0x%x\n", Timestamp, Event->Data1, Event->Data2)); break; } } /** Dump Vtd registers event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_CONTEXT event **/ VOID VtdLibDumpSetAttribute ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_CONTEXT *Event ) { VTD_PROTOCOL_SET_ATTRIBUTE * SetAttributeInfo; SetAttributeInfo = (VTD_PROTOCOL_SET_ATTRIBUTE *) Event->Data; VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: SetAttribute SourceId = 0x%04x, Address = 0x%lx, Length = 0x%lx, IoMmuAccess = 0x%lx, %r\n", Event->Header.Timestamp, SetAttributeInfo->SourceId.Uint16, SetAttributeInfo->DeviceAddress, SetAttributeInfo->Length, SetAttributeInfo->IoMmuAccess, SetAttributeInfo->Status)); } /** Dump Vtd Root Table event. @param[in] Context Event context @param[in out] CallbackHandle Callback handler @param[in] Event VTDLOG_EVENT_CONTEXT event **/ VOID VtdLibDumpRootTable ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT_CONTEXT *Event ) { VTD_ROOT_TABLE_INFO *RootTableInfo; RootTableInfo = (VTD_ROOT_TABLE_INFO *) Event->Data; if (Event->Param == 0) { VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Root Entry Table [0x%016lx]\n", Event->Header.Timestamp, RootTableInfo->BaseAddress)); VtdLibDumpDmarContextEntryTable (Context, CallbackHandle, (VTD_ROOT_ENTRY *) (UINTN) RootTableInfo->TableAddress, RootTableInfo->Is5LevelPaging); } else if (Event->Param == 1) { VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Ext Root Entry Table [0x%016lx]\n", Event->Header.Timestamp, RootTableInfo->BaseAddress)); VtdLibDumpDmarExtContextEntryTable (Context, CallbackHandle, (VTD_EXT_ROOT_ENTRY *) (UINTN) RootTableInfo->TableAddress, RootTableInfo->Is5LevelPaging); } else { VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Unknown Root Table Type (%d)\n", Event->Header.Timestamp, Event->Param)); } } /** Decode log event. @param[in] Context Event context @param[in out] PciDeviceId Callback handler @param[in] Event Event struct @retval TRUE Decode event success @retval FALSE Unknown event **/ BOOLEAN VtdLibDecodeEvent ( IN VOID *Context, IN OUT EDKII_VTD_LIB_STRING_CB CallbackHandle, IN VTDLOG_EVENT *Event ) { BOOLEAN Result; UINT64 Timestamp; UINT64 Data1; UINT64 Data2; Result = TRUE; Timestamp = Event->EventHeader.Timestamp; Data1 = Event->CommenEvent.Data1; Data2 = Event->CommenEvent.Data2; switch (Event->EventHeader.LogType) { case VTDLOG_LOG_TYPE (VTDLOG_PEI_BASIC): if (Data1 & VTD_LOG_ERROR_BUFFER_FULL) { VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Info : Log Buffer Full\n", Timestamp)); Data1 &= ~VTD_LOG_ERROR_BUFFER_FULL; } if (Data1 != 0) { VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Info : 0x%x, 0x%x\n", Timestamp, Data1, Data2)); } break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PRE_MEM_DMA_PROTECT): VtdLibDumpPeiPreMemInfo (Context, CallbackHandle, &(Event->CommenEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PMR_LOW_MEMORY_RANGE): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PMR Low Memory Range [0x%x, 0x%x]\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PMR_HIGH_MEMORY_RANGE): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PMR High Memory Range [0x%016lx, 0x%016lx]\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PROTECT_MEMORY_RANGE): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Protected DMA Memory Range [0x%016lx, 0x%016lx]\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_POST_MEM_ENABLE_DMA_PROTECT): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Enable DMA protection [0x%016lx] %r\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_POST_MEM_DISABLE_DMA_PROTECT): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Disable DMA protection [0x%016lx]\n", Timestamp, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_QUEUED_INVALIDATION): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Queued Invalidation", Timestamp)); VtdLibDumpQueuedInvaildation (Context, CallbackHandle, &(Event->CommenEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_REGISTER): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: Dump Registers\n", Timestamp)); VtdLibDumpRegisters (Context, CallbackHandle, &(Event->ContextEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_VTD_ERROR): VtdLibDumpPeiError (Context, CallbackHandle, &(Event->CommenEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PPI_ALLOC_BUFFER): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PPI AllocateBuffer 0x%x, Length = 0x%x\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_PEI_PPI_MAP): VTDLIB_DEBUG ((DEBUG_INFO, "PEI [%ld]: PPI Map 0x%x, Length = 0x%x\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_BASIC): if (Data1 & VTD_LOG_ERROR_BUFFER_FULL) { VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Info : Log Buffer Full\n", Timestamp)); Data1 &= ~VTD_LOG_ERROR_BUFFER_FULL; } if (Data1 != 0) { VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Info : 0x%x, 0x%x\n", Timestamp, Data1, Data2)); } break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_DMAR_TABLE): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: DMAR Table\n", Timestamp)); VtdLibDumpAcpiDmar (Context, CallbackHandle, (EFI_ACPI_DMAR_HEADER *) Event->ContextEvent.Data); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_SETUP_VTD): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Setup VTd Below/Above 4G Memory Limit = [0x%016lx, 0x%016lx]\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_PCI_DEVICE): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: PCI Devices [0x%016lx]\n", Timestamp, Event->ContextEvent.Param)); VtdLibDumpPciDeviceInfo (Context, CallbackHandle, (PCI_DEVICE_INFORMATION *) Event->ContextEvent.Data); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_REGISTER): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Dump Registers\n", Timestamp)); VtdLibDumpRegisters (Context, CallbackHandle, &(Event->ContextEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_ENABLE_DMAR): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Enable DMAR [0x%016lx]\n", Timestamp, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_DISABLE_DMAR): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Disable DMAR [0x%016lx]\n", Timestamp, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_DISABLE_PMR): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Disable PMR [0x%016lx] %r\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_INSTALL_IOMMU_PROTOCOL): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Install IOMMU Protocol %r\n", Timestamp, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_QUEUED_INVALIDATION): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Queued Invalidation", Timestamp)); VtdLibDumpQueuedInvaildation (Context, CallbackHandle, &(Event->CommenEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_ROOT_TABLE): VtdLibDumpRootTable (Context, CallbackHandle, &(Event->ContextEvent)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_ALLOC_BUFFER): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: AllocateBuffer 0x%x, Page = 0x%x\n", Timestamp, Data2, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_FREE_BUFFER): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: FreeBuffer 0x%x, Page = 0x%x\n", Timestamp, Data2, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_MAP): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Map 0x%x, Operation = 0x%x\n", Timestamp, Data1, Data2)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_UNMAP): VTDLIB_DEBUG ((DEBUG_INFO, "DXE [%ld]: Unmap 0x%x, NumberOfBytes = 0x%x\n", Timestamp, Data2, Data1)); break; case VTDLOG_LOG_TYPE (VTDLOG_DXE_IOMMU_SET_ATTRIBUTE): VtdLibDumpSetAttribute (Context, CallbackHandle, &(Event->ContextEvent)); break; default: VTDLIB_DEBUG ((DEBUG_INFO, "## Unknown VTd Event Type=%d Timestamp=%ld Size=%d\n", Event->EventHeader.LogType, Event->EventHeader.Timestamp, Event->EventHeader.DataSize)); Result = FALSE; break; } return Result; } /** Flush VTd engine write buffer. @param[in] VtdUnitBaseAddress The base address of the VTd engine. **/ VOID VtdLibFlushWriteBuffer ( IN UINTN VtdUnitBaseAddress ) { UINT32 Reg32; VTD_CAP_REG CapReg; CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); if (CapReg.Bits.RWBF != 0) { Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); Reg32 = (Reg32 & 0x96FFFFFF); // Reset the one-shot bits MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF); do { Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); } while ((Reg32 & B_GSTS_REG_WBF) != 0); } } /** Clear Global Command Register Bits @param[in] VtdUnitBaseAddress The base address of the VTd engine. @param[in] BitMask Bit mask **/ VOID VtdLibClearGlobalCommandRegisterBits ( IN UINTN VtdUnitBaseAddress, IN UINT32 BitMask ) { UINT32 Reg32; UINT32 Status; UINT32 Command; Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); Status = (Reg32 & 0x96FFFFFF); // Reset the one-shot bits Command = (Status & (~BitMask)); MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command); DEBUG ((DEBUG_INFO, "Clear GCMD_REG bits 0x%x.\n", BitMask)); // // Poll on Status bit of Global status register to become zero // do { Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); } while ((Reg32 & BitMask) == BitMask); DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32)); } /** Set Global Command Register Bits @param[in] VtdUnitBaseAddress The base address of the VTd engine. @param[in] BitMask Bit mask **/ VOID VtdLibSetGlobalCommandRegisterBits ( IN UINTN VtdUnitBaseAddress, IN UINT32 BitMask ) { UINT32 Reg32; UINT32 Status; UINT32 Command; Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); Status = (Reg32 & 0x96FFFFFF); // Reset the one-shot bits Command = (Status | BitMask); MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command); DEBUG ((DEBUG_INFO, "Set GCMD_REG bits 0x%x.\n", BitMask)); // // Poll on Status bit of Global status register to become not zero // do { Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); } while ((Reg32 & BitMask) == 0); DEBUG ((DEBUG_INFO, "GSTS_REG : 0x%08x \n", Reg32)); } /** Disable DMAR translation. @param[in] VtdUnitBaseAddress The base address of the VTd engine. @retval EFI_SUCCESS DMAR translation is disabled. **/ EFI_STATUS VtdLibDisableDmar ( IN UINTN VtdUnitBaseAddress ) { UINT32 Reg32; DEBUG ((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x]\n", VtdUnitBaseAddress)); // // Write Buffer Flush before invalidation // VtdLibFlushWriteBuffer (VtdUnitBaseAddress); // // Disable Dmar // // // Set TE (Translation Enable: BIT31) of Global command register to zero // VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_TE); // // Set SRTP (Set Root Table Pointer: BIT30) of Global command register in order to update the root table pointerDisable VTd // VtdLibSetGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_SRTP); Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG); DEBUG ((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32)); MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0); DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n")); return EFI_SUCCESS; } /** Disable PMR. @param[in] VtdUnitBaseAddress The base address of the VTd engine. @retval EFI_SUCCESS PMR is disabled. @retval EFI_UNSUPPORTED PMR is not supported. @retval EFI_NOT_STARTED PMR was not enabled. **/ EFI_STATUS VtdLibDisablePmr ( IN UINTN VtdUnitBaseAddress ) { UINT32 Reg32; VTD_CAP_REG CapReg; EFI_STATUS Status; CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG); if (CapReg.Bits.PLMR == 0 || CapReg.Bits.PHMR == 0) { // // PMR is not supported // return EFI_UNSUPPORTED; } Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); if ((Reg32 & BIT0) != 0) { MmioWrite32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG, 0x0); do { Reg32 = MmioRead32 (VtdUnitBaseAddress + R_PMEN_ENABLE_REG); } while((Reg32 & BIT0) != 0); DEBUG ((DEBUG_INFO,"Pmr [0x%016lx] disabled\n", VtdUnitBaseAddress)); Status = EFI_SUCCESS; } else { DEBUG ((DEBUG_INFO,"Pmr [0x%016lx] not enabled\n", VtdUnitBaseAddress)); Status = EFI_NOT_STARTED; } return Status; } /** Disable queued invalidation interface. @param[in] VtdUnitBaseAddress The base address of the VTd engine. **/ VOID VtdLibDisableQueuedInvalidationInterface ( IN UINTN VtdUnitBaseAddress ) { QI_256_DESC QiDesc; QiDesc.Uint64[0] = QI_IWD_TYPE; QiDesc.Uint64[1] = 0; QiDesc.Uint64[2] = 0; QiDesc.Uint64[3] = 0; VtdLibSubmitQueuedInvalidationDescriptor (VtdUnitBaseAddress, &QiDesc, TRUE); DEBUG ((DEBUG_INFO, "Disable Queued Invalidation Interface. [%x]\n", VtdUnitBaseAddress)); VtdLibClearGlobalCommandRegisterBits (VtdUnitBaseAddress, B_GMCD_REG_QIE); MmioWrite64 (VtdUnitBaseAddress + R_IQA_REG, 0); } /** Submit the queued invalidation descriptor to the remapping hardware unit and wait for its completion. @param[in] VtdUnitBaseAddress The base address of the VTd engine. @param[in] Desc The invalidate descriptor @param[in] ClearFaultBits Clear Error bits @retval EFI_SUCCESS The operation was successful. @retval EFI_INVALID_PARAMETER Parameter is invalid. @retval EFI_NOT_READY Queued invalidation is not inited. @retval EFI_DEVICE_ERROR Detect fault, need to clear fault bits if ClearFaultBits is FALSE **/ EFI_STATUS VtdLibSubmitQueuedInvalidationDescriptor ( IN UINTN VtdUnitBaseAddress, IN VOID *Desc, IN BOOLEAN ClearFaultBits ) { UINTN QueueSize; UINTN QueueTail; UINTN QueueHead; QI_DESC *Qi128Desc; QI_256_DESC *Qi256Desc; VTD_IQA_REG IqaReg; VTD_IQT_REG IqtReg; VTD_IQH_REG IqhReg; UINT32 FaultReg; UINT64 IqercdReg; UINT64 IQBassAddress; if (Desc == NULL) { return EFI_INVALID_PARAMETER; } IqaReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQA_REG); // // Get IQA_REG.IQA (Invalidation Queue Base Address) // IQBassAddress = RShiftU64 (IqaReg.Uint64, 12); if (IQBassAddress == 0) { DEBUG ((DEBUG_ERROR,"Invalidation Queue Buffer not ready [0x%lx]\n", IqaReg.Uint64)); return EFI_NOT_READY; } IqtReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQT_REG); // // Check IQA_REG.DW (Descriptor Width) // if ((IqaReg.Uint64 & BIT11) == 0) { // // 128-bit descriptor // QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 8)); Qi128Desc = (QI_DESC *) (UINTN) LShiftU64 (IQBassAddress, VTD_PAGE_SHIFT); // // Get IQT_REG.QT for 128-bit descriptors // QueueTail = (UINTN) (RShiftU64 (IqtReg.Uint64, 4) & 0x7FFF); Qi128Desc += QueueTail; CopyMem (Qi128Desc, Desc, sizeof (QI_DESC)); QueueTail = (QueueTail + 1) % QueueSize; DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx]\n", VtdUnitBaseAddress, QueueTail, Qi128Desc->Low, Qi128Desc->High)); IqtReg.Uint64 &= ~(0x7FFF << 4); IqtReg.Uint64 |= LShiftU64 (QueueTail, 4); } else { // // 256-bit descriptor // QueueSize = (UINTN) (1 << (IqaReg.Bits.QS + 7)); Qi256Desc = (QI_256_DESC *) (UINTN) LShiftU64 (IQBassAddress, VTD_PAGE_SHIFT); // // Get IQT_REG.QT for 256-bit descriptors // QueueTail = (UINTN) (RShiftU64 (IqtReg.Uint64, 5) & 0x3FFF); Qi256Desc += QueueTail; CopyMem (Qi256Desc, Desc, sizeof (QI_256_DESC)); QueueTail = (QueueTail + 1) % QueueSize; DEBUG ((DEBUG_VERBOSE, "[0x%x] Submit QI Descriptor 0x%x [0x%016lx, 0x%016lx, 0x%016lx, 0x%016lx]\n", VtdUnitBaseAddress, QueueTail, Qi256Desc->Uint64[0], Qi256Desc->Uint64[1], Qi256Desc->Uint64[2], Qi256Desc->Uint64[3])); IqtReg.Uint64 &= ~(0x3FFF << 5); IqtReg.Uint64 |= LShiftU64 (QueueTail, 5); } // // Update the HW tail register indicating the presence of new descriptors. // MmioWrite64 (VtdUnitBaseAddress + R_IQT_REG, IqtReg.Uint64); do { FaultReg = MmioRead32 (VtdUnitBaseAddress + R_FSTS_REG); if (FaultReg & (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE)) { IqercdReg = MmioRead64 (VtdUnitBaseAddress + R_IQERCD_REG); DEBUG((DEBUG_ERROR, "BAR [0x%016lx] Detect Queue Invalidation Fault [0x%08x] - IQERCD [0x%016lx]\n", VtdUnitBaseAddress, FaultReg, IqercdReg)); if (ClearFaultBits) { FaultReg &= (B_FSTS_REG_IQE | B_FSTS_REG_ITE | B_FSTS_REG_ICE); MmioWrite32 (VtdUnitBaseAddress + R_FSTS_REG, FaultReg); } return EFI_DEVICE_ERROR; } IqhReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_IQH_REG); // // Check IQA_REG.DW (Descriptor Width) and get IQH_REG.QH // if ((IqaReg.Uint64 & BIT11) == 0) { QueueHead = (UINTN) (RShiftU64 (IqhReg.Uint64, 4) & 0x7FFF); } else { QueueHead = (UINTN) (RShiftU64 (IqhReg.Uint64, 5) & 0x3FFF); } } while (QueueTail != QueueHead); return EFI_SUCCESS; }