/** @file This code provides a initialization of intel VT-d (Virtualization Technology for Directed I/O). Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "SaInitDxe.h" #include "SaInit.h" #include "VTd.h" #include #include #include #include #include GLOBAL_REMOVE_IF_UNREFERENCED SA_POLICY_PROTOCOL *mSaPolicy; GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB *mPchConfigHob; GLOBAL_REMOVE_IF_UNREFERENCED PCH_SERIES mPchSeries; GLOBAL_REMOVE_IF_UNREFERENCED SA_CONFIG_HOB *SaConfigHob; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C0Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C1Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C2Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C3Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C4Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddI2C5Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddSpi0Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddSpi1Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddUa00Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddUa01Needed; GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mAnddUa02Needed; /** For device that specified by Device Num and Function Num, mDevEnMap is used to check device presence. 0x80 means use Device ID to detemine presence The structure is used to check if device scope is valid when update DMAR table **/ UINT16 mDevEnMap[][2] = {{0x0200, 0x80}, {0x1400, 0x80}, {0x1401, 0x80}}; BOOLEAN mInterruptRemappingSupport; /** Get the corresponding device Enable/Disable bit according DevNum and FunNum @param[in] DevNum - Device Number @param[in] FunNum - Function Number @retval If the device is found, return disable/Enable bit in FD/Deven reigster @retval If not found return 0xFF **/ UINT16 GetFunDisableBit ( UINT8 DevNum, UINT8 FunNum ) { UINTN Index; for (Index = 0; Index < sizeof (mDevEnMap) / 4; Index++) { if (mDevEnMap[Index][0] == ((DevNum << 0x08) | FunNum)) { return mDevEnMap[Index][1]; } } return 0xFF; } /** Update the DRHD structure @param[in, out] DrhdEnginePtr - A pointer to DRHD structure **/ VOID UpdateDrhd ( IN OUT VOID *DrhdEnginePtr ) { UINT16 Length; UINT16 DisableBit; UINTN DeviceScopeNum; BOOLEAN NeedRemove; EFI_ACPI_DRHD_ENGINE1_STRUCT *DrhdEngine; // // Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE1_STRUCT Pointer // DrhdEngine = (EFI_ACPI_DRHD_ENGINE1_STRUCT *) DrhdEnginePtr; Length = DrhdEngine->Length; DeviceScopeNum = (DrhdEngine->Length - EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); DisableBit = GetFunDisableBit ( DrhdEngine->DeviceScope[0].PciPath[0], DrhdEngine->DeviceScope[0].PciPath[1] ); NeedRemove = FALSE; if ((DisableBit == 0xFF) || (DrhdEngine->RegisterBaseAddress == 0) || ((DisableBit == 0x80) && (MmioRead32 (MmPciBase (0, DrhdEngine->DeviceScope[0].PciPath[0], DrhdEngine->DeviceScope[0].PciPath[1]) + 0x00) == 0xFFFFFFFF)) ) { NeedRemove = TRUE; } if (NeedRemove) { Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); } /// /// If no devicescope is left, we set the structure length as 0x00 /// if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine->Flags == 0x01)) { DrhdEngine->Length = Length; } else { DrhdEngine->Length = 0; } } /** Get IOAPIC ID from LPC @retval APIC ID **/ UINT8 GetIoApicId ( VOID ) { UINT8 volatile *IoapicIndex; UINT32 volatile *IoapicData; UINT32 IoApicIndexAddr; UINT32 IoApicDataAddr; UINT32 Data32; /// /// Get IOAPIC base /// PchIoApicBaseGet (&IoApicIndexAddr, &IoApicDataAddr); IoapicIndex = (UINT8 *) (UINTN) IoApicIndexAddr; IoapicData = (UINT32 *) (UINTN) IoApicDataAddr; /// /// Get APIC ID from Identification Register (Index 0) /// *IoapicIndex = 0; Data32 = (*IoapicData & 0x0F000000) >> 24; return (UINT8) Data32; } /** Initialize some data required for ANDD table generation. **/ VOID AnddTablePreInit ( VOID ) { /* For Serial IO devices, they do not appear in PCI space, use platform policy or SPT SKU to determine existence - I2C0 (D21: F0) - I2C1 (D21: F1) - I2C2 (D21: F2) (LP Only) - I2C3 (D21: F3) (LP Only) - I2C4 (D25: F2) (LP Only) - I2C5 (D25: F1) (LP Only) - SPI0 (D30: F2) - SPI1 (D30: F3) - UART0 (D30: F0) - UART1 (D30: F1) - UART2 (D25: F0) - PEMC (D30: F4) (LP Only) (PCI mode only) - PSDO (D30: F5) (LP Only) (Deprecated) - PSDC (D30: F6) (LP Only) (PCI mode only) */ mAnddI2C0Needed = TRUE; mAnddI2C1Needed = TRUE; mAnddI2C2Needed = TRUE; mAnddI2C3Needed = TRUE; mAnddI2C4Needed = TRUE; mAnddI2C5Needed = TRUE; mAnddSpi0Needed = TRUE; mAnddSpi1Needed = TRUE; mAnddUa00Needed = TRUE; mAnddUa01Needed = TRUE; mAnddUa02Needed = TRUE; if (mPchConfigHob->SerialIo.DevMode[0] != 2) { mAnddI2C0Needed = FALSE; if (mPchConfigHob->SerialIo.DevMode[0] == 0) { // // Function 0 disabled so no sub-functions // mAnddI2C1Needed = FALSE; mAnddI2C2Needed = FALSE; mAnddI2C3Needed = FALSE; } } if (mPchConfigHob->SerialIo.DevMode[1] != 2) { mAnddI2C1Needed = FALSE; } if ((mPchSeries != PchLp) || (mPchConfigHob->SerialIo.DevMode[2] != 2)) { mAnddI2C2Needed = FALSE; } if ((mPchSeries != PchLp) || (mPchConfigHob->SerialIo.DevMode[3] != 2)) { mAnddI2C3Needed = FALSE; } if ((mPchSeries != PchLp) || (mPchConfigHob->SerialIo.DevMode[4] != 2)) { mAnddI2C4Needed = FALSE; } if ((mPchSeries != PchLp) || (mPchConfigHob->SerialIo.DevMode[5] != 2)) { mAnddI2C5Needed = FALSE; } if (mPchConfigHob->SerialIo.DevMode[6] != 2) { mAnddSpi0Needed = FALSE; } if (mPchConfigHob->SerialIo.DevMode[7] != 2) { mAnddSpi1Needed = FALSE; } if (mPchConfigHob->SerialIo.DevMode[8] != 2) { mAnddUa00Needed = FALSE; if (mPchConfigHob->SerialIo.DevMode[8] == 0) { // // Function 0 disabled so no sub-functions // mAnddUa01Needed = FALSE; mAnddSpi0Needed = FALSE; mAnddSpi1Needed = FALSE; } } if (mPchConfigHob->SerialIo.DevMode[9] != 2) { mAnddUa01Needed = FALSE; } if (mPchConfigHob->SerialIo.DevMode[10] != 2) { mAnddUa02Needed = FALSE; if (mPchConfigHob->SerialIo.DevMode[10] == 0) { // // Function 0 disabled so no sub-functions // mAnddI2C4Needed = FALSE; mAnddI2C5Needed = FALSE; } } } /** Update the second DRHD structure @param[in, out] DrhdEnginePtr - A pointer to DRHD structure **/ VOID UpdateDrhd2 ( IN OUT VOID *DrhdEnginePtr ) { UINT16 Length; UINTN DeviceScopeNum; UINTN ValidDeviceScopeNum; UINT16 Data16; UINT16 Index; UINT8 Bus; UINT8 Path[2]; BOOLEAN NeedRemove; EFI_ACPI_DRHD_ENGINE2_STRUCT *DrhdEngine; /// /// Convert DrhdEnginePtr to EFI_ACPI_DRHD_ENGINE2_STRUCT Pointer /// DrhdEngine = (EFI_ACPI_DRHD_ENGINE2_STRUCT *) DrhdEnginePtr; Length = DrhdEngine->Length; DeviceScopeNum = (DrhdEngine->Length - EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); Data16 = 0; Bus = 0; ValidDeviceScopeNum = 0; Path[0] = 0; Path[1] = 0; AnddTablePreInit (); for (Index = 0; Index < DeviceScopeNum; Index++) { NeedRemove = FALSE; /** For HPET and APIC, update device scope if Interrupt remapping is supported. remove device scope if interrupt remapping is not supported. - Index = 0 - IOAPIC - Index = 1 - HPET **/ if (mInterruptRemappingSupport) { if (Index == 0) { /// /// Update source id for IoApic's device scope entry /// PchP2sbCfgGet16 (R_PCH_P2SB_IBDF, &Data16); Bus = (UINT8) (Data16 >> 8); if (Bus != 0x00) { Path[0] = (UINT8) ((Data16 & 0xff) >> 3); Path[1] = (UINT8) (Data16 & 0x7); } else { DEBUG ((DEBUG_WARN, "P2SB APIC Bus, Device and Function numbers were not programmed yet or invalid, use hardcoding values instead!\n")); Bus = 0xF0; Path[0] = 0x1F; Path[1] = 0x0; } DrhdEngine->DeviceScope[Index].StartBusNumber = Bus; DrhdEngine->DeviceScope[Index].PciPath[0] = Path[0]; DrhdEngine->DeviceScope[Index].PciPath[1] = Path[1]; // // Update APIC ID // DrhdEngine->DeviceScope[Index].EnumId = GetIoApicId (); } if (Index == 1) { /// /// Update source id for HPET's device scope entry /// PchP2sbCfgGet16 (R_PCH_P2SB_HBDF, &Data16); Bus = (UINT8) (Data16 >> 8); Path[0] = (UINT8) ((Data16 & 0xFF) >> 3); Path[1] = (UINT8) (Data16 & 0x7); DrhdEngine->DeviceScope[Index].StartBusNumber = Bus; DrhdEngine->DeviceScope[Index].PciPath[0] = Path[0]; DrhdEngine->DeviceScope[Index].PciPath[1] = Path[1]; } } else { if ((Index == 0) || (Index == 1)) { NeedRemove = TRUE; } } switch (Index) { case 0: case 1: break; case 2: if (mAnddI2C0Needed == FALSE) { NeedRemove = TRUE; } break; case 3: if (mAnddI2C1Needed == FALSE) { NeedRemove = TRUE; } break; case 4: if (mAnddI2C2Needed == FALSE) { NeedRemove = TRUE; } break; case 5: if (mAnddI2C3Needed == FALSE) { NeedRemove = TRUE; } break; case 6: if (mAnddI2C4Needed == FALSE) { NeedRemove = TRUE; } break; case 7: if (mAnddI2C5Needed == FALSE) { NeedRemove = TRUE; } break; case 8: if (mAnddSpi0Needed == FALSE) { NeedRemove = TRUE; } break; case 9: if (mAnddSpi1Needed == FALSE) { NeedRemove = TRUE; } break; case 10: if (mAnddUa00Needed == FALSE) { NeedRemove = TRUE; } break; case 11: if (mAnddUa01Needed == FALSE) { NeedRemove = TRUE; } break; case 12: if (mAnddUa02Needed == FALSE) { NeedRemove = TRUE; } break; default: NeedRemove = TRUE; break; } CopyMem ( &DrhdEngine->DeviceScope[ValidDeviceScopeNum], &DrhdEngine->DeviceScope[Index], sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE) ); if (NeedRemove) { Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); } else { ValidDeviceScopeNum++; } } /// /// If no devicescope is left, we set the structure length as 0x00 /// if ((Length > EFI_ACPI_DRHD_ENGINE_HEADER_LENGTH) || (DrhdEngine->Flags == 0x01)) { DrhdEngine->Length = Length; } else { DrhdEngine->Length = 0; } } /** Update the RMRR structure @param[in, out] RmrrPtr - A pointer to RMRR structure **/ VOID UpdateRmrr ( IN OUT VOID *RmrrPtr ) { UINT16 Length; UINT16 DisableBit; UINTN DeviceScopeNum; UINTN ValidDeviceScopeNum; UINTN Index; BOOLEAN NeedRemove; EFI_ACPI_RMRR_USB_STRUC *Rmrr; /// /// To make sure all devicescope can be checked, /// we convert the RmrrPtr to EFI_ACPI_RMRR_USB_STRUC pointer /// Rmrr = (EFI_ACPI_RMRR_USB_STRUC *) RmrrPtr; Length = Rmrr->Length; ValidDeviceScopeNum = 0; DeviceScopeNum = (Rmrr->Length - EFI_ACPI_RMRR_HEADER_LENGTH) / sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); for (Index = 0; Index < DeviceScopeNum; Index++) { DisableBit = GetFunDisableBit ( Rmrr->DeviceScope[Index].PciPath[0], Rmrr->DeviceScope[Index].PciPath[1] ); NeedRemove = FALSE; if ((DisableBit == 0xFF) || ((DisableBit == 0x80) && (MmioRead32 (MmPciBase (0, Rmrr->DeviceScope[Index].PciPath[0], Rmrr->DeviceScope[Index].PciPath[1]) + 0x00) == 0xFFFFFFFF)) ) { NeedRemove = TRUE; } CopyMem ( &Rmrr->DeviceScope[ValidDeviceScopeNum], &Rmrr->DeviceScope[Index], sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE) ); if (Rmrr->RmrLimitAddress == 0x0) { NeedRemove = TRUE; } if (NeedRemove) { Length -= sizeof (EFI_ACPI_DEV_SCOPE_STRUCTURE); } else { ValidDeviceScopeNum++; } } /// /// If No deviceScope is left, set length as 0x00 /// if (Length > EFI_ACPI_RMRR_HEADER_LENGTH) { Rmrr->Length = Length; } else { Rmrr->Length = 0; } } /** Update the DMAR table @param[in, out] TableHeader - The table to be set @param[in, out] Version - Version to publish **/ VOID DmarTableUpdate ( IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader, IN OUT EFI_ACPI_TABLE_VERSION *Version ) { EFI_ACPI_DMAR_TABLE *DmarTable; EFI_ACPI_DMAR_TABLE TempDmarTable; UINTN Offset; UINTN StructureLen; UINTN McD0BaseAddress; UINT32 MchBar; UINT16 IgdMode; UINT16 GttMode; UINT32 IgdMemSize; UINT32 GttMemSize; EFI_STATUS Status; MISC_DXE_CONFIG *MiscDxeConfig; CPU_GENERATION CpuGeneration; UINT64 OemTableId; IgdMemSize = 0; GttMemSize = 0; DmarTable = (EFI_ACPI_DMAR_TABLE *) TableHeader; CpuGeneration = GetCpuGeneration (); // // The Default OEM Table ID is "KBL " // OemTableId = KBL_OEM_TABLE_ID; Status = GetConfigBlock ((VOID *) mSaPolicy, &gMiscDxeConfigGuid, (VOID *)&MiscDxeConfig); ASSERT_EFI_ERROR (Status); /// /// Set INTR_REMAP bit (BIT 0) if interrupt remapping is supported /// if (mInterruptRemappingSupport) { DmarTable->Flags |= BIT0; } if (SaConfigHob->VtdData.X2ApicOptOut == 1) { DmarTable->Flags |= BIT1; } else { DmarTable->Flags &= 0xFD; } /// /// Get OemId /// CopyMem (DmarTable->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (DmarTable->Header.OemId)); if (CpuGeneration == EnumSklCpu) { // // Use "SKL " as OEM Table ID if the CpuGeneration is SKL // OemTableId = SKL_OEM_TABLE_ID; } // // Update OEM Table ID // DmarTable->Header.OemTableId = OemTableId; /// /// Calculate IGD memsize /// McD0BaseAddress = MmPciBase (SA_MC_BUS, 0, 0); MchBar = (UINT32) MmioRead64 (McD0BaseAddress + R_SA_MCHBAR) & ~BIT0; IgdMode = ((MmioRead16 (McD0BaseAddress + R_SA_GGC) & B_SKL_SA_GGC_GMS_MASK) >> N_SKL_SA_GGC_GMS_OFFSET) & 0xFF; if (IgdMode < 0xF0) { IgdMemSize = IgdMode * 32 * (1024) * (1024); } else { IgdMemSize = 4 * (IgdMode - 0xF0 + 1) * (1024) * (1024); } /// /// Calculate GTT mem size /// GttMemSize = 0; GttMode = (MmioRead16 (McD0BaseAddress + R_SA_GGC) & B_SKL_SA_GGC_GGMS_MASK) >> N_SKL_SA_GGC_GGMS_OFFSET; if (GttMode <= V_SKL_SA_GGC_GGMS_8MB) { GttMemSize = (1 << GttMode) * (1024) * (1024); } DmarTable->RmrrIgd.RmrBaseAddress = (MmioRead32 (McD0BaseAddress + R_SA_TOLUD) & ~(0x01)) - IgdMemSize - GttMemSize; DmarTable->RmrrIgd.RmrLimitAddress = DmarTable->RmrrIgd.RmrBaseAddress + IgdMemSize + GttMemSize - 1; DEBUG ((DEBUG_INFO, "RMRR Base address IGD %016lX\n", DmarTable->RmrrIgd.RmrBaseAddress)); DEBUG ((DEBUG_INFO, "RMRR Limit address IGD %016lX\n", DmarTable->RmrrIgd.RmrLimitAddress)); DmarTable->RmrrUsb.RmrBaseAddress = MiscDxeConfig->RmrrUsbBaseAddress[0]; DmarTable->RmrrUsb.RmrLimitAddress = MiscDxeConfig->RmrrUsbBaseAddress[1]; /// /// Convert to 4KB alignment. /// if (DmarTable->RmrrUsb.RmrLimitAddress != 0x0) { DmarTable->RmrrUsb.RmrBaseAddress &= (EFI_PHYSICAL_ADDRESS) ~0xFFF; DmarTable->RmrrUsb.RmrLimitAddress &= (EFI_PHYSICAL_ADDRESS) ~0xFFF; DmarTable->RmrrUsb.RmrLimitAddress += 0x1000-1; } DEBUG ((DEBUG_INFO, "RMRR Base address USB %016lX\n", DmarTable->RmrrUsb.RmrBaseAddress)); DEBUG ((DEBUG_INFO, "RMRR Limit address USB %016lX\n", DmarTable->RmrrUsb.RmrLimitAddress)); if (DmarTable->RmrrUsb.RmrBaseAddress == 0) { DEBUG ((DEBUG_WARN, "WARNING: RmrrUsb.RmrBaseAddress is 0.\n")); } /// /// Update DRHD structures of DmarTable /// DmarTable->DrhdEngine1.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD1_OFFSET) &~1); DmarTable->DrhdEngine2.RegisterBaseAddress = (MmioRead32 (MchBar + R_SA_MCHBAR_VTD2_OFFSET) &~1); DEBUG ((DEBUG_INFO, "VTD base address1 %x\n", DmarTable->DrhdEngine1.RegisterBaseAddress)); DEBUG ((DEBUG_INFO, "VTD base address2 %x\n", DmarTable->DrhdEngine2.RegisterBaseAddress)); /// /// copy DmarTable to TempDmarTable to be processed /// CopyMem (&TempDmarTable, DmarTable, sizeof (EFI_ACPI_DMAR_TABLE)); UpdateDrhd (&TempDmarTable.DrhdEngine1); UpdateDrhd2 (&TempDmarTable.DrhdEngine2); /// /// Update RMRR structures of temp DMAR table /// UpdateRmrr ((VOID *) &TempDmarTable.RmrrUsb); UpdateRmrr ((VOID *) &TempDmarTable.RmrrIgd); /// /// Remove unused device scope or entire DRHD structures /// Offset = (UINTN) (&TempDmarTable.DrhdEngine1); if (TempDmarTable.DrhdEngine1.Length != 0) { Offset += TempDmarTable.DrhdEngine1.Length; } if (TempDmarTable.DrhdEngine2.Length != 0) { StructureLen = TempDmarTable.DrhdEngine2.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.DrhdEngine2, TempDmarTable.DrhdEngine2.Length); Offset += StructureLen; } /// /// Remove unused device scope or entire RMRR structures /// if (TempDmarTable.RmrrUsb.Length != 0) { StructureLen = TempDmarTable.RmrrUsb.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.RmrrUsb, TempDmarTable.RmrrUsb.Length); Offset += StructureLen; } if (TempDmarTable.RmrrIgd.Length != 0) { StructureLen = TempDmarTable.RmrrIgd.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.RmrrIgd, TempDmarTable.RmrrIgd.Length); Offset += StructureLen; } /// /// Include necessary ANDD structures for SPT /// if (mAnddI2C0Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C0.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C0, TempDmarTable.AnddI2C0.Length); Offset += StructureLen; } if (mAnddI2C1Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C1.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C1, TempDmarTable.AnddI2C1.Length); Offset += StructureLen; } if (mAnddI2C2Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C2.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C2, TempDmarTable.AnddI2C2.Length); Offset += StructureLen; } if (mAnddI2C3Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C3.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C3, TempDmarTable.AnddI2C3.Length); Offset += StructureLen; } if (mAnddI2C4Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C4.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C4, TempDmarTable.AnddI2C4.Length); Offset += StructureLen; } if (mAnddI2C5Needed == TRUE) { StructureLen = TempDmarTable.AnddI2C5.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddI2C5, TempDmarTable.AnddI2C5.Length); Offset += StructureLen; } if (mAnddSpi0Needed == TRUE) { StructureLen = TempDmarTable.AnddSpi0.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddSpi0, TempDmarTable.AnddSpi0.Length); Offset += StructureLen; } if (mAnddSpi1Needed == TRUE) { StructureLen = TempDmarTable.AnddSpi1.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddSpi1, TempDmarTable.AnddSpi1.Length); Offset += StructureLen; } if (mAnddUa00Needed == TRUE) { StructureLen = TempDmarTable.AnddUa00.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddUa00, TempDmarTable.AnddUa00.Length); Offset += StructureLen; } if (mAnddUa01Needed == TRUE) { StructureLen = TempDmarTable.AnddUa01.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddUa01, TempDmarTable.AnddUa01.Length); Offset += StructureLen; } if (mAnddUa02Needed == TRUE) { StructureLen = TempDmarTable.AnddUa02.Length; CopyMem ((VOID *) Offset, (VOID *) &TempDmarTable.AnddUa02, TempDmarTable.AnddUa02.Length); Offset += StructureLen; } Offset = Offset - (UINTN) &TempDmarTable; /// /// Re-calculate DMAR table check sum /// TempDmarTable.Header.Checksum = (UINT8) (TempDmarTable.Header.Checksum + TempDmarTable.Header.Length - Offset); /// /// Set DMAR table length /// TempDmarTable.Header.Length = (UINT32) Offset; /// /// Replace DMAR table with rebuilt table TempDmarTable /// CopyMem ((VOID *) DmarTable, (VOID *) &TempDmarTable, TempDmarTable.Header.Length); } /** EndOfDxe routine for update DMAR **/ VOID UpdateDmarEndOfDxe ( VOID ) { EFI_STATUS Status; EFI_HANDLE *HandleBuffer; UINTN NumberOfHandles; EFI_FV_FILETYPE FileType; UINT32 FvStatus; EFI_FV_FILE_ATTRIBUTES Attributes; UINTN Size; UINTN i; INTN Instance; EFI_ACPI_TABLE_VERSION Version; EFI_ACPI_COMMON_HEADER *CurrentTable; UINTN AcpiTableHandle; EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol; EFI_ACPI_TABLE_PROTOCOL *AcpiTable; EFI_ACPI_DESCRIPTION_HEADER *VtdAcpiTable; STATIC BOOLEAN Triggered = FALSE; EFI_PEI_HOB_POINTERS HobPtr; if (Triggered) { return; } Triggered = TRUE; FwVol = NULL; AcpiTable = NULL; VtdAcpiTable = NULL; /// /// Locate PCH Policy HOB and PCH series to support feature enabling/disabling /// // // Get PCH Config HOB. // HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid); ASSERT (HobPtr.Guid != NULL); mPchConfigHob = GET_GUID_HOB_DATA (HobPtr.Guid); mPchSeries = GetPchSeries (); /// /// Locate ACPI support protocol /// Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable); /// /// Locate protocol. /// There is little chance we can't find an FV protocol /// Status = gBS->LocateHandleBuffer ( ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NumberOfHandles, &HandleBuffer ); ASSERT_EFI_ERROR (Status); /// /// Looking for FV with ACPI storage file /// for (i = 0; i < NumberOfHandles; i++) { /// /// Get the protocol on this handle /// This should not fail because of LocateHandleBuffer /// Status = gBS->HandleProtocol ( HandleBuffer[i], &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &FwVol ); ASSERT_EFI_ERROR (Status); /// /// See if it has the ACPI storage file /// Size = 0; FvStatus = 0; Status = FwVol->ReadFile ( FwVol, &gSaAcpiTableStorageGuid, NULL, &Size, &FileType, &Attributes, &FvStatus ); /// /// If we found it, then we are done /// if (Status == EFI_SUCCESS) { break; } } /// /// Our exit status is determined by the success of the previous operations /// If the protocol was found, Instance already points to it. /// /// /// Free any allocated buffers /// FreePool (HandleBuffer); /// /// Sanity check that we found our data file /// ASSERT (FwVol); if (FwVol == NULL) { return; } /// /// By default, a table belongs in all ACPI table versions published. /// Version = EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0; /// /// Read tables from the storage file. /// Instance = 0; CurrentTable = NULL; while (Status == EFI_SUCCESS) { Status = FwVol->ReadSection ( FwVol, &gSaAcpiTableStorageGuid, EFI_SECTION_RAW, Instance, (VOID **) &CurrentTable, &Size, &FvStatus ); if (!EFI_ERROR (Status)) { /// /// Check the Signature ID to modify the table /// switch (((EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable)->Signature) { case EFI_ACPI_VTD_DMAR_TABLE_SIGNATURE: VtdAcpiTable = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTable; DmarTableUpdate (VtdAcpiTable, &Version); break; default: break; } /// /// Increment the instance /// Instance++; CurrentTable = NULL; } } /// /// Update the VTD table in the ACPI tables. /// AcpiTableHandle = 0; if (VtdAcpiTable != NULL) { Status = AcpiTable->InstallAcpiTable ( AcpiTable, VtdAcpiTable, VtdAcpiTable->Length, &AcpiTableHandle ); FreePool (VtdAcpiTable); } } /** Locate the VT-d ACPI tables data file and read ACPI SSDT tables. Publish the appropriate SSDT based on current configuration and capabilities. @param[in] SaPolicy - SA DXE Policy protocol @retval EFI_SUCCESS - Vtd initialization complete @exception EFI_UNSUPPORTED - Vtd is not enabled by policy **/ EFI_STATUS VtdInit ( IN SA_POLICY_PROTOCOL *SaPolicy ) { UINTN McD0BaseAddress; mInterruptRemappingSupport = FALSE; SaConfigHob = NULL; SaConfigHob = GetFirstGuidHob (&gSaConfigHobGuid); if (SaConfigHob != NULL) { mInterruptRemappingSupport = SaConfigHob->VtdData.InterruptRemappingSupport; } McD0BaseAddress = MmPciBase (SA_MC_BUS, 0, 0); mSaPolicy = SaPolicy; if (((SaConfigHob != NULL) && (SaConfigHob->VtdData.VtdDisable)) || (MmioRead32 (McD0BaseAddress + R_SA_MC_CAPID0_A_OFFSET) & BIT23)) { DEBUG ((DEBUG_WARN, "VTd disabled or no capability!\n")); return EFI_UNSUPPORTED; } /// /// Check SA supports VTD and VTD is enabled in setup menu /// DEBUG ((DEBUG_INFO, "VTd enabled\n")); return EFI_SUCCESS; }