IntelSiliconPkg/VtdPmrPei: Add premem support.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / DmarTable.c
1 /** @file
2
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.
8
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.
11
12 **/
13
14 #include <Uefi.h>
15 #include <PiPei.h>
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>
22
23 #include "IntelVTdPmrPei.h"
24
25 /**
26 Dump DMAR DeviceScopeEntry.
27
28 @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry
29 **/
30 VOID
31 DumpDmarDeviceScopeEntry (
32 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry
33 )
34 {
35 UINTN PciPathNumber;
36 UINTN PciPathIndex;
37 EFI_ACPI_DMAR_PCI_PATH *PciPath;
38
39 if (DmarDeviceScopeEntry == NULL) {
40 return;
41 }
42
43 DEBUG ((DEBUG_INFO,
44 " *************************************************************************\n"
45 ));
46 DEBUG ((DEBUG_INFO,
47 " * DMA-Remapping Device Scope Entry Structure *\n"
48 ));
49 DEBUG ((DEBUG_INFO,
50 " *************************************************************************\n"
51 ));
52 DEBUG ((DEBUG_INFO,
53 (sizeof(UINTN) == sizeof(UINT64)) ?
54 " DMAR Device Scope Entry address ...................... 0x%016lx\n" :
55 " DMAR Device Scope Entry address ...................... 0x%08x\n",
56 DmarDeviceScopeEntry
57 ));
58 DEBUG ((DEBUG_INFO,
59 " Device Scope Entry Type ............................ 0x%02x\n",
60 DmarDeviceScopeEntry->Type
61 ));
62 switch (DmarDeviceScopeEntry->Type) {
63 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:
64 DEBUG ((DEBUG_INFO,
65 " PCI Endpoint Device\n"
66 ));
67 break;
68 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:
69 DEBUG ((DEBUG_INFO,
70 " PCI Sub-hierachy\n"
71 ));
72 break;
73 default:
74 break;
75 }
76 DEBUG ((DEBUG_INFO,
77 " Length ............................................. 0x%02x\n",
78 DmarDeviceScopeEntry->Length
79 ));
80 DEBUG ((DEBUG_INFO,
81 " Enumeration ID ..................................... 0x%02x\n",
82 DmarDeviceScopeEntry->EnumerationId
83 ));
84 DEBUG ((DEBUG_INFO,
85 " Starting Bus Number ................................ 0x%02x\n",
86 DmarDeviceScopeEntry->StartBusNumber
87 ));
88
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++) {
92 DEBUG ((DEBUG_INFO,
93 " Device ............................................. 0x%02x\n",
94 PciPath[PciPathIndex].Device
95 ));
96 DEBUG ((DEBUG_INFO,
97 " Function ........................................... 0x%02x\n",
98 PciPath[PciPathIndex].Function
99 ));
100 }
101
102 DEBUG ((DEBUG_INFO,
103 " *************************************************************************\n\n"
104 ));
105
106 return;
107 }
108
109 /**
110 Dump DMAR RMRR table.
111
112 @param[in] Rmrr DMAR RMRR table
113 **/
114 VOID
115 DumpDmarRmrr (
116 IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr
117 )
118 {
119 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
120 INTN RmrrLen;
121
122 if (Rmrr == NULL) {
123 return;
124 }
125
126 DEBUG ((DEBUG_INFO,
127 " ***************************************************************************\n"
128 ));
129 DEBUG ((DEBUG_INFO,
130 " * Reserved Memory Region Reporting Structure *\n"
131 ));
132 DEBUG ((DEBUG_INFO,
133 " ***************************************************************************\n"
134 ));
135 DEBUG ((DEBUG_INFO,
136 (sizeof(UINTN) == sizeof(UINT64)) ?
137 " RMRR address ........................................... 0x%016lx\n" :
138 " RMRR address ........................................... 0x%08x\n",
139 Rmrr
140 ));
141 DEBUG ((DEBUG_INFO,
142 " Type ................................................. 0x%04x\n",
143 Rmrr->Header.Type
144 ));
145 DEBUG ((DEBUG_INFO,
146 " Length ............................................... 0x%04x\n",
147 Rmrr->Header.Length
148 ));
149 DEBUG ((DEBUG_INFO,
150 " Segment Number ....................................... 0x%04x\n",
151 Rmrr->SegmentNumber
152 ));
153 DEBUG ((DEBUG_INFO,
154 " Reserved Memory Region Base Address .................. 0x%016lx\n",
155 Rmrr->ReservedMemoryRegionBaseAddress
156 ));
157 DEBUG ((DEBUG_INFO,
158 " Reserved Memory Region Limit Address ................. 0x%016lx\n",
159 Rmrr->ReservedMemoryRegionLimitAddress
160 ));
161
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);
168 }
169
170 DEBUG ((DEBUG_INFO,
171 " ***************************************************************************\n\n"
172 ));
173
174 return;
175 }
176
177 /**
178 Dump DMAR DRHD table.
179
180 @param[in] Drhd DMAR DRHD table
181 **/
182 VOID
183 DumpDmarDrhd (
184 IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd
185 )
186 {
187 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;
188 INTN DrhdLen;
189
190 if (Drhd == NULL) {
191 return;
192 }
193
194 DEBUG ((DEBUG_INFO,
195 " ***************************************************************************\n"
196 ));
197 DEBUG ((DEBUG_INFO,
198 " * DMA-Remapping Hardware Definition Structure *\n"
199 ));
200 DEBUG ((DEBUG_INFO,
201 " ***************************************************************************\n"
202 ));
203 DEBUG ((DEBUG_INFO,
204 (sizeof(UINTN) == sizeof(UINT64)) ?
205 " DRHD address ........................................... 0x%016lx\n" :
206 " DRHD address ........................................... 0x%08x\n",
207 Drhd
208 ));
209 DEBUG ((DEBUG_INFO,
210 " Type ................................................. 0x%04x\n",
211 Drhd->Header.Type
212 ));
213 DEBUG ((DEBUG_INFO,
214 " Length ............................................... 0x%04x\n",
215 Drhd->Header.Length
216 ));
217 DEBUG ((DEBUG_INFO,
218 " Flags ................................................ 0x%02x\n",
219 Drhd->Flags
220 ));
221 DEBUG ((DEBUG_INFO,
222 " INCLUDE_PCI_ALL .................................... 0x%02x\n",
223 Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL
224 ));
225 DEBUG ((DEBUG_INFO,
226 " Segment Number ....................................... 0x%04x\n",
227 Drhd->SegmentNumber
228 ));
229 DEBUG ((DEBUG_INFO,
230 " Register Base Address ................................ 0x%016lx\n",
231 Drhd->RegisterBaseAddress
232 ));
233
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);
240 }
241
242 DEBUG ((DEBUG_INFO,
243 " ***************************************************************************\n\n"
244 ));
245
246 return;
247 }
248
249 /**
250 Dump DMAR ACPI table.
251
252 @param[in] Dmar DMAR ACPI table
253 **/
254 VOID
255 DumpAcpiDMAR (
256 IN EFI_ACPI_DMAR_HEADER *Dmar
257 )
258 {
259 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
260 INTN DmarLen;
261
262 if (Dmar == NULL) {
263 return;
264 }
265
266 //
267 // Dump Dmar table
268 //
269 DEBUG ((DEBUG_INFO,
270 "*****************************************************************************\n"
271 ));
272 DEBUG ((DEBUG_INFO,
273 "* DMAR Table *\n"
274 ));
275 DEBUG ((DEBUG_INFO,
276 "*****************************************************************************\n"
277 ));
278
279 DEBUG ((DEBUG_INFO,
280 (sizeof(UINTN) == sizeof(UINT64)) ?
281 "DMAR address ............................................. 0x%016lx\n" :
282 "DMAR address ............................................. 0x%08x\n",
283 Dmar
284 ));
285
286 DEBUG ((DEBUG_INFO,
287 " Table Contents:\n"
288 ));
289 DEBUG ((DEBUG_INFO,
290 " Host Address Width ................................... 0x%02x\n",
291 Dmar->HostAddressWidth
292 ));
293 DEBUG ((DEBUG_INFO,
294 " Flags ................................................ 0x%02x\n",
295 Dmar->Flags
296 ));
297 DEBUG ((DEBUG_INFO,
298 " INTR_REMAP ......................................... 0x%02x\n",
299 Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP
300 ));
301 DEBUG ((DEBUG_INFO,
302 " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",
303 Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT
304 ));
305
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);
312 break;
313 case EFI_ACPI_DMAR_TYPE_RMRR:
314 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);
315 break;
316 default:
317 break;
318 }
319 DmarLen -= DmarHeader->Length;
320 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
321 }
322
323 DEBUG ((DEBUG_INFO,
324 "*****************************************************************************\n\n"
325 ));
326
327 return;
328 }
329
330 /**
331 Get VTd engine number.
332
333 @param[in] AcpiDmarTable DMAR ACPI table
334
335 @return the VTd engine number.
336 **/
337 UINTN
338 GetVtdEngineNumber (
339 IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable
340 )
341 {
342 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
343 UINTN VtdIndex;
344
345 VtdIndex = 0;
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:
350 VtdIndex++;
351 break;
352 default:
353 break;
354 }
355 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
356 }
357 return VtdIndex ;
358 }
359
360 /**
361 Process DMAR DHRD table.
362
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.
366 **/
367 VOID
368 ProcessDhrd (
369 IN VTD_INFO *VTdInfo,
370 IN UINTN VtdIndex,
371 IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd
372 )
373 {
374 DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));
375 VTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;
376 }
377
378 /**
379 Parse DMAR DRHD table.
380
381 @param[in] AcpiDmarTable DMAR ACPI table
382
383 @return EFI_SUCCESS The DMAR DRHD table is parsed.
384 **/
385 EFI_STATUS
386 ParseDmarAcpiTableDrhd (
387 IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable
388 )
389 {
390 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
391 UINTN VtdUnitNumber;
392 UINTN VtdIndex;
393 VTD_INFO *VTdInfo;
394
395 VtdUnitNumber = GetVtdEngineNumber (AcpiDmarTable);
396 if (VtdUnitNumber == 0) {
397 return EFI_UNSUPPORTED;
398 }
399
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;
404 }
405
406 //
407 // Initialize the engine mask to all.
408 //
409 VTdInfo->AcpiDmarTable = AcpiDmarTable;
410 VTdInfo->EngineMask = LShiftU64 (1, VtdUnitNumber) - 1;
411 VTdInfo->HostAddressWidth = AcpiDmarTable->HostAddressWidth;
412 VTdInfo->VTdEngineCount = VtdUnitNumber;
413
414 VtdIndex = 0;
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);
421 VtdIndex++;
422
423 break;
424
425 default:
426 break;
427 }
428 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
429 }
430 ASSERT (VtdIndex == VtdUnitNumber);
431
432 return EFI_SUCCESS;
433 }
434
435 /**
436 Return the VTd engine index according to the Segment and DevScopeEntry.
437
438 @param AcpiDmarTable DMAR ACPI table
439 @param Segment The segment of the VTd engine
440 @param DevScopeEntry The DevScopeEntry of the VTd engine
441
442 @return The VTd engine index according to the Segment and DevScopeEntry.
443 @retval -1 The VTd engine is not found.
444 **/
445 UINTN
446 GetVTdEngineFromDevScopeEntry (
447 IN EFI_ACPI_DMAR_HEADER *AcpiDmarTable,
448 IN UINT16 Segment,
449 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry
450 )
451 {
452 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
453 UINTN VtdIndex;
454 EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd;
455 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry;
456
457 VtdIndex = 0;
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) {
464 // Mismatch
465 break;
466 }
467 if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||
468 ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {
469 // No DevScopeEntry
470 // Do not handle PCI_ALL
471 break;
472 }
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)) {
477 return VtdIndex;
478 }
479 ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);
480 }
481 break;
482 default:
483 break;
484 }
485 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
486 }
487 return (UINTN)-1;
488 }
489
490 /**
491 Process DMAR RMRR table.
492
493 @param[in] VTdInfo The VTd engine context information.
494 @param[in] DmarRmrr The RMRR table.
495 **/
496 VOID
497 ProcessRmrr (
498 IN VTD_INFO *VTdInfo,
499 IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr
500 )
501 {
502 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;
503 UINTN VTdIndex;
504 UINT64 RmrrMask;
505 UINTN LowBottom;
506 UINTN LowTop;
507 UINTN HighBottom;
508 UINT64 HighTop;
509 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
510
511 AcpiDmarTable = VTdInfo->AcpiDmarTable;
512
513 DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));
514
515 if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||
516 (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {
517 return ;
518 }
519
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);
523
524 VTdIndex = GetVTdEngineFromDevScopeEntry (AcpiDmarTable, DmarRmrr->SegmentNumber, DmarDevScopeEntry);
525 if (VTdIndex != (UINTN)-1) {
526 RmrrMask = LShiftU64 (1, VTdIndex);
527
528 LowBottom = 0;
529 LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;
530 HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;
531 HighTop = GetTopMemory ();
532
533 SetDmaProtectedRange (
534 VTdInfo,
535 RmrrMask,
536 0,
537 (UINT32)(LowTop - LowBottom),
538 HighBottom,
539 HighTop - HighBottom
540 );
541
542 //
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.
546 //
547 VTdInfo->EngineMask = VTdInfo->EngineMask & (~RmrrMask);
548 }
549
550 DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);
551 }
552 }
553
554 /**
555 Parse DMAR DRHD table.
556
557 @param[in] VTdInfo The VTd engine context information.
558 **/
559 VOID
560 ParseDmarAcpiTableRmrr (
561 IN VTD_INFO *VTdInfo
562 )
563 {
564 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;
565 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;
566
567 AcpiDmarTable = VTdInfo->AcpiDmarTable;
568
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);
574 break;
575 default:
576 break;
577 }
578 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);
579 }
580 }