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.
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 " DMA_CTRL_PLATFORM_OPT_IN_FLAG ...................... 0x%02x\n",
307 Dmar
->Flags
& EFI_ACPI_DMAR_FLAGS_DMA_CTRL_PLATFORM_OPT_IN_FLAG
310 DmarLen
= Dmar
->Header
.Length
- sizeof(EFI_ACPI_DMAR_HEADER
);
311 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)(Dmar
+ 1);
312 while (DmarLen
> 0) {
313 switch (DmarHeader
->Type
) {
314 case EFI_ACPI_DMAR_TYPE_DRHD
:
315 DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
317 case EFI_ACPI_DMAR_TYPE_RMRR
:
318 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
323 DmarLen
-= DmarHeader
->Length
;
324 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
328 "*****************************************************************************\n\n"
335 Get VTd engine number.
337 @param[in] AcpiDmarTable DMAR ACPI table
339 @return the VTd engine number.
343 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
346 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
350 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
351 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
352 switch (DmarHeader
->Type
) {
353 case EFI_ACPI_DMAR_TYPE_DRHD
:
359 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
365 Process DMAR DHRD table.
367 @param[in] VTdInfo The VTd engine context information.
368 @param[in] VtdIndex The index of VTd engine.
369 @param[in] DmarDrhd The DRHD table.
373 IN VTD_INFO
*VTdInfo
,
375 IN EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
378 DEBUG ((DEBUG_INFO
," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex
, DmarDrhd
->RegisterBaseAddress
));
379 VTdInfo
->VTdEngineAddress
[VtdIndex
] = DmarDrhd
->RegisterBaseAddress
;
383 Parse DMAR DRHD table.
385 @param[in] AcpiDmarTable DMAR ACPI table
387 @return EFI_SUCCESS The DMAR DRHD table is parsed.
390 ParseDmarAcpiTableDrhd (
391 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
394 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
399 VtdUnitNumber
= GetVtdEngineNumber (AcpiDmarTable
);
400 if (VtdUnitNumber
== 0) {
401 return EFI_UNSUPPORTED
;
404 VTdInfo
= BuildGuidHob (&mVTdInfoGuid
, sizeof(VTD_INFO
) + (VtdUnitNumber
- 1) * sizeof(UINT64
));
405 ASSERT(VTdInfo
!= NULL
);
406 if (VTdInfo
== NULL
) {
407 return EFI_OUT_OF_RESOURCES
;
411 // Initialize the engine mask to all.
413 VTdInfo
->AcpiDmarTable
= AcpiDmarTable
;
414 VTdInfo
->EngineMask
= LShiftU64 (1, VtdUnitNumber
) - 1;
415 VTdInfo
->HostAddressWidth
= AcpiDmarTable
->HostAddressWidth
;
416 VTdInfo
->VTdEngineCount
= VtdUnitNumber
;
419 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
420 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
421 switch (DmarHeader
->Type
) {
422 case EFI_ACPI_DMAR_TYPE_DRHD
:
423 ASSERT (VtdIndex
< VtdUnitNumber
);
424 ProcessDhrd (VTdInfo
, VtdIndex
, (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
);
432 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
434 ASSERT (VtdIndex
== VtdUnitNumber
);
440 Return the VTd engine index according to the Segment and DevScopeEntry.
442 @param AcpiDmarTable DMAR ACPI table
443 @param Segment The segment of the VTd engine
444 @param DevScopeEntry The DevScopeEntry of the VTd engine
446 @return The VTd engine index according to the Segment and DevScopeEntry.
447 @retval -1 The VTd engine is not found.
450 GetVTdEngineFromDevScopeEntry (
451 IN EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
,
453 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DevScopeEntry
456 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
458 EFI_ACPI_DMAR_DRHD_HEADER
*DmarDrhd
;
459 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*ThisDevScopeEntry
;
462 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
463 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
464 switch (DmarHeader
->Type
) {
465 case EFI_ACPI_DMAR_TYPE_DRHD
:
466 DmarDrhd
= (EFI_ACPI_DMAR_DRHD_HEADER
*)DmarHeader
;
467 if (DmarDrhd
->SegmentNumber
!= Segment
) {
471 if ((DmarDrhd
->Header
.Length
== sizeof(EFI_ACPI_DMAR_DRHD_HEADER
)) ||
472 ((DmarDrhd
->Flags
& EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
) != 0)) {
474 // Do not handle PCI_ALL
477 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarDrhd
+ 1));
478 while ((UINTN
)ThisDevScopeEntry
< (UINTN
)DmarDrhd
+ DmarDrhd
->Header
.Length
) {
479 if ((ThisDevScopeEntry
->Length
== DevScopeEntry
->Length
) &&
480 (CompareMem (ThisDevScopeEntry
, DevScopeEntry
, DevScopeEntry
->Length
) == 0)) {
483 ThisDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)ThisDevScopeEntry
+ ThisDevScopeEntry
->Length
);
489 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);
495 Process DMAR RMRR table.
497 @param[in] VTdInfo The VTd engine context information.
498 @param[in] DmarRmrr The RMRR table.
502 IN VTD_INFO
*VTdInfo
,
503 IN EFI_ACPI_DMAR_RMRR_HEADER
*DmarRmrr
506 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*DmarDevScopeEntry
;
513 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
515 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
517 DEBUG ((DEBUG_INFO
," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr
->ReservedMemoryRegionBaseAddress
, DmarRmrr
->ReservedMemoryRegionLimitAddress
));
519 if ((DmarRmrr
->ReservedMemoryRegionBaseAddress
== 0) ||
520 (DmarRmrr
->ReservedMemoryRegionLimitAddress
== 0)) {
524 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)(DmarRmrr
+ 1));
525 while ((UINTN
)DmarDevScopeEntry
< (UINTN
)DmarRmrr
+ DmarRmrr
->Header
.Length
) {
526 ASSERT (DmarDevScopeEntry
->Type
== EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT
);
528 VTdIndex
= GetVTdEngineFromDevScopeEntry (AcpiDmarTable
, DmarRmrr
->SegmentNumber
, DmarDevScopeEntry
);
529 if (VTdIndex
!= (UINTN
)-1) {
530 RmrrMask
= LShiftU64 (1, VTdIndex
);
533 LowTop
= (UINTN
)DmarRmrr
->ReservedMemoryRegionBaseAddress
;
534 HighBottom
= (UINTN
)DmarRmrr
->ReservedMemoryRegionLimitAddress
+ 1;
535 HighTop
= LShiftU64 (1, VTdInfo
->HostAddressWidth
+ 1);
537 SetDmaProtectedRange (
541 (UINT32
)(LowTop
- LowBottom
),
547 // Remove the engine from the engine mask.
548 // The assumption is that any other PEI driver does not access
549 // the device covered by this engine.
551 VTdInfo
->EngineMask
= VTdInfo
->EngineMask
& (~RmrrMask
);
554 DmarDevScopeEntry
= (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER
*)((UINTN
)DmarDevScopeEntry
+ DmarDevScopeEntry
->Length
);
559 Parse DMAR DRHD table.
561 @param[in] VTdInfo The VTd engine context information.
564 ParseDmarAcpiTableRmrr (
568 EFI_ACPI_DMAR_HEADER
*AcpiDmarTable
;
569 EFI_ACPI_DMAR_STRUCTURE_HEADER
*DmarHeader
;
571 AcpiDmarTable
= VTdInfo
->AcpiDmarTable
;
573 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)(AcpiDmarTable
+ 1));
574 while ((UINTN
)DmarHeader
< (UINTN
)AcpiDmarTable
+ AcpiDmarTable
->Header
.Length
) {
575 switch (DmarHeader
->Type
) {
576 case EFI_ACPI_DMAR_TYPE_RMRR
:
577 ProcessRmrr (VTdInfo
, (EFI_ACPI_DMAR_RMRR_HEADER
*)DmarHeader
);
582 DmarHeader
= (EFI_ACPI_DMAR_STRUCTURE_HEADER
*)((UINTN
)DmarHeader
+ DmarHeader
->Length
);