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.
16 #include <Library/BaseLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/HobLib.h>
20 #include <IndustryStandard/Vtd.h>
21 #include <Ppi/VtdInfo.h>
23 #include "IntelVTdPmrPei.h"
26 Dump DMAR DeviceScopeEntry.
28 @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
31 DumpDmarDeviceScopeEntry (
32 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
37 EFI_ACPI_DMAR_PCI_PATH
*PciPath
;
39 if (DmarDeviceScopeEntry
== NULL
) {
44 " *************************************************************************\n"
47 " * DMA-Remapping Device Scope Entry Structure *\n"
50 " *************************************************************************\n"
53 (sizeof(UINTN
) == sizeof(UINT64
)) ?
54 " DMAR Device Scope Entry address ...................... 0x%016lx\n" :
55 " DMAR Device Scope Entry address ...................... 0x%08x\n",
59 " Device Scope Entry Type ............................ 0x%02x\n",
60 DmarDeviceScopeEntry
->Type
62 switch (DmarDeviceScopeEntry
->Type
) {
63 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
:
65 " PCI Endpoint Device\n"
68 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE
:
77 " Length ............................................. 0x%02x\n",
78 DmarDeviceScopeEntry
->Length
81 " Enumeration ID ..................................... 0x%02x\n",
82 DmarDeviceScopeEntry
->EnumerationId
85 " Starting Bus Number ................................ 0x%02x\n",
86 DmarDeviceScopeEntry
->StartBusNumber
89 PciPathNumber
= (DmarDeviceScopeEntry
->Length
- sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
)) / sizeof(EFI_ACPI_DMAR_PCI_PATH
);
90 PciPath
= (EFI_ACPI_DMAR_PCI_PATH
*)(DmarDeviceScopeEntry
+ 1);
91 for (PciPathIndex
= 0; PciPathIndex
< PciPathNumber
; PciPathIndex
++) {
93 " Device ............................................. 0x%02x\n",
94 PciPath
[PciPathIndex
].Device
97 " Function ........................................... 0x%02x\n",
98 PciPath
[PciPathIndex
].Function
103 " *************************************************************************\n\n"
110 Dump DMAR RMRR table.
112 @param[in] Rmrr DMAR RMRR table
116 IN EFI_ACPI_DMAR_RMRR_HEADER
*Rmrr
119 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
127 " ***************************************************************************\n"
130 " * Reserved Memory Region Reporting Structure *\n"
133 " ***************************************************************************\n"
136 (sizeof(UINTN
) == sizeof(UINT64
)) ?
137 " RMRR address ........................................... 0x%016lx\n" :
138 " RMRR address ........................................... 0x%08x\n",
142 " Type ................................................. 0x%04x\n",
146 " Length ............................................... 0x%04x\n",
150 " Segment Number ....................................... 0x%04x\n",
154 " Reserved Memory Region Base Address .................. 0x%016lx\n",
155 Rmrr
->ReservedMemoryRegionBaseAddress
158 " Reserved Memory Region Limit Address ................. 0x%016lx\n",
159 Rmrr
->ReservedMemoryRegionLimitAddress
162 RmrrLen
= Rmrr
->Header
.Length
- sizeof(EFI_ACPI_DMAR_RMRR_HEADER
);
163 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Rmrr
+ 1);
164 while (RmrrLen
> 0) {
165 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
166 RmrrLen
-= DmarDeviceScopeEntry
->Length
;
167 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
171 " ***************************************************************************\n\n"
178 Dump DMAR DRHD table.
180 @param[in] Drhd DMAR DRHD table
184 IN EFI_ACPI_DMAR_DRHD_HEADER
*Drhd
187 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDeviceScopeEntry
;
195 " ***************************************************************************\n"
198 " * DMA-Remapping Hardware Definition Structure *\n"
201 " ***************************************************************************\n"
204 (sizeof(UINTN
) == sizeof(UINT64
)) ?
205 " DRHD address ........................................... 0x%016lx\n" :
206 " DRHD address ........................................... 0x%08x\n",
210 " Type ................................................. 0x%04x\n",
214 " Length ............................................... 0x%04x\n",
218 " Flags ................................................ 0x%02x\n",
222 " INCLUDE_PCI_ALL .................................... 0x%02x\n",
223 Drhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
226 " Segment Number ....................................... 0x%04x\n",
230 " Register Base Address ................................ 0x%016lx\n",
231 Drhd
->RegisterBaseAddress
234 DrhdLen
= Drhd
->Header
.Length
- sizeof(EFI_ACPI_DMAR_DRHD_HEADER
);
235 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)(Drhd
+ 1);
236 while (DrhdLen
> 0) {
237 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry
);
238 DrhdLen
-= DmarDeviceScopeEntry
->Length
;
239 DmarDeviceScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDeviceScopeEntry
+ DmarDeviceScopeEntry
->Length
);
243 " ***************************************************************************\n\n"
250 Dump DMAR ACPI table.
252 @param[in] Dmar DMAR ACPI table
256 IN EFI_ACPI_DMAR_HEADER
*Dmar
259 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
270 "*****************************************************************************\n"
276 "*****************************************************************************\n"
280 (sizeof(UINTN
) == sizeof(UINT64
)) ?
281 "DMAR address ............................................. 0x%016lx\n" :
282 "DMAR address ............................................. 0x%08x\n",
290 " Host Address Width ................................... 0x%02x\n",
291 Dmar
->HostAddressWidth
294 " Flags ................................................ 0x%02x\n",
298 " INTR_REMAP ......................................... 0x%02x\n",
299 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_INTR_REMAP
302 " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
303 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
306 DmarLen
= Dmar
->Header
.Length
- sizeof(EFI_ACPI_DMAR_HEADER
);
307 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)(Dmar
+ 1);
308 while (DmarLen
> 0) {
309 switch (DmarHeader
->Type
) {
310 case EFI_ACPI_DMAR_TYPE_DRHD
:
311 DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
313 case EFI_ACPI_DMAR_TYPE_RMRR
:
314 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
319 DmarLen
-= DmarHeader
->Length
;
320 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
324 "*****************************************************************************\n\n"
331 Get VTd engine number.
333 @param[in] AcpiDmarTable DMAR ACPI table
335 @return the VTd engine number.
339 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
342 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
346 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
347 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
348 switch (DmarHeader
->Type
) {
349 case EFI_ACPI_DMAR_TYPE_DRHD
:
355 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
361 Process DMAR DHRD table.
363 @param[in] VTdInfo The VTd engine context information.
364 @param[in] VtdIndex The index of VTd engine.
365 @param[in] DmarDrhd The DRHD table.
369 IN VTD_INFO
*VTdInfo
,
371 IN EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
374 DEBUG ((DEBUG_INFO
," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex
, DmarDrhd
->RegisterBaseAddress
));
375 VTdInfo
->VTdEngineAddress
[VtdIndex
] = DmarDrhd
->RegisterBaseAddress
;
379 Parse DMAR DRHD table.
381 @param[in] AcpiDmarTable DMAR ACPI table
383 @return EFI_SUCCESS The DMAR DRHD table is parsed.
386 ParseDmarAcpiTableDrhd (
387 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
390 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
395 VtdUnitNumber
= GetVtdEngineNumber (AcpiDmarTable
);
396 if (VtdUnitNumber
== 0) {
397 return EFI_UNSUPPORTED
;
400 VTdInfo
= BuildGuidHob (&mVTdInfoGuid
, sizeof(VTD_INFO
) + (VtdUnitNumber
- 1) * sizeof(UINT64
));
401 ASSERT(VTdInfo
!= NULL
);
402 if (VTdInfo
== NULL
) {
403 return EFI_OUT_OF_RESOURCES
;
407 // Initialize the engine mask to all.
409 VTdInfo
->AcpiDmarTable
= AcpiDmarTable
;
410 VTdInfo
->EngineMask
= LShiftU64 (1, VtdUnitNumber
) - 1;
411 VTdInfo
->HostAddressWidth
= AcpiDmarTable
->HostAddressWidth
;
412 VTdInfo
->VTdEngineCount
= VtdUnitNumber
;
415 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
416 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
417 switch (DmarHeader
->Type
) {
418 case EFI_ACPI_DMAR_TYPE_DRHD
:
419 ASSERT (VtdIndex
< VtdUnitNumber
);
420 ProcessDhrd (VTdInfo
, VtdIndex
, (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
428 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
430 ASSERT (VtdIndex
== VtdUnitNumber
);
436 Return the VTd engine index according to the Segment and DevScopeEntry.
438 @param AcpiDmarTable DMAR ACPI table
439 @param Segment The segment of the VTd engine
440 @param DevScopeEntry The DevScopeEntry of the VTd engine
442 @return The VTd engine index according to the Segment and DevScopeEntry.
443 @retval -1 The VTd engine is not found.
446 GetVTdEngineFromDevScopeEntry (
447 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
,
449 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DevScopeEntry
452 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
454 EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
;
455 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*ThisDevScopeEntry
;
458 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
459 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
460 switch (DmarHeader
->Type
) {
461 case EFI_ACPI_DMAR_TYPE_DRHD
:
462 DmarDrhd
= (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
;
463 if (DmarDrhd
->SegmentNumber
!= Segment
) {
467 if ((DmarDrhd
->Header
.Length
== sizeof(EFI_ACPI_DMAR_DRHD_HEADER
)) ||
468 ((DmarDrhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
) != 0)) {
470 // Do not handle PCI_ALL
473 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarDrhd
+ 1));
474 while ((UINTN
)ThisDevScopeEntry
< (UINTN
)DmarDrhd
+ DmarDrhd
->Header
.Length
) {
475 if ((ThisDevScopeEntry
->Length
== DevScopeEntry
->Length
) &&
476 (CompareMem (ThisDevScopeEntry
, DevScopeEntry
, DevScopeEntry
->Length
) == 0)) {
479 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)ThisDevScopeEntry
+ ThisDevScopeEntry
->Length
);
485 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
491 Process DMAR RMRR table.
493 @param[in] VTdInfo The VTd engine context information.
494 @param[in] DmarRmrr The RMRR table.
498 IN VTD_INFO
*VTdInfo
,
499 IN EFI_ACPI_DMAR_RMRR_HEADER
*DmarRmrr
502 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDevScopeEntry
;
509 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
511 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
513 DEBUG ((DEBUG_INFO
," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr
->ReservedMemoryRegionBaseAddress
, DmarRmrr
->ReservedMemoryRegionLimitAddress
));
515 if ((DmarRmrr
->ReservedMemoryRegionBaseAddress
== 0) ||
516 (DmarRmrr
->ReservedMemoryRegionLimitAddress
== 0)) {
520 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarRmrr
+ 1));
521 while ((UINTN
)DmarDevScopeEntry
< (UINTN
)DmarRmrr
+ DmarRmrr
->Header
.Length
) {
522 ASSERT (DmarDevScopeEntry
->Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
);
524 VTdIndex
= GetVTdEngineFromDevScopeEntry (AcpiDmarTable
, DmarRmrr
->SegmentNumber
, DmarDevScopeEntry
);
525 if (VTdIndex
!= (UINTN
)-1) {
526 RmrrMask
= LShiftU64 (1, VTdIndex
);
529 LowTop
= (UINTN
)DmarRmrr
->ReservedMemoryRegionBaseAddress
;
530 HighBottom
= (UINTN
)DmarRmrr
->ReservedMemoryRegionLimitAddress
+ 1;
531 HighTop
= GetTopMemory ();
533 SetDmaProtectedRange (
537 (UINT32
)(LowTop
- LowBottom
),
543 // Remove the engine from the engine mask.
544 // The assumption is that any other PEI driver does not access
545 // the device covered by this engine.
547 VTdInfo
->EngineMask
= VTdInfo
->EngineMask
& (~RmrrMask
);
550 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDevScopeEntry
+ DmarDevScopeEntry
->Length
);
555 Parse DMAR DRHD table.
557 @param[in] VTdInfo The VTd engine context information.
560 ParseDmarAcpiTableRmrr (
564 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
565 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
567 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
569 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
570 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
571 switch (DmarHeader
->Type
) {
572 case EFI_ACPI_DMAR_TYPE_RMRR
:
573 ProcessRmrr (VTdInfo
, (EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
578 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);