3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/HobLib.h>
14 #include <IndustryStandard/Vtd.h>
15 #include <Ppi/VtdInfo.h>
17 #include "IntelVTdPmrPei.h"
20 Dump DMAR DeviceScopeEntry.
22 @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
25 DumpDmarDeviceScopeEntry (
26 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
31 EFI_ACPI_DMAR_PCI_PATH
*PciPath
;
33 if (DmarDeviceScopeEntry
== NULL
) {
38 " *************************************************************************\n"
41 " * DMA-Remapping Device Scope Entry Structure *\n"
44 " *************************************************************************\n"
47 (sizeof(UINTN
) == sizeof(UINT64
)) ?
48 " DMAR Device Scope Entry address ...................... 0x%016lx\n" :
49 " DMAR Device Scope Entry address ...................... 0x%08x\n",
53 " Device Scope Entry Type ............................ 0x%02x\n",
54 DmarDeviceScopeEntry
->Type
56 switch (DmarDeviceScopeEntry
->Type
) {
57 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
:
59 " PCI Endpoint Device\n"
62 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
:
71 " Length ............................................. 0x%02x\n",
72 DmarDeviceScopeEntry
->Length
75 " Enumeration ID ..................................... 0x%02x\n",
76 DmarDeviceScopeEntry
->EnumerationId
79 " Starting Bus Number ................................ 0x%02x\n",
80 DmarDeviceScopeEntry
->StartBusNumber
83 PciPathNumber
= (DmarDeviceScopeEntry
->Length
- sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
)) / sizeof(EFI_ACPI_DMAR_PCI_PATH
);
84 PciPath
= (EFI_ACPI_DMAR_PCI_PATH
*)(DmarDeviceScopeEntry
+ 1);
85 for (PciPathIndex
= 0; PciPathIndex
< PciPathNumber
; PciPathIndex
++) {
87 " Device ............................................. 0x%02x\n",
88 PciPath
[PciPathIndex
].Device
91 " Function ........................................... 0x%02x\n",
92 PciPath
[PciPathIndex
].Function
97 " *************************************************************************\n\n"
104 Dump DMAR RMRR table.
106 @param[in] Rmrr DMAR RMRR table
110 IN EFI_ACPI_DMAR_RMRR_HEADER
*Rmrr
113 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
121 " ***************************************************************************\n"
124 " * Reserved Memory Region Reporting Structure *\n"
127 " ***************************************************************************\n"
130 (sizeof(UINTN
) == sizeof(UINT64
)) ?
131 " RMRR address ........................................... 0x%016lx\n" :
132 " RMRR address ........................................... 0x%08x\n",
136 " Type ................................................. 0x%04x\n",
140 " Length ............................................... 0x%04x\n",
144 " Segment Number ....................................... 0x%04x\n",
148 " Reserved Memory Region Base Address .................. 0x%016lx\n",
149 Rmrr
->ReservedMemoryRegionBaseAddress
152 " Reserved Memory Region Limit Address ................. 0x%016lx\n",
153 Rmrr
->ReservedMemoryRegionLimitAddress
156 RmrrLen
= Rmrr
->Header
.Length
- sizeof(EFI_ACPI_DMAR_RMRR_HEADER
);
157 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Rmrr
+ 1);
158 while (RmrrLen
> 0) {
159 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
160 RmrrLen
-= DmarDeviceScopeEntry
->Length
;
161 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
165 " ***************************************************************************\n\n"
172 Dump DMAR DRHD table.
174 @param[in] Drhd DMAR DRHD table
178 IN EFI_ACPI_DMAR_DRHD_HEADER
*Drhd
181 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
189 " ***************************************************************************\n"
192 " * DMA-Remapping Hardware Definition Structure *\n"
195 " ***************************************************************************\n"
198 (sizeof(UINTN
) == sizeof(UINT64
)) ?
199 " DRHD address ........................................... 0x%016lx\n" :
200 " DRHD address ........................................... 0x%08x\n",
204 " Type ................................................. 0x%04x\n",
208 " Length ............................................... 0x%04x\n",
212 " Flags ................................................ 0x%02x\n",
216 " INCLUDE_PCI_ALL .................................... 0x%02x\n",
217 Drhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
220 " Segment Number ....................................... 0x%04x\n",
224 " Register Base Address ................................ 0x%016lx\n",
225 Drhd
->RegisterBaseAddress
228 DrhdLen
= Drhd
->Header
.Length
- sizeof(EFI_ACPI_DMAR_DRHD_HEADER
);
229 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Drhd
+ 1);
230 while (DrhdLen
> 0) {
231 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
232 DrhdLen
-= DmarDeviceScopeEntry
->Length
;
233 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
237 " ***************************************************************************\n\n"
244 Dump DMAR ACPI table.
246 @param[in] Dmar DMAR ACPI table
250 IN EFI_ACPI_DMAR_HEADER
*Dmar
253 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
264 "*****************************************************************************\n"
270 "*****************************************************************************\n"
274 (sizeof(UINTN
) == sizeof(UINT64
)) ?
275 "DMAR address ............................................. 0x%016lx\n" :
276 "DMAR address ............................................. 0x%08x\n",
284 " Host Address Width ................................... 0x%02x\n",
285 Dmar
->HostAddressWidth
288 " Flags ................................................ 0x%02x\n",
292 " INTR_REMAP ......................................... 0x%02x\n",
293 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_INTR_REMAP
296 " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
297 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
300 " DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
301 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
304 DmarLen
= Dmar
->Header
.Length
- sizeof(EFI_ACPI_DMAR_HEADER
);
305 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)(Dmar
+ 1);
306 while (DmarLen
> 0) {
307 switch (DmarHeader
->Type
) {
308 case EFI_ACPI_DMAR_TYPE_DRHD
:
309 DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
311 case EFI_ACPI_DMAR_TYPE_RMRR
:
312 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
317 DmarLen
-= DmarHeader
->Length
;
318 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
322 "*****************************************************************************\n\n"
329 Get VTd engine number.
331 @param[in] AcpiDmarTable DMAR ACPI table
333 @return the VTd engine number.
337 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
340 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
344 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
345 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
346 switch (DmarHeader
->Type
) {
347 case EFI_ACPI_DMAR_TYPE_DRHD
:
353 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
359 Process DMAR DHRD table.
361 @param[in] VTdInfo The VTd engine context information.
362 @param[in] VtdIndex The index of VTd engine.
363 @param[in] DmarDrhd The DRHD table.
367 IN VTD_INFO
*VTdInfo
,
369 IN EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
372 DEBUG ((DEBUG_INFO
," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex
, DmarDrhd
->RegisterBaseAddress
));
373 VTdInfo
->VTdEngineAddress
[VtdIndex
] = DmarDrhd
->RegisterBaseAddress
;
377 Parse DMAR DRHD table.
379 @param[in] AcpiDmarTable DMAR ACPI table
381 @return EFI_SUCCESS The DMAR DRHD table is parsed.
384 ParseDmarAcpiTableDrhd (
385 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
388 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
393 VtdUnitNumber
= GetVtdEngineNumber (AcpiDmarTable
);
394 if (VtdUnitNumber
== 0) {
395 return EFI_UNSUPPORTED
;
398 VTdInfo
= BuildGuidHob (&mVTdInfoGuid
, sizeof(VTD_INFO
) + (VtdUnitNumber
- 1) * sizeof(UINT64
));
399 ASSERT(VTdInfo
!= NULL
);
400 if (VTdInfo
== NULL
) {
401 return EFI_OUT_OF_RESOURCES
;
405 // Initialize the engine mask to all.
407 VTdInfo
->AcpiDmarTable
= AcpiDmarTable
;
408 VTdInfo
->EngineMask
= LShiftU64 (1, VtdUnitNumber
) - 1;
409 VTdInfo
->HostAddressWidth
= AcpiDmarTable
->HostAddressWidth
;
410 VTdInfo
->VTdEngineCount
= VtdUnitNumber
;
413 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
414 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
415 switch (DmarHeader
->Type
) {
416 case EFI_ACPI_DMAR_TYPE_DRHD
:
417 ASSERT (VtdIndex
< VtdUnitNumber
);
418 ProcessDhrd (VTdInfo
, VtdIndex
, (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
426 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
428 ASSERT (VtdIndex
== VtdUnitNumber
);
434 Return the VTd engine index according to the Segment and DevScopeEntry.
436 @param AcpiDmarTable DMAR ACPI table
437 @param Segment The segment of the VTd engine
438 @param DevScopeEntry The DevScopeEntry of the VTd engine
440 @return The VTd engine index according to the Segment and DevScopeEntry.
441 @retval -1 The VTd engine is not found.
444 GetVTdEngineFromDevScopeEntry (
445 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
,
447 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DevScopeEntry
450 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
452 EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
;
453 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*ThisDevScopeEntry
;
456 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
457 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
458 switch (DmarHeader
->Type
) {
459 case EFI_ACPI_DMAR_TYPE_DRHD
:
460 DmarDrhd
= (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
;
461 if (DmarDrhd
->SegmentNumber
!= Segment
) {
465 if ((DmarDrhd
->Header
.Length
== sizeof(EFI_ACPI_DMAR_DRHD_HEADER
)) ||
466 ((DmarDrhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
) != 0)) {
468 // Do not handle PCI_ALL
471 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarDrhd
+ 1));
472 while ((UINTN
)ThisDevScopeEntry
< (UINTN
)DmarDrhd
+ DmarDrhd
->Header
.Length
) {
473 if ((ThisDevScopeEntry
->Length
== DevScopeEntry
->Length
) &&
474 (CompareMem (ThisDevScopeEntry
, DevScopeEntry
, DevScopeEntry
->Length
) == 0)) {
477 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)ThisDevScopeEntry
+ ThisDevScopeEntry
->Length
);
483 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
489 Process DMAR RMRR table.
491 @param[in] VTdInfo The VTd engine context information.
492 @param[in] DmarRmrr The RMRR table.
496 IN VTD_INFO
*VTdInfo
,
497 IN EFI_ACPI_DMAR_RMRR_HEADER
*DmarRmrr
500 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDevScopeEntry
;
507 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
509 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
511 DEBUG ((DEBUG_INFO
," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr
->ReservedMemoryRegionBaseAddress
, DmarRmrr
->ReservedMemoryRegionLimitAddress
));
513 if ((DmarRmrr
->ReservedMemoryRegionBaseAddress
== 0) ||
514 (DmarRmrr
->ReservedMemoryRegionLimitAddress
== 0)) {
518 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarRmrr
+ 1));
519 while ((UINTN
)DmarDevScopeEntry
< (UINTN
)DmarRmrr
+ DmarRmrr
->Header
.Length
) {
520 ASSERT (DmarDevScopeEntry
->Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
);
522 VTdIndex
= GetVTdEngineFromDevScopeEntry (AcpiDmarTable
, DmarRmrr
->SegmentNumber
, DmarDevScopeEntry
);
523 if (VTdIndex
!= (UINTN
)-1) {
524 RmrrMask
= LShiftU64 (1, VTdIndex
);
527 LowTop
= (UINTN
)DmarRmrr
->ReservedMemoryRegionBaseAddress
;
528 HighBottom
= (UINTN
)DmarRmrr
->ReservedMemoryRegionLimitAddress
+ 1;
529 HighTop
= LShiftU64 (1, VTdInfo
->HostAddressWidth
+ 1);
531 SetDmaProtectedRange (
535 (UINT32
)(LowTop
- LowBottom
),
541 // Remove the engine from the engine mask.
542 // The assumption is that any other PEI driver does not access
543 // the device covered by this engine.
545 VTdInfo
->EngineMask
= VTdInfo
->EngineMask
& (~RmrrMask
);
548 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDevScopeEntry
+ DmarDevScopeEntry
->Length
);
553 Parse DMAR DRHD table.
555 @param[in] VTdInfo The VTd engine context information.
558 ParseDmarAcpiTableRmrr (
562 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
563 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
565 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
567 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
568 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
569 switch (DmarHeader
->Type
) {
570 case EFI_ACPI_DMAR_TYPE_RMRR
:
571 ProcessRmrr (VTdInfo
, (EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
576 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);