3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php.
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 #include "DmaProtection.h"
16 EFI_ACPI_SDT_PROTOCOL
*mAcpiSdt
;
17 UINT64 mBelow4GMemoryLimit
;
18 UINT64 mAbove4GMemoryLimit
;
20 EDKII_PLATFORM_VTD_POLICY_PROTOCOL
*mPlatformVTdPolicy
;
23 return the UEFI memory information.
25 @param[out] Below4GMemoryLimit The below 4GiB memory limit
26 @param[out] Above4GMemoryLimit The above 4GiB memory limit
30 OUT UINT64
*Below4GMemoryLimit
,
31 OUT UINT64
*Above4GMemoryLimit
35 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
36 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
37 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
38 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
39 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
40 UINTN EfiMemoryMapSize
;
42 UINTN EfiDescriptorSize
;
43 UINT32 EfiDescriptorVersion
;
44 UINT64 MemoryBlockLength
;
46 *Below4GMemoryLimit
= 0;
47 *Above4GMemoryLimit
= 0;
50 // Get the EFI memory map.
54 Status
= gBS
->GetMemoryMap (
61 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
65 // Use size returned back plus 1 descriptor for the AllocatePool.
66 // We don't just multiply by 2 since the "for" loop below terminates on
67 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
68 // we process bogus entries and create bogus E820 entries.
70 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
71 ASSERT (EfiMemoryMap
!= NULL
);
72 Status
= gBS
->GetMemoryMap (
79 if (EFI_ERROR (Status
)) {
80 FreePool (EfiMemoryMap
);
82 } while (Status
== EFI_BUFFER_TOO_SMALL
);
84 ASSERT_EFI_ERROR (Status
);
87 // Sort memory map from low to high
89 EfiEntry
= EfiMemoryMap
;
90 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
91 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
92 while (EfiEntry
< EfiMemoryMapEnd
) {
93 while (NextEfiEntry
< EfiMemoryMapEnd
) {
94 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
95 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
96 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
97 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
100 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
103 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
104 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
110 DEBUG ((DEBUG_INFO
, "MemoryMap:\n"));
111 EfiEntry
= EfiMemoryMap
;
112 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
113 while (EfiEntry
< EfiMemoryMapEnd
) {
114 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
115 DEBUG ((DEBUG_INFO
, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry
->Type
, EfiEntry
->PhysicalStart
, EfiEntry
->PhysicalStart
+ MemoryBlockLength
));
116 switch (EfiEntry
->Type
) {
119 case EfiBootServicesCode
:
120 case EfiBootServicesData
:
121 case EfiConventionalMemory
:
122 case EfiRuntimeServicesCode
:
123 case EfiRuntimeServicesData
:
124 case EfiACPIReclaimMemory
:
125 case EfiACPIMemoryNVS
:
126 case EfiReservedMemoryType
:
127 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) <= BASE_1MB
) {
129 // Skip the memory block is under 1MB
131 } else if (EfiEntry
->PhysicalStart
>= BASE_4GB
) {
132 if (*Above4GMemoryLimit
< EfiEntry
->PhysicalStart
+ MemoryBlockLength
) {
133 *Above4GMemoryLimit
= EfiEntry
->PhysicalStart
+ MemoryBlockLength
;
136 if (*Below4GMemoryLimit
< EfiEntry
->PhysicalStart
+ MemoryBlockLength
) {
137 *Below4GMemoryLimit
= EfiEntry
->PhysicalStart
+ MemoryBlockLength
;
142 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
145 FreePool (EfiMemoryMap
);
147 DEBUG ((DEBUG_INFO
, "Result:\n"));
148 DEBUG ((DEBUG_INFO
, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit
));
149 DEBUG ((DEBUG_INFO
, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit
));
155 The scan bus callback function to always enable page attribute.
157 @param[in] Context The context of the callback.
158 @param[in] Segment The segment of the source.
159 @param[in] Bus The bus of the source.
160 @param[in] Device The device of the source.
161 @param[in] Function The function of the source.
163 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
167 ScanBusCallbackAlwaysEnablePageAttribute (
175 VTD_SOURCE_ID SourceId
;
178 SourceId
.Bits
.Bus
= Bus
;
179 SourceId
.Bits
.Device
= Device
;
180 SourceId
.Bits
.Function
= Function
;
181 Status
= AlwaysEnablePageAttribute (Segment
, SourceId
);
186 Always enable the VTd page attribute for the device in the DeviceScope.
188 @param[in] DeviceScope the input device scope data structure
190 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
193 AlwaysEnablePageAttributeDeviceScope (
194 IN EDKII_PLATFORM_VTD_DEVICE_SCOPE
*DeviceScope
200 VTD_SOURCE_ID SourceId
;
201 UINT8 SecondaryBusNumber
;
204 Status
= GetPciBusDeviceFunction (DeviceScope
->SegmentNumber
, &DeviceScope
->DeviceScope
, &Bus
, &Device
, &Function
);
206 if (DeviceScope
->DeviceScope
.Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
) {
208 // Need scan the bridge and add all devices.
210 SecondaryBusNumber
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope
->SegmentNumber
, Bus
, Device
, Function
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
));
211 Status
= ScanPciBus (NULL
, DeviceScope
->SegmentNumber
, SecondaryBusNumber
, ScanBusCallbackAlwaysEnablePageAttribute
);
214 SourceId
.Bits
.Bus
= Bus
;
215 SourceId
.Bits
.Device
= Device
;
216 SourceId
.Bits
.Function
= Function
;
217 Status
= AlwaysEnablePageAttribute (DeviceScope
->SegmentNumber
, SourceId
);
223 Always enable the VTd page attribute for the device matching DeviceId.
225 @param[in] PciDeviceId the input PCI device ID
227 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.
230 AlwaysEnablePageAttributePciDeviceId (
231 IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID
*PciDeviceId
236 PCI_DEVICE_DATA
*PciDeviceData
;
239 for (VtdIndex
= 0; VtdIndex
< mVtdUnitNumber
; VtdIndex
++) {
240 for (PciIndex
= 0; PciIndex
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; PciIndex
++) {
241 PciDeviceData
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[PciIndex
];
243 if (((PciDeviceId
->VendorId
== 0xFFFF) || (PciDeviceId
->VendorId
== PciDeviceData
->PciDeviceId
.VendorId
)) &&
244 ((PciDeviceId
->DeviceId
== 0xFFFF) || (PciDeviceId
->DeviceId
== PciDeviceData
->PciDeviceId
.DeviceId
)) &&
245 ((PciDeviceId
->RevisionId
== 0xFF) || (PciDeviceId
->RevisionId
== PciDeviceData
->PciDeviceId
.RevisionId
)) &&
246 ((PciDeviceId
->SubsystemVendorId
== 0xFFFF) || (PciDeviceId
->SubsystemVendorId
== PciDeviceData
->PciDeviceId
.SubsystemVendorId
)) &&
247 ((PciDeviceId
->SubsystemDeviceId
== 0xFFFF) || (PciDeviceId
->SubsystemDeviceId
== PciDeviceData
->PciDeviceId
.SubsystemDeviceId
)) ) {
248 Status
= AlwaysEnablePageAttribute (mVtdUnitInformation
[VtdIndex
].Segment
, PciDeviceData
->PciSourceId
);
249 if (EFI_ERROR(Status
)) {
259 Always enable the VTd page attribute for the device.
261 @param[in] DeviceInfo the exception device information
263 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.
266 AlwaysEnablePageAttributeExceptionDeviceInfo (
267 IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO
*DeviceInfo
270 switch (DeviceInfo
->Type
) {
271 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE
:
272 return AlwaysEnablePageAttributeDeviceScope ((VOID
*)(DeviceInfo
+ 1));
273 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID
:
274 return AlwaysEnablePageAttributePciDeviceId ((VOID
*)(DeviceInfo
+ 1));
276 return EFI_UNSUPPORTED
;
281 Initialize platform VTd policy.
284 InitializePlatformVTdPolicy (
289 UINTN DeviceInfoCount
;
291 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO
*ThisDeviceInfo
;
297 Status
= gBS
->LocateProtocol (
298 &gEdkiiPlatformVTdPolicyProtocolGuid
,
300 (VOID
**)&mPlatformVTdPolicy
302 if (!EFI_ERROR(Status
)) {
303 DEBUG ((DEBUG_INFO
, "InitializePlatformVTdPolicy\n"));
304 Status
= mPlatformVTdPolicy
->GetExceptionDeviceList (mPlatformVTdPolicy
, &DeviceInfoCount
, &DeviceInfo
);
305 if (!EFI_ERROR(Status
)) {
306 ThisDeviceInfo
= DeviceInfo
;
307 for (Index
= 0; Index
< DeviceInfoCount
; Index
++) {
308 if (ThisDeviceInfo
->Type
== EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END
) {
311 AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo
);
312 ThisDeviceInfo
= (VOID
*)((UINTN
)ThisDeviceInfo
+ ThisDeviceInfo
->Length
);
314 FreePool (DeviceInfo
);
328 VOID
*PciEnumerationComplete
;
330 UINT64 Below4GMemoryLimit
;
331 UINT64 Above4GMemoryLimit
;
334 // PCI Enumeration must be done
336 Status
= gBS
->LocateProtocol (
337 &gEfiPciEnumerationCompleteProtocolGuid
,
339 &PciEnumerationComplete
341 ASSERT_EFI_ERROR (Status
);
343 ReturnUefiMemoryMap (&Below4GMemoryLimit
, &Above4GMemoryLimit
);
344 Below4GMemoryLimit
= ALIGN_VALUE_UP(Below4GMemoryLimit
, SIZE_256MB
);
345 DEBUG ((DEBUG_INFO
, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit
));
347 mBelow4GMemoryLimit
= Below4GMemoryLimit
;
348 mAbove4GMemoryLimit
= Above4GMemoryLimit
;
353 DEBUG ((DEBUG_INFO
, "GetDmarAcpiTable\n"));
354 Status
= GetDmarAcpiTable ();
355 if (EFI_ERROR (Status
)) {
358 DEBUG ((DEBUG_INFO
, "ParseDmarAcpiTable\n"));
359 Status
= ParseDmarAcpiTableDrhd ();
360 if (EFI_ERROR (Status
)) {
363 DEBUG ((DEBUG_INFO
, "PrepareVtdConfig\n"));
369 DEBUG ((DEBUG_INFO
, "SetupTranslationTable\n"));
370 Status
= SetupTranslationTable ();
371 if (EFI_ERROR (Status
)) {
375 InitializePlatformVTdPolicy ();
377 ParseDmarAcpiTableRmrr ();
379 for (Index
= 0; Index
< mVtdUnitNumber
; Index
++) {
380 DEBUG ((DEBUG_INFO
,"VTD Unit %d (Segment: %04x)\n", Index
, mVtdUnitInformation
[Index
].Segment
));
381 if (mVtdUnitInformation
[Index
].ExtRootEntryTable
!= NULL
) {
382 DumpDmarExtContextEntryTable (mVtdUnitInformation
[Index
].ExtRootEntryTable
);
384 if (mVtdUnitInformation
[Index
].RootEntryTable
!= NULL
) {
385 DumpDmarContextEntryTable (mVtdUnitInformation
[Index
].RootEntryTable
);
392 DEBUG ((DEBUG_INFO
, "EnableDmar\n"));
393 Status
= EnableDmar ();
394 if (EFI_ERROR (Status
)) {
397 DEBUG ((DEBUG_INFO
, "DumpVtdRegs\n"));
402 ACPI notification function.
404 @param[in] Table A pointer to the ACPI table header.
405 @param[in] Version The ACPI table's version.
406 @param[in] TableKey The table key for this ACPI table.
408 @retval EFI_SUCCESS The notification function is executed.
412 AcpiNotificationFunc (
413 IN EFI_ACPI_SDT_HEADER
*Table
,
414 IN EFI_ACPI_TABLE_VERSION Version
,
418 if (Table
->Signature
== EFI_ACPI_4_0_DMA_REMAPPING_TABLE_SIGNATURE
) {
419 DEBUG((DEBUG_INFO
, "Vtd AcpiNotificationFunc\n"));
426 Exit boot service callback function.
428 @param[in] Event The event handle.
429 @param[in] Context The event content.
438 DEBUG ((DEBUG_INFO
, "Vtd OnExitBootServices\n"));
445 Legacy boot callback function.
447 @param[in] Event The event handle.
448 @param[in] Context The event content.
457 DEBUG ((DEBUG_INFO
, "Vtd OnLegacyBoot\n"));
464 Initialize DMA protection.
467 InitializeDmaProtection (
472 EFI_EVENT ExitBootServicesEvent
;
473 EFI_EVENT LegacyBootEvent
;
475 Status
= gBS
->LocateProtocol (&gEfiAcpiSdtProtocolGuid
, NULL
, (VOID
**) &mAcpiSdt
);
476 ASSERT_EFI_ERROR (Status
);
478 Status
= mAcpiSdt
->RegisterNotify (TRUE
, AcpiNotificationFunc
);
479 ASSERT_EFI_ERROR (Status
);
481 Status
= gBS
->CreateEventEx (
486 &gEfiEventExitBootServicesGuid
,
487 &ExitBootServicesEvent
489 ASSERT_EFI_ERROR (Status
);
491 Status
= EfiCreateEventLegacyBootEx (
497 ASSERT_EFI_ERROR (Status
);