]> git.proxmox.com Git - mirror_edk2.git/blob - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
IntelSiliconPkg/Vtd: Add more debug info.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / DmaProtection.c
1 /** @file
2
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.
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 "DmaProtection.h"
15
16 UINT64 mBelow4GMemoryLimit;
17 UINT64 mAbove4GMemoryLimit;
18
19 EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;
20
21 VTD_ACCESS_REQUEST *mAccessRequest = NULL;
22 UINTN mAccessRequestCount = 0;
23 UINTN mAccessRequestMaxCount = 0;
24
25 /**
26 Append VTd Access Request to global.
27
28 @param[in] Segment The Segment used to identify a VTd engine.
29 @param[in] SourceId The SourceId used to identify a VTd engine and table entry.
30 @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
31 @param[in] Length The length of device memory address to be used as the DMA memory.
32 @param[in] IoMmuAccess The IOMMU access.
33
34 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
35 @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
36 @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
37 @retval EFI_INVALID_PARAMETER Length is 0.
38 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
39 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
40 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
41 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
42 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
43
44 **/
45 EFI_STATUS
46 RequestAccessAttribute (
47 IN UINT16 Segment,
48 IN VTD_SOURCE_ID SourceId,
49 IN UINT64 BaseAddress,
50 IN UINT64 Length,
51 IN UINT64 IoMmuAccess
52 )
53 {
54 VTD_ACCESS_REQUEST *NewAccessRequest;
55 UINTN Index;
56
57 //
58 // Optimization for memory.
59 //
60 // If the last record is to IoMmuAccess=0,
61 // Check previous records and remove the matched entry.
62 //
63 if (IoMmuAccess == 0) {
64 for (Index = 0; Index < mAccessRequestCount; Index++) {
65 if ((mAccessRequest[Index].Segment == Segment) &&
66 (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) &&
67 (mAccessRequest[Index].BaseAddress == BaseAddress) &&
68 (mAccessRequest[Index].Length == Length) &&
69 (mAccessRequest[Index].IoMmuAccess != 0)) {
70 //
71 // Remove this record [Index].
72 // No need to add the new record.
73 //
74 if (Index != mAccessRequestCount - 1) {
75 CopyMem (
76 &mAccessRequest[Index],
77 &mAccessRequest[Index + 1],
78 sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index)
79 );
80 }
81 ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST));
82 mAccessRequestCount--;
83 return EFI_SUCCESS;
84 }
85 }
86 }
87
88 if (mAccessRequestCount >= mAccessRequestMaxCount) {
89 NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));
90 if (NewAccessRequest == NULL) {
91 return EFI_OUT_OF_RESOURCES;
92 }
93 mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST;
94 if (mAccessRequest != NULL) {
95 CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount);
96 FreePool (mAccessRequest);
97 }
98 mAccessRequest = NewAccessRequest;
99 }
100
101 ASSERT (mAccessRequestCount < mAccessRequestMaxCount);
102
103 mAccessRequest[mAccessRequestCount].Segment = Segment;
104 mAccessRequest[mAccessRequestCount].SourceId = SourceId;
105 mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress;
106 mAccessRequest[mAccessRequestCount].Length = Length;
107 mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess;
108
109 mAccessRequestCount++;
110
111 return EFI_SUCCESS;
112 }
113
114 /**
115 Process Access Requests from before DMAR table is installed.
116
117 **/
118 VOID
119 ProcessRequestedAccessAttribute (
120 VOID
121 )
122 {
123 UINTN Index;
124 EFI_STATUS Status;
125
126 DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));
127
128 for (Index = 0; Index < mAccessRequestCount; Index++) {
129 DEBUG ((
130 DEBUG_INFO,
131 "PCI(S%x.B%x.D%x.F%x) ",
132 mAccessRequest[Index].Segment,
133 mAccessRequest[Index].SourceId.Bits.Bus,
134 mAccessRequest[Index].SourceId.Bits.Device,
135 mAccessRequest[Index].SourceId.Bits.Function
136 ));
137 DEBUG ((
138 DEBUG_INFO,
139 "(0x%lx~0x%lx) - %lx\n",
140 mAccessRequest[Index].BaseAddress,
141 mAccessRequest[Index].Length,
142 mAccessRequest[Index].IoMmuAccess
143 ));
144 Status = SetAccessAttribute (
145 mAccessRequest[Index].Segment,
146 mAccessRequest[Index].SourceId,
147 mAccessRequest[Index].BaseAddress,
148 mAccessRequest[Index].Length,
149 mAccessRequest[Index].IoMmuAccess
150 );
151 if (EFI_ERROR (Status)) {
152 DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));
153 }
154 }
155
156 if (mAccessRequest != NULL) {
157 FreePool (mAccessRequest);
158 }
159 mAccessRequest = NULL;
160 mAccessRequestCount = 0;
161 mAccessRequestMaxCount = 0;
162
163 DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));
164 }
165
166 /**
167 return the UEFI memory information.
168
169 @param[out] Below4GMemoryLimit The below 4GiB memory limit
170 @param[out] Above4GMemoryLimit The above 4GiB memory limit
171 **/
172 VOID
173 ReturnUefiMemoryMap (
174 OUT UINT64 *Below4GMemoryLimit,
175 OUT UINT64 *Above4GMemoryLimit
176 )
177 {
178 EFI_STATUS Status;
179 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
180 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
181 EFI_MEMORY_DESCRIPTOR *EfiEntry;
182 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
183 EFI_MEMORY_DESCRIPTOR TempEfiEntry;
184 UINTN EfiMemoryMapSize;
185 UINTN EfiMapKey;
186 UINTN EfiDescriptorSize;
187 UINT32 EfiDescriptorVersion;
188 UINT64 MemoryBlockLength;
189
190 *Below4GMemoryLimit = 0;
191 *Above4GMemoryLimit = 0;
192
193 //
194 // Get the EFI memory map.
195 //
196 EfiMemoryMapSize = 0;
197 EfiMemoryMap = NULL;
198 Status = gBS->GetMemoryMap (
199 &EfiMemoryMapSize,
200 EfiMemoryMap,
201 &EfiMapKey,
202 &EfiDescriptorSize,
203 &EfiDescriptorVersion
204 );
205 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
206
207 do {
208 //
209 // Use size returned back plus 1 descriptor for the AllocatePool.
210 // We don't just multiply by 2 since the "for" loop below terminates on
211 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
212 // we process bogus entries and create bogus E820 entries.
213 //
214 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
215 ASSERT (EfiMemoryMap != NULL);
216 Status = gBS->GetMemoryMap (
217 &EfiMemoryMapSize,
218 EfiMemoryMap,
219 &EfiMapKey,
220 &EfiDescriptorSize,
221 &EfiDescriptorVersion
222 );
223 if (EFI_ERROR (Status)) {
224 FreePool (EfiMemoryMap);
225 }
226 } while (Status == EFI_BUFFER_TOO_SMALL);
227
228 ASSERT_EFI_ERROR (Status);
229
230 //
231 // Sort memory map from low to high
232 //
233 EfiEntry = EfiMemoryMap;
234 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
235 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
236 while (EfiEntry < EfiMemoryMapEnd) {
237 while (NextEfiEntry < EfiMemoryMapEnd) {
238 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
239 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
240 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
241 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
242 }
243
244 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
245 }
246
247 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
248 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
249 }
250
251 //
252 //
253 //
254 DEBUG ((DEBUG_INFO, "MemoryMap:\n"));
255 EfiEntry = EfiMemoryMap;
256 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
257 while (EfiEntry < EfiMemoryMapEnd) {
258 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
259 DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));
260 switch (EfiEntry->Type) {
261 case EfiLoaderCode:
262 case EfiLoaderData:
263 case EfiBootServicesCode:
264 case EfiBootServicesData:
265 case EfiConventionalMemory:
266 case EfiRuntimeServicesCode:
267 case EfiRuntimeServicesData:
268 case EfiACPIReclaimMemory:
269 case EfiACPIMemoryNVS:
270 case EfiReservedMemoryType:
271 if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {
272 //
273 // Skip the memory block is under 1MB
274 //
275 } else if (EfiEntry->PhysicalStart >= BASE_4GB) {
276 if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
277 *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
278 }
279 } else {
280 if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
281 *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
282 }
283 }
284 break;
285 }
286 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
287 }
288
289 FreePool (EfiMemoryMap);
290
291 DEBUG ((DEBUG_INFO, "Result:\n"));
292 DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));
293 DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));
294
295 return ;
296 }
297
298 /**
299 The scan bus callback function to always enable page attribute.
300
301 @param[in] Context The context of the callback.
302 @param[in] Segment The segment of the source.
303 @param[in] Bus The bus of the source.
304 @param[in] Device The device of the source.
305 @param[in] Function The function of the source.
306
307 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
308 **/
309 EFI_STATUS
310 EFIAPI
311 ScanBusCallbackAlwaysEnablePageAttribute (
312 IN VOID *Context,
313 IN UINT16 Segment,
314 IN UINT8 Bus,
315 IN UINT8 Device,
316 IN UINT8 Function
317 )
318 {
319 VTD_SOURCE_ID SourceId;
320 EFI_STATUS Status;
321
322 SourceId.Bits.Bus = Bus;
323 SourceId.Bits.Device = Device;
324 SourceId.Bits.Function = Function;
325 Status = AlwaysEnablePageAttribute (Segment, SourceId);
326 return Status;
327 }
328
329 /**
330 Always enable the VTd page attribute for the device in the DeviceScope.
331
332 @param[in] DeviceScope the input device scope data structure
333
334 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
335 **/
336 EFI_STATUS
337 AlwaysEnablePageAttributeDeviceScope (
338 IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope
339 )
340 {
341 UINT8 Bus;
342 UINT8 Device;
343 UINT8 Function;
344 VTD_SOURCE_ID SourceId;
345 UINT8 SecondaryBusNumber;
346 EFI_STATUS Status;
347
348 Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);
349
350 if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {
351 //
352 // Need scan the bridge and add all devices.
353 //
354 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
355 Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);
356 return Status;
357 } else {
358 SourceId.Bits.Bus = Bus;
359 SourceId.Bits.Device = Device;
360 SourceId.Bits.Function = Function;
361 Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);
362 return Status;
363 }
364 }
365
366 /**
367 Always enable the VTd page attribute for the device matching DeviceId.
368
369 @param[in] PciDeviceId the input PCI device ID
370
371 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.
372 **/
373 EFI_STATUS
374 AlwaysEnablePageAttributePciDeviceId (
375 IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId
376 )
377 {
378 UINTN VtdIndex;
379 UINTN PciIndex;
380 PCI_DEVICE_DATA *PciDeviceData;
381 EFI_STATUS Status;
382
383 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
384 for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {
385 PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];
386
387 if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&
388 ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&
389 ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&
390 ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&
391 ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {
392 Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);
393 if (EFI_ERROR(Status)) {
394 continue;
395 }
396 }
397 }
398 }
399 return EFI_SUCCESS;
400 }
401
402 /**
403 Always enable the VTd page attribute for the device.
404
405 @param[in] DeviceInfo the exception device information
406
407 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.
408 **/
409 EFI_STATUS
410 AlwaysEnablePageAttributeExceptionDeviceInfo (
411 IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo
412 )
413 {
414 switch (DeviceInfo->Type) {
415 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:
416 return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));
417 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:
418 return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));
419 default:
420 return EFI_UNSUPPORTED;
421 }
422 }
423
424 /**
425 Initialize platform VTd policy.
426 **/
427 VOID
428 InitializePlatformVTdPolicy (
429 VOID
430 )
431 {
432 EFI_STATUS Status;
433 UINTN DeviceInfoCount;
434 VOID *DeviceInfo;
435 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;
436 UINTN Index;
437
438 //
439 // It is optional.
440 //
441 Status = gBS->LocateProtocol (
442 &gEdkiiPlatformVTdPolicyProtocolGuid,
443 NULL,
444 (VOID **)&mPlatformVTdPolicy
445 );
446 if (!EFI_ERROR(Status)) {
447 DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));
448 Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);
449 if (!EFI_ERROR(Status)) {
450 ThisDeviceInfo = DeviceInfo;
451 for (Index = 0; Index < DeviceInfoCount; Index++) {
452 if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {
453 break;
454 }
455 AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);
456 ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);
457 }
458 FreePool (DeviceInfo);
459 }
460 }
461 }
462
463 /**
464 Setup VTd engine.
465 **/
466 VOID
467 SetupVtd (
468 VOID
469 )
470 {
471 EFI_STATUS Status;
472 VOID *PciEnumerationComplete;
473 UINTN Index;
474 UINT64 Below4GMemoryLimit;
475 UINT64 Above4GMemoryLimit;
476
477 //
478 // PCI Enumeration must be done
479 //
480 Status = gBS->LocateProtocol (
481 &gEfiPciEnumerationCompleteProtocolGuid,
482 NULL,
483 &PciEnumerationComplete
484 );
485 ASSERT_EFI_ERROR (Status);
486
487 ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);
488 Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);
489 DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));
490
491 mBelow4GMemoryLimit = Below4GMemoryLimit;
492 mAbove4GMemoryLimit = Above4GMemoryLimit;
493
494 //
495 // 1. setup
496 //
497 DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));
498 Status = ParseDmarAcpiTableDrhd ();
499 if (EFI_ERROR (Status)) {
500 return;
501 }
502 DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
503 PrepareVtdConfig ();
504
505 //
506 // 2. initialization
507 //
508 DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));
509 Status = SetupTranslationTable ();
510 if (EFI_ERROR (Status)) {
511 return;
512 }
513
514 InitializePlatformVTdPolicy ();
515
516 ParseDmarAcpiTableRmrr ();
517
518 ProcessRequestedAccessAttribute ();
519
520 for (Index = 0; Index < mVtdUnitNumber; Index++) {
521 DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));
522 if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
523 DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);
524 }
525 if (mVtdUnitInformation[Index].RootEntryTable != NULL) {
526 DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);
527 }
528 }
529
530 //
531 // 3. enable
532 //
533 DEBUG ((DEBUG_INFO, "EnableDmar\n"));
534 Status = EnableDmar ();
535 if (EFI_ERROR (Status)) {
536 return;
537 }
538 DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));
539 DumpVtdRegsAll ();
540 }
541
542 /**
543 Notification function of ACPI Table change.
544
545 This is a notification function registered on ACPI Table change event.
546
547 @param Event Event whose notification function is being invoked.
548 @param Context Pointer to the notification function's context.
549
550 **/
551 VOID
552 EFIAPI
553 AcpiNotificationFunc (
554 IN EFI_EVENT Event,
555 IN VOID *Context
556 )
557 {
558 EFI_STATUS Status;
559
560 Status = GetDmarAcpiTable ();
561 if (EFI_ERROR (Status)) {
562 if (Status == EFI_ALREADY_STARTED) {
563 gBS->CloseEvent (Event);
564 }
565 return;
566 }
567 SetupVtd ();
568 gBS->CloseEvent (Event);
569 }
570
571 /**
572 Exit boot service callback function.
573
574 @param[in] Event The event handle.
575 @param[in] Context The event content.
576 **/
577 VOID
578 EFIAPI
579 OnExitBootServices (
580 IN EFI_EVENT Event,
581 IN VOID *Context
582 )
583 {
584 DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));
585 DumpVtdRegsAll ();
586
587 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
588 DisableDmar ();
589 DumpVtdRegsAll ();
590 }
591 }
592
593 /**
594 Legacy boot callback function.
595
596 @param[in] Event The event handle.
597 @param[in] Context The event content.
598 **/
599 VOID
600 EFIAPI
601 OnLegacyBoot (
602 EFI_EVENT Event,
603 VOID *Context
604 )
605 {
606 DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));
607 DumpVtdRegsAll ();
608 DisableDmar ();
609 DumpVtdRegsAll ();
610 }
611
612 /**
613 Initialize DMA protection.
614 **/
615 VOID
616 InitializeDmaProtection (
617 VOID
618 )
619 {
620 EFI_STATUS Status;
621 EFI_EVENT ExitBootServicesEvent;
622 EFI_EVENT LegacyBootEvent;
623 EFI_EVENT EventAcpi10;
624 EFI_EVENT EventAcpi20;
625
626 Status = gBS->CreateEventEx (
627 EVT_NOTIFY_SIGNAL,
628 VTD_TPL_LEVEL,
629 AcpiNotificationFunc,
630 NULL,
631 &gEfiAcpi10TableGuid,
632 &EventAcpi10
633 );
634 ASSERT_EFI_ERROR (Status);
635
636 Status = gBS->CreateEventEx (
637 EVT_NOTIFY_SIGNAL,
638 VTD_TPL_LEVEL,
639 AcpiNotificationFunc,
640 NULL,
641 &gEfiAcpi20TableGuid,
642 &EventAcpi20
643 );
644 ASSERT_EFI_ERROR (Status);
645
646 //
647 // Signal the events initially for the case
648 // that DMAR table has been installed.
649 //
650 gBS->SignalEvent (EventAcpi20);
651 gBS->SignalEvent (EventAcpi10);
652
653 Status = gBS->CreateEventEx (
654 EVT_NOTIFY_SIGNAL,
655 TPL_CALLBACK,
656 OnExitBootServices,
657 NULL,
658 &gEfiEventExitBootServicesGuid,
659 &ExitBootServicesEvent
660 );
661 ASSERT_EFI_ERROR (Status);
662
663 Status = EfiCreateEventLegacyBootEx (
664 TPL_CALLBACK,
665 OnLegacyBoot,
666 NULL,
667 &LegacyBootEvent
668 );
669 ASSERT_EFI_ERROR (Status);
670
671 return ;
672 }