3 Copyright (c) 2017 - 2018, 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 UINT64 mBelow4GMemoryLimit
;
17 UINT64 mAbove4GMemoryLimit
;
19 EDKII_PLATFORM_VTD_POLICY_PROTOCOL
*mPlatformVTdPolicy
;
22 return the UEFI memory information.
24 @param[out] Below4GMemoryLimit The below 4GiB memory limit
25 @param[out] Above4GMemoryLimit The above 4GiB memory limit
29 OUT UINT64
*Below4GMemoryLimit
,
30 OUT UINT64
*Above4GMemoryLimit
34 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
35 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
36 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
37 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
38 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
39 UINTN EfiMemoryMapSize
;
41 UINTN EfiDescriptorSize
;
42 UINT32 EfiDescriptorVersion
;
43 UINT64 MemoryBlockLength
;
45 *Below4GMemoryLimit
= 0;
46 *Above4GMemoryLimit
= 0;
49 // Get the EFI memory map.
53 Status
= gBS
->GetMemoryMap (
60 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
64 // Use size returned back plus 1 descriptor for the AllocatePool.
65 // We don't just multiply by 2 since the "for" loop below terminates on
66 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
67 // we process bogus entries and create bogus E820 entries.
69 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
70 ASSERT (EfiMemoryMap
!= NULL
);
71 Status
= gBS
->GetMemoryMap (
78 if (EFI_ERROR (Status
)) {
79 FreePool (EfiMemoryMap
);
81 } while (Status
== EFI_BUFFER_TOO_SMALL
);
83 ASSERT_EFI_ERROR (Status
);
86 // Sort memory map from low to high
88 EfiEntry
= EfiMemoryMap
;
89 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
90 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
91 while (EfiEntry
< EfiMemoryMapEnd
) {
92 while (NextEfiEntry
< EfiMemoryMapEnd
) {
93 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
94 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
95 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
96 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
99 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
102 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
103 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
109 DEBUG ((DEBUG_INFO
, "MemoryMap:\n"));
110 EfiEntry
= EfiMemoryMap
;
111 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
112 while (EfiEntry
< EfiMemoryMapEnd
) {
113 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
114 DEBUG ((DEBUG_INFO
, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry
->Type
, EfiEntry
->PhysicalStart
, EfiEntry
->PhysicalStart
+ MemoryBlockLength
));
115 switch (EfiEntry
->Type
) {
118 case EfiBootServicesCode
:
119 case EfiBootServicesData
:
120 case EfiConventionalMemory
:
121 case EfiRuntimeServicesCode
:
122 case EfiRuntimeServicesData
:
123 case EfiACPIReclaimMemory
:
124 case EfiACPIMemoryNVS
:
125 case EfiReservedMemoryType
:
126 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) <= BASE_1MB
) {
128 // Skip the memory block is under 1MB
130 } else if (EfiEntry
->PhysicalStart
>= BASE_4GB
) {
131 if (*Above4GMemoryLimit
< EfiEntry
->PhysicalStart
+ MemoryBlockLength
) {
132 *Above4GMemoryLimit
= EfiEntry
->PhysicalStart
+ MemoryBlockLength
;
135 if (*Below4GMemoryLimit
< EfiEntry
->PhysicalStart
+ MemoryBlockLength
) {
136 *Below4GMemoryLimit
= EfiEntry
->PhysicalStart
+ MemoryBlockLength
;
141 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
144 FreePool (EfiMemoryMap
);
146 DEBUG ((DEBUG_INFO
, "Result:\n"));
147 DEBUG ((DEBUG_INFO
, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit
));
148 DEBUG ((DEBUG_INFO
, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit
));
154 The scan bus callback function to always enable page attribute.
156 @param[in] Context The context of the callback.
157 @param[in] Segment The segment of the source.
158 @param[in] Bus The bus of the source.
159 @param[in] Device The device of the source.
160 @param[in] Function The function of the source.
162 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
166 ScanBusCallbackAlwaysEnablePageAttribute (
174 VTD_SOURCE_ID SourceId
;
177 SourceId
.Bits
.Bus
= Bus
;
178 SourceId
.Bits
.Device
= Device
;
179 SourceId
.Bits
.Function
= Function
;
180 Status
= AlwaysEnablePageAttribute (Segment
, SourceId
);
185 Always enable the VTd page attribute for the device in the DeviceScope.
187 @param[in] DeviceScope the input device scope data structure
189 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
192 AlwaysEnablePageAttributeDeviceScope (
193 IN EDKII_PLATFORM_VTD_DEVICE_SCOPE
*DeviceScope
199 VTD_SOURCE_ID SourceId
;
200 UINT8 SecondaryBusNumber
;
203 Status
= GetPciBusDeviceFunction (DeviceScope
->SegmentNumber
, &DeviceScope
->DeviceScope
, &Bus
, &Device
, &Function
);
205 if (DeviceScope
->DeviceScope
.Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
) {
207 // Need scan the bridge and add all devices.
209 SecondaryBusNumber
= PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope
->SegmentNumber
, Bus
, Device
, Function
, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET
));
210 Status
= ScanPciBus (NULL
, DeviceScope
->SegmentNumber
, SecondaryBusNumber
, ScanBusCallbackAlwaysEnablePageAttribute
);
213 SourceId
.Bits
.Bus
= Bus
;
214 SourceId
.Bits
.Device
= Device
;
215 SourceId
.Bits
.Function
= Function
;
216 Status
= AlwaysEnablePageAttribute (DeviceScope
->SegmentNumber
, SourceId
);
222 Always enable the VTd page attribute for the device matching DeviceId.
224 @param[in] PciDeviceId the input PCI device ID
226 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.
229 AlwaysEnablePageAttributePciDeviceId (
230 IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID
*PciDeviceId
235 PCI_DEVICE_DATA
*PciDeviceData
;
238 for (VtdIndex
= 0; VtdIndex
< mVtdUnitNumber
; VtdIndex
++) {
239 for (PciIndex
= 0; PciIndex
< mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceDataNumber
; PciIndex
++) {
240 PciDeviceData
= &mVtdUnitInformation
[VtdIndex
].PciDeviceInfo
.PciDeviceData
[PciIndex
];
242 if (((PciDeviceId
->VendorId
== 0xFFFF) || (PciDeviceId
->VendorId
== PciDeviceData
->PciDeviceId
.VendorId
)) &&
243 ((PciDeviceId
->DeviceId
== 0xFFFF) || (PciDeviceId
->DeviceId
== PciDeviceData
->PciDeviceId
.DeviceId
)) &&
244 ((PciDeviceId
->RevisionId
== 0xFF) || (PciDeviceId
->RevisionId
== PciDeviceData
->PciDeviceId
.RevisionId
)) &&
245 ((PciDeviceId
->SubsystemVendorId
== 0xFFFF) || (PciDeviceId
->SubsystemVendorId
== PciDeviceData
->PciDeviceId
.SubsystemVendorId
)) &&
246 ((PciDeviceId
->SubsystemDeviceId
== 0xFFFF) || (PciDeviceId
->SubsystemDeviceId
== PciDeviceData
->PciDeviceId
.SubsystemDeviceId
)) ) {
247 Status
= AlwaysEnablePageAttribute (mVtdUnitInformation
[VtdIndex
].Segment
, PciDeviceData
->PciSourceId
);
248 if (EFI_ERROR(Status
)) {
258 Always enable the VTd page attribute for the device.
260 @param[in] DeviceInfo the exception device information
262 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.
265 AlwaysEnablePageAttributeExceptionDeviceInfo (
266 IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO
*DeviceInfo
269 switch (DeviceInfo
->Type
) {
270 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE
:
271 return AlwaysEnablePageAttributeDeviceScope ((VOID
*)(DeviceInfo
+ 1));
272 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID
:
273 return AlwaysEnablePageAttributePciDeviceId ((VOID
*)(DeviceInfo
+ 1));
275 return EFI_UNSUPPORTED
;
280 Initialize platform VTd policy.
283 InitializePlatformVTdPolicy (
288 UINTN DeviceInfoCount
;
290 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO
*ThisDeviceInfo
;
296 Status
= gBS
->LocateProtocol (
297 &gEdkiiPlatformVTdPolicyProtocolGuid
,
299 (VOID
**)&mPlatformVTdPolicy
301 if (!EFI_ERROR(Status
)) {
302 DEBUG ((DEBUG_INFO
, "InitializePlatformVTdPolicy\n"));
303 Status
= mPlatformVTdPolicy
->GetExceptionDeviceList (mPlatformVTdPolicy
, &DeviceInfoCount
, &DeviceInfo
);
304 if (!EFI_ERROR(Status
)) {
305 ThisDeviceInfo
= DeviceInfo
;
306 for (Index
= 0; Index
< DeviceInfoCount
; Index
++) {
307 if (ThisDeviceInfo
->Type
== EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END
) {
310 AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo
);
311 ThisDeviceInfo
= (VOID
*)((UINTN
)ThisDeviceInfo
+ ThisDeviceInfo
->Length
);
313 FreePool (DeviceInfo
);
327 VOID
*PciEnumerationComplete
;
329 UINT64 Below4GMemoryLimit
;
330 UINT64 Above4GMemoryLimit
;
333 // PCI Enumeration must be done
335 Status
= gBS
->LocateProtocol (
336 &gEfiPciEnumerationCompleteProtocolGuid
,
338 &PciEnumerationComplete
340 ASSERT_EFI_ERROR (Status
);
342 ReturnUefiMemoryMap (&Below4GMemoryLimit
, &Above4GMemoryLimit
);
343 Below4GMemoryLimit
= ALIGN_VALUE_UP(Below4GMemoryLimit
, SIZE_256MB
);
344 DEBUG ((DEBUG_INFO
, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit
));
346 mBelow4GMemoryLimit
= Below4GMemoryLimit
;
347 mAbove4GMemoryLimit
= Above4GMemoryLimit
;
352 DEBUG ((DEBUG_INFO
, "ParseDmarAcpiTable\n"));
353 Status
= ParseDmarAcpiTableDrhd ();
354 if (EFI_ERROR (Status
)) {
357 DEBUG ((DEBUG_INFO
, "PrepareVtdConfig\n"));
363 DEBUG ((DEBUG_INFO
, "SetupTranslationTable\n"));
364 Status
= SetupTranslationTable ();
365 if (EFI_ERROR (Status
)) {
369 InitializePlatformVTdPolicy ();
371 ParseDmarAcpiTableRmrr ();
373 for (Index
= 0; Index
< mVtdUnitNumber
; Index
++) {
374 DEBUG ((DEBUG_INFO
,"VTD Unit %d (Segment: %04x)\n", Index
, mVtdUnitInformation
[Index
].Segment
));
375 if (mVtdUnitInformation
[Index
].ExtRootEntryTable
!= NULL
) {
376 DumpDmarExtContextEntryTable (mVtdUnitInformation
[Index
].ExtRootEntryTable
);
378 if (mVtdUnitInformation
[Index
].RootEntryTable
!= NULL
) {
379 DumpDmarContextEntryTable (mVtdUnitInformation
[Index
].RootEntryTable
);
386 DEBUG ((DEBUG_INFO
, "EnableDmar\n"));
387 Status
= EnableDmar ();
388 if (EFI_ERROR (Status
)) {
391 DEBUG ((DEBUG_INFO
, "DumpVtdRegs\n"));
396 Notification function of ACPI Table change.
398 This is a notification function registered on ACPI Table change event.
400 @param Event Event whose notification function is being invoked.
401 @param Context Pointer to the notification function's context.
406 AcpiNotificationFunc (
413 Status
= GetDmarAcpiTable ();
414 if (EFI_ERROR (Status
)) {
415 if (Status
== EFI_ALREADY_STARTED
) {
416 gBS
->CloseEvent (Event
);
421 gBS
->CloseEvent (Event
);
425 Exit boot service callback function.
427 @param[in] Event The event handle.
428 @param[in] Context The event content.
437 DEBUG ((DEBUG_INFO
, "Vtd OnExitBootServices\n"));
440 if ((PcdGet8(PcdVTdPolicyPropertyMask
) & BIT1
) == 0) {
447 Legacy boot callback function.
449 @param[in] Event The event handle.
450 @param[in] Context The event content.
459 DEBUG ((DEBUG_INFO
, "Vtd OnLegacyBoot\n"));
466 Initialize DMA protection.
469 InitializeDmaProtection (
474 EFI_EVENT ExitBootServicesEvent
;
475 EFI_EVENT LegacyBootEvent
;
476 EFI_EVENT EventAcpi10
;
477 EFI_EVENT EventAcpi20
;
479 Status
= gBS
->CreateEventEx (
482 AcpiNotificationFunc
,
484 &gEfiAcpi10TableGuid
,
487 ASSERT_EFI_ERROR (Status
);
489 Status
= gBS
->CreateEventEx (
492 AcpiNotificationFunc
,
494 &gEfiAcpi20TableGuid
,
497 ASSERT_EFI_ERROR (Status
);
500 // Signal the events initially for the case
501 // that DMAR table has been installed.
503 gBS
->SignalEvent (EventAcpi20
);
504 gBS
->SignalEvent (EventAcpi10
);
506 Status
= gBS
->CreateEventEx (
511 &gEfiEventExitBootServicesGuid
,
512 &ExitBootServicesEvent
514 ASSERT_EFI_ERROR (Status
);
516 Status
= EfiCreateEventLegacyBootEx (
522 ASSERT_EFI_ERROR (Status
);