-/** @file\r
-\r
- Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "DmaProtection.h"\r
-\r
-UINT64 mBelow4GMemoryLimit;\r
-UINT64 mAbove4GMemoryLimit;\r
-\r
-EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
-\r
-VTD_ACCESS_REQUEST *mAccessRequest = NULL;\r
-UINTN mAccessRequestCount = 0;\r
-UINTN mAccessRequestMaxCount = 0;\r
-\r
-/**\r
- Append VTd Access Request to global.\r
-\r
- @param[in] Segment The Segment used to identify a VTd engine.\r
- @param[in] SourceId The SourceId used to identify a VTd engine and table entry.\r
- @param[in] BaseAddress The base of device memory address to be used as the DMA memory.\r
- @param[in] Length The length of device memory address to be used as the DMA memory.\r
- @param[in] IoMmuAccess The IOMMU access.\r
-\r
- @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.\r
- @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.\r
- @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.\r
- @retval EFI_INVALID_PARAMETER Length is 0.\r
- @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
- @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
- @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.\r
- @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
- @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
-\r
-**/\r
-EFI_STATUS\r
-RequestAccessAttribute (\r
- IN UINT16 Segment,\r
- IN VTD_SOURCE_ID SourceId,\r
- IN UINT64 BaseAddress,\r
- IN UINT64 Length,\r
- IN UINT64 IoMmuAccess\r
- )\r
-{\r
- VTD_ACCESS_REQUEST *NewAccessRequest;\r
- UINTN Index;\r
-\r
- //\r
- // Optimization for memory.\r
- //\r
- // If the last record is to IoMmuAccess=0,\r
- // Check previous records and remove the matched entry.\r
- //\r
- if (IoMmuAccess == 0) {\r
- for (Index = 0; Index < mAccessRequestCount; Index++) {\r
- if ((mAccessRequest[Index].Segment == Segment) &&\r
- (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) &&\r
- (mAccessRequest[Index].BaseAddress == BaseAddress) &&\r
- (mAccessRequest[Index].Length == Length) &&\r
- (mAccessRequest[Index].IoMmuAccess != 0)) {\r
- //\r
- // Remove this record [Index].\r
- // No need to add the new record.\r
- //\r
- if (Index != mAccessRequestCount - 1) {\r
- CopyMem (\r
- &mAccessRequest[Index],\r
- &mAccessRequest[Index + 1],\r
- sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index)\r
- );\r
- }\r
- ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST));\r
- mAccessRequestCount--;\r
- return EFI_SUCCESS;\r
- }\r
- }\r
- }\r
-\r
- if (mAccessRequestCount >= mAccessRequestMaxCount) {\r
- NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));\r
- if (NewAccessRequest == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST;\r
- if (mAccessRequest != NULL) {\r
- CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount);\r
- FreePool (mAccessRequest);\r
- }\r
- mAccessRequest = NewAccessRequest;\r
- }\r
-\r
- ASSERT (mAccessRequestCount < mAccessRequestMaxCount);\r
-\r
- mAccessRequest[mAccessRequestCount].Segment = Segment;\r
- mAccessRequest[mAccessRequestCount].SourceId = SourceId;\r
- mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress;\r
- mAccessRequest[mAccessRequestCount].Length = Length;\r
- mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess;\r
-\r
- mAccessRequestCount++;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Process Access Requests from before DMAR table is installed.\r
-\r
-**/\r
-VOID\r
-ProcessRequestedAccessAttribute (\r
- VOID\r
- )\r
-{\r
- UINTN Index;\r
- EFI_STATUS Status;\r
-\r
- DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));\r
-\r
- for (Index = 0; Index < mAccessRequestCount; Index++) {\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "PCI(S%x.B%x.D%x.F%x) ",\r
- mAccessRequest[Index].Segment,\r
- mAccessRequest[Index].SourceId.Bits.Bus,\r
- mAccessRequest[Index].SourceId.Bits.Device,\r
- mAccessRequest[Index].SourceId.Bits.Function\r
- ));\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "(0x%lx~0x%lx) - %lx\n",\r
- mAccessRequest[Index].BaseAddress,\r
- mAccessRequest[Index].Length,\r
- mAccessRequest[Index].IoMmuAccess\r
- ));\r
- Status = SetAccessAttribute (\r
- mAccessRequest[Index].Segment,\r
- mAccessRequest[Index].SourceId,\r
- mAccessRequest[Index].BaseAddress,\r
- mAccessRequest[Index].Length,\r
- mAccessRequest[Index].IoMmuAccess\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));\r
- }\r
- }\r
-\r
- if (mAccessRequest != NULL) {\r
- FreePool (mAccessRequest);\r
- }\r
- mAccessRequest = NULL;\r
- mAccessRequestCount = 0;\r
- mAccessRequestMaxCount = 0;\r
-\r
- DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));\r
-}\r
-\r
-/**\r
- return the UEFI memory information.\r
-\r
- @param[out] Below4GMemoryLimit The below 4GiB memory limit\r
- @param[out] Above4GMemoryLimit The above 4GiB memory limit\r
-**/\r
-VOID\r
-ReturnUefiMemoryMap (\r
- OUT UINT64 *Below4GMemoryLimit,\r
- OUT UINT64 *Above4GMemoryLimit\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
- EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
- EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
- EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
- EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
- UINTN EfiMemoryMapSize;\r
- UINTN EfiMapKey;\r
- UINTN EfiDescriptorSize;\r
- UINT32 EfiDescriptorVersion;\r
- UINT64 MemoryBlockLength;\r
-\r
- *Below4GMemoryLimit = 0;\r
- *Above4GMemoryLimit = 0;\r
-\r
- //\r
- // Get the EFI memory map.\r
- //\r
- EfiMemoryMapSize = 0;\r
- EfiMemoryMap = NULL;\r
- Status = gBS->GetMemoryMap (\r
- &EfiMemoryMapSize,\r
- EfiMemoryMap,\r
- &EfiMapKey,\r
- &EfiDescriptorSize,\r
- &EfiDescriptorVersion\r
- );\r
- ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- do {\r
- //\r
- // Use size returned back plus 1 descriptor for the AllocatePool.\r
- // We don't just multiply by 2 since the "for" loop below terminates on\r
- // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
- // we process bogus entries and create bogus E820 entries.\r
- //\r
- EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
- ASSERT (EfiMemoryMap != NULL);\r
- Status = gBS->GetMemoryMap (\r
- &EfiMemoryMapSize,\r
- EfiMemoryMap,\r
- &EfiMapKey,\r
- &EfiDescriptorSize,\r
- &EfiDescriptorVersion\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (EfiMemoryMap);\r
- }\r
- } while (Status == EFI_BUFFER_TOO_SMALL);\r
-\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Sort memory map from low to high\r
- //\r
- EfiEntry = EfiMemoryMap;\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
- while (EfiEntry < EfiMemoryMapEnd) {\r
- while (NextEfiEntry < EfiMemoryMapEnd) {\r
- if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
- CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
- }\r
-\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- //\r
- //\r
- //\r
- DEBUG ((DEBUG_INFO, "MemoryMap:\n"));\r
- EfiEntry = EfiMemoryMap;\r
- EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
- while (EfiEntry < EfiMemoryMapEnd) {\r
- MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
- DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));\r
- switch (EfiEntry->Type) {\r
- case EfiLoaderCode:\r
- case EfiLoaderData:\r
- case EfiBootServicesCode:\r
- case EfiBootServicesData:\r
- case EfiConventionalMemory:\r
- case EfiRuntimeServicesCode:\r
- case EfiRuntimeServicesData:\r
- case EfiACPIReclaimMemory:\r
- case EfiACPIMemoryNVS:\r
- case EfiReservedMemoryType:\r
- if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {\r
- //\r
- // Skip the memory block is under 1MB\r
- //\r
- } else if (EfiEntry->PhysicalStart >= BASE_4GB) {\r
- if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
- *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
- }\r
- } else {\r
- if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
- *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
- }\r
- }\r
- break;\r
- }\r
- EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
- }\r
-\r
- FreePool (EfiMemoryMap);\r
-\r
- DEBUG ((DEBUG_INFO, "Result:\n"));\r
- DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));\r
- DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- The scan bus callback function to always enable page attribute.\r
-\r
- @param[in] Context The context of the callback.\r
- @param[in] Segment The segment of the source.\r
- @param[in] Bus The bus of the source.\r
- @param[in] Device The device of the source.\r
- @param[in] Function The function of the source.\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-ScanBusCallbackAlwaysEnablePageAttribute (\r
- IN VOID *Context,\r
- IN UINT16 Segment,\r
- IN UINT8 Bus,\r
- IN UINT8 Device,\r
- IN UINT8 Function\r
- )\r
-{\r
- VTD_SOURCE_ID SourceId;\r
- EFI_STATUS Status;\r
-\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
- Status = AlwaysEnablePageAttribute (Segment, SourceId);\r
- return Status;\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device in the DeviceScope.\r
-\r
- @param[in] DeviceScope the input device scope data structure\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributeDeviceScope (\r
- IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope\r
- )\r
-{\r
- UINT8 Bus;\r
- UINT8 Device;\r
- UINT8 Function;\r
- VTD_SOURCE_ID SourceId;\r
- UINT8 SecondaryBusNumber;\r
- EFI_STATUS Status;\r
-\r
- Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);\r
-\r
- if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {\r
- //\r
- // Need scan the bridge and add all devices.\r
- //\r
- SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
- Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);\r
- return Status;\r
- } else {\r
- SourceId.Bits.Bus = Bus;\r
- SourceId.Bits.Device = Device;\r
- SourceId.Bits.Function = Function;\r
- Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);\r
- return Status;\r
- }\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device matching DeviceId.\r
-\r
- @param[in] PciDeviceId the input PCI device ID\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributePciDeviceId (\r
- IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId\r
- )\r
-{\r
- UINTN VtdIndex;\r
- UINTN PciIndex;\r
- PCI_DEVICE_DATA *PciDeviceData;\r
- EFI_STATUS Status;\r
-\r
- for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
- for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {\r
- PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];\r
-\r
- if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&\r
- ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&\r
- ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&\r
- ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&\r
- ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {\r
- Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);\r
- if (EFI_ERROR(Status)) {\r
- continue;\r
- }\r
- }\r
- }\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Always enable the VTd page attribute for the device.\r
-\r
- @param[in] DeviceInfo the exception device information\r
-\r
- @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.\r
-**/\r
-EFI_STATUS\r
-AlwaysEnablePageAttributeExceptionDeviceInfo (\r
- IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo\r
- )\r
-{\r
- switch (DeviceInfo->Type) {\r
- case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:\r
- return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));\r
- case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:\r
- return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));\r
- default:\r
- return EFI_UNSUPPORTED;\r
- }\r
-}\r
-\r
-/**\r
- Initialize platform VTd policy.\r
-**/\r
-VOID\r
-InitializePlatformVTdPolicy (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN DeviceInfoCount;\r
- VOID *DeviceInfo;\r
- EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;\r
- UINTN Index;\r
-\r
- //\r
- // It is optional.\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEdkiiPlatformVTdPolicyProtocolGuid,\r
- NULL,\r
- (VOID **)&mPlatformVTdPolicy\r
- );\r
- if (!EFI_ERROR(Status)) {\r
- DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));\r
- Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);\r
- if (!EFI_ERROR(Status)) {\r
- ThisDeviceInfo = DeviceInfo;\r
- for (Index = 0; Index < DeviceInfoCount; Index++) {\r
- if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {\r
- break;\r
- }\r
- AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);\r
- ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);\r
- }\r
- FreePool (DeviceInfo);\r
- }\r
- }\r
-}\r
-\r
-/**\r
- Setup VTd engine.\r
-**/\r
-VOID\r
-SetupVtd (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- VOID *PciEnumerationComplete;\r
- UINTN Index;\r
- UINT64 Below4GMemoryLimit;\r
- UINT64 Above4GMemoryLimit;\r
-\r
- //\r
- // PCI Enumeration must be done\r
- //\r
- Status = gBS->LocateProtocol (\r
- &gEfiPciEnumerationCompleteProtocolGuid,\r
- NULL,\r
- &PciEnumerationComplete\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);\r
- Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);\r
- DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));\r
-\r
- mBelow4GMemoryLimit = Below4GMemoryLimit;\r
- mAbove4GMemoryLimit = Above4GMemoryLimit;\r
-\r
- //\r
- // 1. setup\r
- //\r
- DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));\r
- Status = ParseDmarAcpiTableDrhd ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
- DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));\r
- PrepareVtdConfig ();\r
-\r
- //\r
- // 2. initialization\r
- //\r
- DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));\r
- Status = SetupTranslationTable ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
-\r
- InitializePlatformVTdPolicy ();\r
-\r
- ParseDmarAcpiTableRmrr ();\r
-\r
- if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) == 0) {\r
- //\r
- // Support IOMMU access attribute request recording before DMAR table is installed.\r
- // Here is to process the requests.\r
- //\r
- ProcessRequestedAccessAttribute ();\r
- }\r
-\r
- for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
- DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));\r
- if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {\r
- DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);\r
- }\r
- if (mVtdUnitInformation[Index].RootEntryTable != NULL) {\r
- DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);\r
- }\r
- }\r
-\r
- //\r
- // 3. enable\r
- //\r
- DEBUG ((DEBUG_INFO, "EnableDmar\n"));\r
- Status = EnableDmar ();\r
- if (EFI_ERROR (Status)) {\r
- return;\r
- }\r
- DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));\r
- DumpVtdRegsAll ();\r
-}\r
-\r
-/**\r
- Notification function of ACPI Table change.\r
-\r
- This is a notification function registered on ACPI Table change event.\r
-\r
- @param Event Event whose notification function is being invoked.\r
- @param Context Pointer to the notification function's context.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-AcpiNotificationFunc (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- Status = GetDmarAcpiTable ();\r
- if (EFI_ERROR (Status)) {\r
- if (Status == EFI_ALREADY_STARTED) {\r
- gBS->CloseEvent (Event);\r
- }\r
- return;\r
- }\r
- SetupVtd ();\r
- gBS->CloseEvent (Event);\r
-}\r
-\r
-/**\r
- Exit boot service callback function.\r
-\r
- @param[in] Event The event handle.\r
- @param[in] Context The event content.\r
-**/\r
-VOID\r
-EFIAPI\r
-OnExitBootServices (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- UINTN VtdIndex;\r
-\r
- DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
- DumpVtdRegsAll ();\r
-\r
- DEBUG ((DEBUG_INFO, "Invalidate all\n"));\r
- for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
- FlushWriteBuffer (VtdIndex);\r
-\r
- InvalidateContextCache (VtdIndex);\r
-\r
- InvalidateIOTLB (VtdIndex);\r
- }\r
-\r
- if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
- DisableDmar ();\r
- DumpVtdRegsAll ();\r
- }\r
-}\r
-\r
-/**\r
- Legacy boot callback function.\r
-\r
- @param[in] Event The event handle.\r
- @param[in] Context The event content.\r
-**/\r
-VOID\r
-EFIAPI\r
-OnLegacyBoot (\r
- EFI_EVENT Event,\r
- VOID *Context\r
- )\r
-{\r
- DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));\r
- DumpVtdRegsAll ();\r
- DisableDmar ();\r
- DumpVtdRegsAll ();\r
-}\r
-\r
-/**\r
- Initialize DMA protection.\r
-**/\r
-VOID\r
-InitializeDmaProtection (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_EVENT ExitBootServicesEvent;\r
- EFI_EVENT LegacyBootEvent;\r
- EFI_EVENT EventAcpi10;\r
- EFI_EVENT EventAcpi20;\r
-\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- VTD_TPL_LEVEL,\r
- AcpiNotificationFunc,\r
- NULL,\r
- &gEfiAcpi10TableGuid,\r
- &EventAcpi10\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- VTD_TPL_LEVEL,\r
- AcpiNotificationFunc,\r
- NULL,\r
- &gEfiAcpi20TableGuid,\r
- &EventAcpi20\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Signal the events initially for the case\r
- // that DMAR table has been installed.\r
- //\r
- gBS->SignalEvent (EventAcpi20);\r
- gBS->SignalEvent (EventAcpi10);\r
-\r
- Status = gBS->CreateEventEx (\r
- EVT_NOTIFY_SIGNAL,\r
- TPL_CALLBACK,\r
- OnExitBootServices,\r
- NULL,\r
- &gEfiEventExitBootServicesGuid,\r
- &ExitBootServicesEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- Status = EfiCreateEventLegacyBootEx (\r
- TPL_CALLBACK,\r
- OnLegacyBoot,\r
- NULL,\r
- &LegacyBootEvent\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return ;\r
-}\r