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