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