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