/** @file Copyright (c) 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include "IntelVTdDmarPei.h" /** 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; 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 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 )); DEBUG ((DEBUG_INFO, " DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n", Dmar->Flags & EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG )); 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; default: break; } DmarLen -= DmarHeader->Length; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) DmarHeader + DmarHeader->Length); } DEBUG ((DEBUG_INFO, "*****************************************************************************\n\n" )); return; } /** Get VTd engine number. @param[in] AcpiDmarTable DMAR ACPI table @return the VTd engine number. **/ UINTN GetVtdEngineNumber ( IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable ) { EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; UINTN VtdIndex; VtdIndex = 0; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) (AcpiDmarTable + 1)); while ((UINTN) DmarHeader < (UINTN) AcpiDmarTable + AcpiDmarTable->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 ; } /** 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; } /** Return the index of PCI data. @param[in] VTdUnitInfo The VTd engine unit information. @param[in] Segment The Segment used to identify a VTd engine. @param[in] SourceId The SourceId used to identify a VTd engine and table entry. @return The index of the PCI data. @retval (UINTN)-1 The PCI data is not found. **/ UINTN GetPciDataIndex ( IN VTD_UNIT_INFO *VTdUnitInfo, IN UINT16 Segment, IN VTD_SOURCE_ID SourceId ) { UINTN Index; VTD_SOURCE_ID *PciSourceId; PEI_PCI_DEVICE_DATA *PciDeviceDataBase; if (Segment != VTdUnitInfo->Segment) { return (UINTN)-1; } for (Index = 0; Index < VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber; Index++) { PciDeviceDataBase = (PEI_PCI_DEVICE_DATA*) (UINTN) VTdUnitInfo->PciDeviceInfo.PciDeviceData; PciSourceId = &PciDeviceDataBase[Index].PciSourceId; if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) && (PciSourceId->Bits.Device == SourceId.Bits.Device) && (PciSourceId->Bits.Function == SourceId.Bits.Function) ) { return Index; } } return (UINTN)-1; } /** Register PCI device to VTd engine. @param[in] VTdUnitInfo The VTd engine unit information. @param[in] Segment The segment of the source. @param[in] SourceId The SourceId of the source. @param[in] DeviceType The DMAR device scope type. @param[in] CheckExist TRUE: ERROR will be returned if the PCI device is already registered. FALSE: SUCCESS will be returned if the PCI device is registered. @retval EFI_SUCCESS The PCI device is registered. @retval EFI_OUT_OF_RESOURCES No enough resource to register a new PCI device. @retval EFI_ALREADY_STARTED The device is already registered. **/ EFI_STATUS RegisterPciDevice ( IN VTD_UNIT_INFO *VTdUnitInfo, IN UINT16 Segment, IN VTD_SOURCE_ID SourceId, IN UINT8 DeviceType, IN BOOLEAN CheckExist ) { PEI_PCI_DEVICE_INFORMATION *PciDeviceInfo; VTD_SOURCE_ID *PciSourceId; UINTN PciDataIndex; UINTN PciDeviceDataSize; PEI_PCI_DEVICE_DATA *NewPciDeviceData; PEI_PCI_DEVICE_DATA *PciDeviceDataBase; PciDeviceInfo = &VTdUnitInfo->PciDeviceInfo; PciDataIndex = GetPciDataIndex (VTdUnitInfo, Segment, SourceId); if (PciDataIndex == (UINTN)-1) { // // Register new // if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) { // // Reallocate // PciDeviceDataSize = sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER); DEBUG ((DEBUG_INFO, "New PciDeviceDataSize:%d Page:%d\n", PciDeviceDataSize, EFI_SIZE_TO_PAGES (PciDeviceDataSize))); NewPciDeviceData = AllocateZeroPages (EFI_SIZE_TO_PAGES(PciDeviceDataSize)); if (NewPciDeviceData == NULL) { return EFI_OUT_OF_RESOURCES; } PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER; if (PciDeviceInfo->PciDeviceData != 0) { CopyMem (NewPciDeviceData, (VOID *) (UINTN) PciDeviceInfo->PciDeviceData, sizeof (*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber); FreePages((VOID *) (UINTN) PciDeviceInfo->PciDeviceData, PciDeviceInfo->PciDeviceDataPageSize); } PciDeviceInfo->PciDeviceData = (UINT32) (UINTN) NewPciDeviceData; PciDeviceInfo->PciDeviceDataPageSize = (UINT32) EFI_SIZE_TO_PAGES (PciDeviceDataSize); } ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber); PciDeviceDataBase = (PEI_PCI_DEVICE_DATA *) (UINTN) PciDeviceInfo->PciDeviceData; PciSourceId = &PciDeviceDataBase[PciDeviceInfo->PciDeviceDataNumber].PciSourceId; PciSourceId->Bits.Bus = SourceId.Bits.Bus; PciSourceId->Bits.Device = SourceId.Bits.Device; PciSourceId->Bits.Function = SourceId.Bits.Function; DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function)); PciDeviceDataBase[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType; if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) && (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) { DEBUG ((DEBUG_INFO, " (*)")); } DEBUG ((DEBUG_INFO, "\n")); PciDeviceInfo->PciDeviceDataNumber++; } else { if (CheckExist) { DEBUG ((DEBUG_INFO, " RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function)); return EFI_ALREADY_STARTED; } } return EFI_SUCCESS; } /** Process DMAR DHRD table. @param[in] VTdUnitInfo The VTd engine unit information. @param[in] DmarDrhd The DRHD table. **/ VOID ProcessDhrd ( IN VTD_UNIT_INFO *VTdUnitInfo, IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd ) { EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry; UINT8 Bus; UINT8 Device; UINT8 Function; EFI_STATUS Status; VTD_SOURCE_ID SourceId; DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress)); VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress; VTdUnitInfo->EnableQueuedInvalidation = 0; DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber)); VTdUnitInfo->Segment = DmarDrhd->SegmentNumber; VTdUnitInfo->FixedSecondLevelPagingEntry = 0; VTdUnitInfo->RmrrSecondLevelPagingEntry = 0; VTdUnitInfo->RootEntryTable = 0; VTdUnitInfo->ExtRootEntryTable = 0; VTdUnitInfo->RootEntryTablePageSize = 0; VTdUnitInfo->ExtRootEntryTablePageSize = 0; VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceDataMaxNumber = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceDataPageSize = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceData = 0; if ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0) { VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = TRUE; DEBUG ((DEBUG_INFO," ProcessDhrd: with INCLUDE ALL\n")); } else { VTdUnitInfo->PciDeviceInfo.IncludeAllFlag = FALSE; DEBUG ((DEBUG_INFO," ProcessDhrd: without INCLUDE ALL\n")); } VTdUnitInfo->PciDeviceInfo.PciDeviceDataNumber = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceDataMaxNumber = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceDataPageSize = 0; VTdUnitInfo->PciDeviceInfo.PciDeviceData = 0; 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; } 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 (VTdUnitInfo, DmarDrhd->SegmentNumber, SourceId, DmarDevScopeEntry->Type, TRUE); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR,"RegisterPciDevice Failed !\n")); } DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINTN) DmarDevScopeEntry + DmarDevScopeEntry->Length); } } /** Dump the PCI device information managed by this VTd engine. @param[in] VTdInfo The VTd engine context information. @param[in] VtdIndex The index of VTd engine. **/ VOID DumpPciDeviceInfo ( IN VTD_INFO *VTdInfo, IN UINTN VtdIndex ) { UINTN Index; PEI_PCI_DEVICE_DATA *PciDeviceDataBase; DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n", VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceDataNumber, VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.IncludeAllFlag )); PciDeviceDataBase = (PEI_PCI_DEVICE_DATA *) (UINTN) VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceData; for (Index = 0; Index < VTdInfo->VtdUnitInfo[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) { DEBUG ((DEBUG_INFO," S%04x B%02x D%02x F%02x\n", VTdInfo->VtdUnitInfo[VtdIndex].Segment, PciDeviceDataBase[Index].PciSourceId.Bits.Bus, PciDeviceDataBase[Index].PciSourceId.Bits.Device, PciDeviceDataBase[Index].PciSourceId.Bits.Function )); } } /** Parse DMAR DRHD table. @param[in] AcpiDmarTable DMAR ACPI table @return EFI_SUCCESS The DMAR DRHD table is parsed. **/ EFI_STATUS ParseDmarAcpiTableDrhd ( IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable ) { EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; UINTN VtdUnitNumber; UINTN VtdIndex; VTD_INFO *VTdInfo; VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable); if (VtdUnitNumber == 0) { return EFI_UNSUPPORTED; } VTdInfo = BuildGuidHob (&mVTdInfoGuid, sizeof (VTD_INFO) + (VtdUnitNumber - 1) * sizeof (VTD_UNIT_INFO)); ASSERT(VTdInfo != NULL); if (VTdInfo == NULL) { return EFI_OUT_OF_RESOURCES; } // // Initialize the engine mask to all. // VTdInfo->AcpiDmarTable = (UINT32) (UINTN) AcpiDmarTable; VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth; VTdInfo->VTdEngineCount = (UINT32) VtdUnitNumber; VtdIndex = 0; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) (AcpiDmarTable + 1)); while ((UINTN) DmarHeader < (UINTN) AcpiDmarTable + AcpiDmarTable->Header.Length) { switch (DmarHeader->Type) { case EFI_ACPI_DMAR_TYPE_DRHD: ASSERT (VtdIndex < VtdUnitNumber); ProcessDhrd (&VTdInfo->VtdUnitInfo[VtdIndex], (EFI_ACPI_DMAR_DRHD_HEADER *) DmarHeader); VtdIndex++; break; default: break; } DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) DmarHeader + DmarHeader->Length); } ASSERT (VtdIndex == VtdUnitNumber); for (VtdIndex = 0; VtdIndex < VtdUnitNumber; VtdIndex++) { DumpPciDeviceInfo (VTdInfo, VtdIndex); } return EFI_SUCCESS; } /** Process DMAR RMRR table. @param[in] VTdInfo The VTd engine context information. @param[in] DmarRmrr The RMRR table. **/ VOID ProcessRmrr ( IN VTD_INFO *VTdInfo, 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," PEI RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress)); if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) || (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) { return ; } 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; } Status = GetPciBusDeviceFunction (DmarRmrr->SegmentNumber, DmarDevScopeEntry, &Bus, &Device, &Function); if (EFI_ERROR (Status)) { continue; } 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 = EnableRmrrPageAttribute ( VTdInfo, DmarRmrr->SegmentNumber, SourceId, DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress, EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "EnableRmrrPageAttribute : %r\n", Status)); } DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *) ((UINTN) DmarDevScopeEntry + DmarDevScopeEntry->Length); } } /** Parse DMAR DRHD table. @param[in] VTdInfo The VTd engine context information. **/ VOID ParseDmarAcpiTableRmrr ( IN VTD_INFO *VTdInfo ) { EFI_ACPI_DMAR_HEADER *AcpiDmarTable; EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader; AcpiDmarTable = (EFI_ACPI_DMAR_HEADER *) (UINTN) VTdInfo->AcpiDmarTable; DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) (AcpiDmarTable + 1)); while ((UINTN) DmarHeader < (UINTN) AcpiDmarTable + AcpiDmarTable->Header.Length) { switch (DmarHeader->Type) { case EFI_ACPI_DMAR_TYPE_RMRR: ProcessRmrr (VTdInfo, (EFI_ACPI_DMAR_RMRR_HEADER *) DmarHeader); break; default: break; } DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *) ((UINTN) DmarHeader + DmarHeader->Length); } }