]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg/IntelVTdPmrPei: Parse RMRR table.
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
CommitLineData
3f5ed3fa
JY
1/** @file\r
2\r
3 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>\r
4\r
5 This program and the accompanying materials are licensed and made available under\r
6 the terms and conditions of the BSD License which accompanies this distribution.\r
7 The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <Uefi.h>\r
16#include <PiPei.h>\r
17#include <Library/BaseLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/IoLib.h>\r
21#include <Library/DebugLib.h>\r
22#include <Library/PeiServicesLib.h>\r
23#include <Library/HobLib.h>\r
24#include <IndustryStandard/Vtd.h>\r
25#include <Ppi/IoMmu.h>\r
4084ccfa 26#include <Ppi/VtdInfo.h>\r
3f5ed3fa
JY
27\r
28#include "IntelVTdPmrPei.h"\r
29\r
30#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB\r
31\r
8e9da4ba
JY
32EFI_ACPI_DMAR_HEADER *mAcpiDmarTable;\r
33VTD_INFO *mVTdInfo;\r
34UINT64 mEngineMask;\r
3f5ed3fa
JY
35UINTN mDmaBufferBase;\r
36UINTN mDmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
37UINTN mDmaBufferCurrentTop;\r
38UINTN mDmaBufferCurrentBottom;\r
39\r
40#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
41typedef struct {\r
42 UINT32 Signature;\r
43 EDKII_IOMMU_OPERATION Operation;\r
44 UINTN NumberOfBytes;\r
45 EFI_PHYSICAL_ADDRESS HostAddress;\r
46 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
47} MAP_INFO;\r
48\r
49/**\r
50\r
51 PEI Memory Layout:\r
52\r
8e9da4ba
JY
53 +------------------+ <=============== PHMR.Limit (Top of memory)\r
54 | Mem Resource |\r
55 | |\r
56\r
3f5ed3fa
JY
57 +------------------+ <------- EfiMemoryTop\r
58 | PEI allocated |\r
8e9da4ba 59 =========== +==================+ <=============== PHMR.Base\r
3f5ed3fa
JY
60 ^ | Commom Buf |\r
61 | | -------------- |\r
62 DMA Buffer | * DMA FREE * |\r
63 | | -------------- |\r
64 V | Read/Write Buf |\r
8e9da4ba 65 =========== +==================+ <=============== PLMR.Limit\r
3f5ed3fa
JY
66 | PEI allocated |\r
67 | -------------- | <------- EfiFreeMemoryTop\r
68 | * PEI FREE * |\r
69 | -------------- | <------- EfiFreeMemoryBottom\r
70 | hob |\r
71 | -------------- |\r
72 | Stack |\r
73 +------------------+ <------- EfiMemoryBottom / Stack Bottom\r
74\r
75 +------------------+\r
76 | Mem Alloc Hob |\r
77 +------------------+\r
78\r
8e9da4ba
JY
79 | |\r
80 | Mem Resource |\r
81 +------------------+ <=============== PLMR.Base (0)\r
3f5ed3fa
JY
82**/\r
83\r
84\r
85/**\r
86 Set IOMMU attribute for a system memory.\r
87\r
88 If the IOMMU PPI exists, the system memory cannot be used\r
89 for DMA by default.\r
90\r
91 When a device requests a DMA access for a system memory,\r
92 the device driver need use SetAttribute() to update the IOMMU\r
93 attribute to request DMA access (read and/or write).\r
94\r
95 @param[in] This The PPI instance pointer.\r
96 @param[in] Mapping The mapping value returned from Map().\r
97 @param[in] IoMmuAccess The IOMMU access.\r
98\r
99 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.\r
100 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
101 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
102 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
103 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.\r
104 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
105 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
106\r
107**/\r
108EFI_STATUS\r
109EFIAPI\r
110PeiIoMmuSetAttribute (\r
111 IN EDKII_IOMMU_PPI *This,\r
112 IN VOID *Mapping,\r
113 IN UINT64 IoMmuAccess\r
114 )\r
115{\r
116 return EFI_SUCCESS;\r
117}\r
118\r
119/**\r
120 Provides the controller-specific addresses required to access system memory from a\r
121 DMA bus master.\r
122\r
123 @param This The PPI instance pointer.\r
124 @param Operation Indicates if the bus master is going to read or write to system memory.\r
125 @param HostAddress The system memory address to map to the PCI controller.\r
126 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
127 that were mapped.\r
128 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
129 access the hosts HostAddress.\r
130 @param Mapping A resulting value to pass to Unmap().\r
131\r
132 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
133 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
134 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
135 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
136 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
137\r
138**/\r
139EFI_STATUS\r
140EFIAPI\r
141PeiIoMmuMap (\r
142 IN EDKII_IOMMU_PPI *This,\r
143 IN EDKII_IOMMU_OPERATION Operation,\r
144 IN VOID *HostAddress,\r
145 IN OUT UINTN *NumberOfBytes,\r
146 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
147 OUT VOID **Mapping\r
148 )\r
149{\r
150 MAP_INFO *MapInfo;\r
151 UINTN Length;\r
152\r
153 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
154 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
155 *DeviceAddress = (UINTN)HostAddress;\r
156 *Mapping = 0;\r
157 return EFI_SUCCESS;\r
158 }\r
159\r
160 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
161 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
162 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
163\r
164 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
165 if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {\r
166 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
167 ASSERT (FALSE);\r
168 return EFI_OUT_OF_RESOURCES;\r
169 }\r
170\r
171 *DeviceAddress = mDmaBufferCurrentBottom;\r
172 mDmaBufferCurrentBottom += Length;\r
173\r
174 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
175 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
176 MapInfo->Operation = Operation;\r
177 MapInfo->NumberOfBytes = *NumberOfBytes;\r
178 MapInfo->HostAddress = (UINTN)HostAddress;\r
179 MapInfo->DeviceAddress = *DeviceAddress;\r
180 *Mapping = MapInfo;\r
181 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));\r
182\r
183 //\r
184 // If this is a read operation from the Bus Master's point of view,\r
185 // then copy the contents of the real buffer into the mapped buffer\r
186 // so the Bus Master can read the contents of the real buffer.\r
187 //\r
188 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
189 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
190 CopyMem (\r
191 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
192 (VOID *) (UINTN) MapInfo->HostAddress,\r
193 MapInfo->NumberOfBytes\r
194 );\r
195 }\r
196\r
197 return EFI_SUCCESS;\r
198}\r
199\r
200/**\r
201 Completes the Map() operation and releases any corresponding resources.\r
202\r
203 @param This The PPI instance pointer.\r
204 @param Mapping The mapping value returned from Map().\r
205\r
206 @retval EFI_SUCCESS The range was unmapped.\r
207 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
208 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
209**/\r
210EFI_STATUS\r
211EFIAPI\r
212PeiIoMmuUnmap (\r
213 IN EDKII_IOMMU_PPI *This,\r
214 IN VOID *Mapping\r
215 )\r
216{\r
217 MAP_INFO *MapInfo;\r
218 UINTN Length;\r
219\r
220 if (Mapping == NULL) {\r
221 return EFI_SUCCESS;\r
222 }\r
223\r
224 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
225 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
226 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
227\r
228 MapInfo = Mapping;\r
229 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
230 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));\r
231\r
232 //\r
233 // If this is a write operation from the Bus Master's point of view,\r
234 // then copy the contents of the mapped buffer into the real buffer\r
235 // so the processor can read the contents of the real buffer.\r
236 //\r
237 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
238 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
239 CopyMem (\r
240 (VOID *) (UINTN) MapInfo->HostAddress,\r
241 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
242 MapInfo->NumberOfBytes\r
243 );\r
244 }\r
245\r
246 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
247 if (mDmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
248 mDmaBufferCurrentBottom -= Length;\r
249 }\r
250\r
251 return EFI_SUCCESS;\r
252}\r
253\r
254/**\r
255 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
256 OperationBusMasterCommonBuffer64 mapping.\r
257\r
258 @param This The PPI instance pointer.\r
259 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
260 EfiRuntimeServicesData.\r
261 @param Pages The number of pages to allocate.\r
262 @param HostAddress A pointer to store the base system memory address of the\r
263 allocated range.\r
264 @param Attributes The requested bit mask of attributes for the allocated range.\r
265\r
266 @retval EFI_SUCCESS The requested memory pages were allocated.\r
267 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
268 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
269 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
270 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
271\r
272**/\r
273EFI_STATUS\r
274EFIAPI\r
275PeiIoMmuAllocateBuffer (\r
276 IN EDKII_IOMMU_PPI *This,\r
277 IN EFI_MEMORY_TYPE MemoryType,\r
278 IN UINTN Pages,\r
279 IN OUT VOID **HostAddress,\r
280 IN UINT64 Attributes\r
281 )\r
282{\r
283 UINTN Length;\r
284\r
285 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
286 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
287 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
288\r
289 Length = EFI_PAGES_TO_SIZE(Pages);\r
290 if (Length > mDmaBufferCurrentTop - mDmaBufferCurrentBottom) {\r
291 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
292 ASSERT (FALSE);\r
293 return EFI_OUT_OF_RESOURCES;\r
294 }\r
295 *HostAddress = (VOID *)(UINTN)(mDmaBufferCurrentTop - Length);\r
296 mDmaBufferCurrentTop -= Length;\r
297\r
298 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302/**\r
303 Frees memory that was allocated with AllocateBuffer().\r
304\r
305 @param This The PPI instance pointer.\r
306 @param Pages The number of pages to free.\r
307 @param HostAddress The base system memory address of the allocated range.\r
308\r
309 @retval EFI_SUCCESS The requested memory pages were freed.\r
310 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
311 was not allocated with AllocateBuffer().\r
312\r
313**/\r
314EFI_STATUS\r
315EFIAPI\r
316PeiIoMmuFreeBuffer (\r
317 IN EDKII_IOMMU_PPI *This,\r
318 IN UINTN Pages,\r
319 IN VOID *HostAddress\r
320 )\r
321{\r
322 UINTN Length;\r
323\r
324 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
325 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentTop - %x\n", mDmaBufferCurrentTop));\r
326 DEBUG ((DEBUG_VERBOSE, " mDmaBufferCurrentBottom - %x\n", mDmaBufferCurrentBottom));\r
327\r
328 Length = EFI_PAGES_TO_SIZE(Pages);\r
329 if ((UINTN)HostAddress == mDmaBufferCurrentTop) {\r
330 mDmaBufferCurrentTop += Length;\r
331 }\r
332\r
333 return EFI_SUCCESS;\r
334}\r
335\r
336EDKII_IOMMU_PPI mIoMmuPpi = {\r
337 EDKII_IOMMU_PPI_REVISION,\r
338 PeiIoMmuSetAttribute,\r
339 PeiIoMmuMap,\r
340 PeiIoMmuUnmap,\r
341 PeiIoMmuAllocateBuffer,\r
342 PeiIoMmuFreeBuffer,\r
343};\r
344\r
345CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {\r
346 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
347 &gEdkiiIoMmuPpiGuid,\r
348 (VOID *) &mIoMmuPpi\r
349};\r
350\r
351#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \\r
352 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \\r
353 EFI_RESOURCE_ATTRIBUTE_TESTED | \\r
354 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \\r
355 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \\r
356 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \\r
357 )\r
358\r
359#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)\r
360\r
361#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)\r
362\r
363#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)\r
364\r
365GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mResourceTypeShortName[] = {\r
366 "Mem",\r
367 "MMIO",\r
368 "I/O",\r
369 "FD",\r
370 "MM Port I/O",\r
371 "Reserved Mem",\r
372 "Reserved I/O",\r
373};\r
374\r
375/**\r
376 Return the short name of resource type.\r
377\r
378 @param Type resource type.\r
379\r
380 @return the short name of resource type.\r
381**/\r
382CHAR8 *\r
383ShortNameOfResourceType (\r
384 IN UINT32 Type\r
385 )\r
386{\r
387 if (Type < sizeof(mResourceTypeShortName) / sizeof(mResourceTypeShortName[0])) {\r
388 return mResourceTypeShortName[Type];\r
389 } else {\r
390 return "Unknown";\r
391 }\r
392}\r
393\r
394/**\r
395 Dump resource hob.\r
396\r
397 @param HobList the HOB list.\r
398**/\r
399VOID\r
400DumpResourceHob (\r
401 IN VOID *HobList\r
402 )\r
403{\r
404 EFI_PEI_HOB_POINTERS Hob;\r
405 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
406\r
407 DEBUG ((DEBUG_VERBOSE, "Resource Descriptor HOBs\n"));\r
408 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
409 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
410 ResourceHob = Hob.ResourceDescriptor;\r
411 DEBUG ((DEBUG_VERBOSE,\r
412 " BA=%016lx L=%016lx Attr=%08x ",\r
413 ResourceHob->PhysicalStart,\r
414 ResourceHob->ResourceLength,\r
415 ResourceHob->ResourceAttribute\r
416 ));\r
417 DEBUG ((DEBUG_VERBOSE, ShortNameOfResourceType(ResourceHob->ResourceType)));\r
418 switch (ResourceHob->ResourceType) {\r
419 case EFI_RESOURCE_SYSTEM_MEMORY:\r
420 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) != 0) {\r
421 DEBUG ((DEBUG_VERBOSE, " (Persistent)"));\r
422 } else if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) != 0) {\r
423 DEBUG ((DEBUG_VERBOSE, " (MoreReliable)"));\r
424 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {\r
425 DEBUG ((DEBUG_VERBOSE, " (Tested)"));\r
426 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {\r
427 DEBUG ((DEBUG_VERBOSE, " (Init)"));\r
428 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {\r
429 DEBUG ((DEBUG_VERBOSE, " (Present)"));\r
430 } else {\r
431 DEBUG ((DEBUG_VERBOSE, " (Unknown)"));\r
432 }\r
433 break;\r
434 default:\r
435 break;\r
436 }\r
437 DEBUG ((DEBUG_VERBOSE, "\n"));\r
438 }\r
439 }\r
440}\r
441\r
442/**\r
443 Dump PHIT hob.\r
444\r
445 @param HobList the HOB list.\r
446**/\r
447VOID\r
448DumpPhitHob (\r
449 IN VOID *HobList\r
450 )\r
451{\r
452 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;\r
453\r
454 PhitHob = HobList;\r
455 ASSERT(GET_HOB_TYPE(HobList) == EFI_HOB_TYPE_HANDOFF);\r
456 DEBUG ((DEBUG_VERBOSE, "PHIT HOB\n"));\r
457 DEBUG ((DEBUG_VERBOSE, " PhitHob - 0x%x\n", PhitHob));\r
458 DEBUG ((DEBUG_VERBOSE, " BootMode - 0x%x\n", PhitHob->BootMode));\r
459 DEBUG ((DEBUG_VERBOSE, " EfiMemoryTop - 0x%016lx\n", PhitHob->EfiMemoryTop));\r
460 DEBUG ((DEBUG_VERBOSE, " EfiMemoryBottom - 0x%016lx\n", PhitHob->EfiMemoryBottom));\r
461 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob->EfiFreeMemoryTop));\r
462 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob->EfiFreeMemoryBottom));\r
463 DEBUG ((DEBUG_VERBOSE, " EfiEndOfHobList - 0x%lx\n", PhitHob->EfiEndOfHobList));\r
464}\r
465\r
466/**\r
467 Get the highest memory.\r
468\r
3f5ed3fa
JY
469 @return the highest memory.\r
470**/\r
471UINT64\r
472GetTopMemory (\r
8e9da4ba 473 VOID\r
3f5ed3fa
JY
474 )\r
475{\r
8e9da4ba 476 VOID *HobList;\r
3f5ed3fa
JY
477 EFI_PEI_HOB_POINTERS Hob;\r
478 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
479 UINT64 TopMemory;\r
480 UINT64 ResourceTop;\r
481\r
8e9da4ba
JY
482 HobList = GetHobList ();\r
483\r
3f5ed3fa
JY
484 TopMemory = 0;\r
485 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
486 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
487 ResourceHob = Hob.ResourceDescriptor;\r
488 switch (ResourceHob->ResourceType) {\r
489 case EFI_RESOURCE_SYSTEM_MEMORY:\r
490 ResourceTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;\r
491 if (TopMemory < ResourceTop) {\r
492 TopMemory = ResourceTop;\r
493 }\r
494 break;\r
495 default:\r
496 break;\r
497 }\r
498 DEBUG ((DEBUG_VERBOSE, "\n"));\r
499 }\r
500 }\r
501 return TopMemory;\r
502}\r
503\r
504/**\r
505 Initialize DMA protection.\r
506\r
507 @param DmaBufferSize the DMA buffer size\r
508 @param DmaBufferBase the DMA buffer base\r
509\r
510 @retval EFI_SUCCESS the DMA protection is initialized.\r
511 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
512**/\r
513EFI_STATUS\r
514InitDmaProtection (\r
515 IN UINTN DmaBufferSize,\r
516 OUT UINTN *DmaBufferBase\r
517 )\r
518{\r
519 EFI_STATUS Status;\r
520 VOID *HobList;\r
521 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;\r
522 UINT32 LowMemoryAlignment;\r
523 UINT64 HighMemoryAlignment;\r
524 UINTN MemoryAlignment;\r
525 UINTN LowBottom;\r
526 UINTN LowTop;\r
527 UINTN HighBottom;\r
528 UINT64 HighTop;\r
529\r
530 HobList = GetHobList ();\r
531 DumpPhitHob (HobList);\r
532 DumpResourceHob (HobList);\r
533\r
534 PhitHob = HobList;\r
535\r
536 ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);\r
537\r
8e9da4ba
JY
538 LowMemoryAlignment = GetLowMemoryAlignment (mEngineMask);\r
539 HighMemoryAlignment = GetHighMemoryAlignment (mEngineMask);\r
3f5ed3fa
JY
540 if (LowMemoryAlignment < HighMemoryAlignment) {\r
541 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
542 } else {\r
543 MemoryAlignment = LowMemoryAlignment;\r
544 }\r
545 ASSERT (DmaBufferSize == ALIGN_VALUE(DmaBufferSize, MemoryAlignment));\r
546 *DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize), MemoryAlignment);\r
547 if (*DmaBufferBase == 0) {\r
548 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
549 return EFI_OUT_OF_RESOURCES;\r
550 }\r
551\r
552 LowBottom = 0;\r
553 LowTop = *DmaBufferBase;\r
554 HighBottom = *DmaBufferBase + DmaBufferSize;\r
8e9da4ba 555 HighTop = GetTopMemory ();\r
3f5ed3fa
JY
556\r
557 Status = SetDmaProtectedRange (\r
8e9da4ba 558 mEngineMask,\r
3f5ed3fa
JY
559 (UINT32)LowBottom,\r
560 (UINT32)(LowTop - LowBottom),\r
561 HighBottom,\r
562 HighTop - HighBottom\r
563 );\r
564\r
565 if (EFI_ERROR(Status)) {\r
566 FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));\r
567 }\r
568\r
569 return Status;\r
570}\r
571\r
8e9da4ba
JY
572/**\r
573 Dump DMAR DeviceScopeEntry.\r
574\r
575 @param[in] DmarDeviceScopeEntry DMAR DeviceScopeEntry\r
576**/\r
577VOID\r
578DumpDmarDeviceScopeEntry (\r
579 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry\r
580 )\r
581{\r
582 UINTN PciPathNumber;\r
583 UINTN PciPathIndex;\r
584 EFI_ACPI_DMAR_PCI_PATH *PciPath;\r
585\r
586 if (DmarDeviceScopeEntry == NULL) {\r
587 return;\r
588 }\r
589\r
590 DEBUG ((DEBUG_INFO,\r
591 " *************************************************************************\n"\r
592 ));\r
593 DEBUG ((DEBUG_INFO,\r
594 " * DMA-Remapping Device Scope Entry Structure *\n"\r
595 ));\r
596 DEBUG ((DEBUG_INFO,\r
597 " *************************************************************************\n"\r
598 ));\r
599 DEBUG ((DEBUG_INFO,\r
600 (sizeof(UINTN) == sizeof(UINT64)) ?\r
601 " DMAR Device Scope Entry address ...................... 0x%016lx\n" :\r
602 " DMAR Device Scope Entry address ...................... 0x%08x\n",\r
603 DmarDeviceScopeEntry\r
604 ));\r
605 DEBUG ((DEBUG_INFO,\r
606 " Device Scope Entry Type ............................ 0x%02x\n",\r
607 DmarDeviceScopeEntry->Type\r
608 ));\r
609 switch (DmarDeviceScopeEntry->Type) {\r
610 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT:\r
611 DEBUG ((DEBUG_INFO,\r
612 " PCI Endpoint Device\n"\r
613 ));\r
614 break;\r
615 case EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE:\r
616 DEBUG ((DEBUG_INFO,\r
617 " PCI Sub-hierachy\n"\r
618 ));\r
619 break;\r
620 default:\r
621 break;\r
622 }\r
623 DEBUG ((DEBUG_INFO,\r
624 " Length ............................................. 0x%02x\n",\r
625 DmarDeviceScopeEntry->Length\r
626 ));\r
627 DEBUG ((DEBUG_INFO,\r
628 " Enumeration ID ..................................... 0x%02x\n",\r
629 DmarDeviceScopeEntry->EnumerationId\r
630 ));\r
631 DEBUG ((DEBUG_INFO,\r
632 " Starting Bus Number ................................ 0x%02x\n",\r
633 DmarDeviceScopeEntry->StartBusNumber\r
634 ));\r
635\r
636 PciPathNumber = (DmarDeviceScopeEntry->Length - sizeof(EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER)) / sizeof(EFI_ACPI_DMAR_PCI_PATH);\r
637 PciPath = (EFI_ACPI_DMAR_PCI_PATH *)(DmarDeviceScopeEntry + 1);\r
638 for (PciPathIndex = 0; PciPathIndex < PciPathNumber; PciPathIndex++) {\r
639 DEBUG ((DEBUG_INFO,\r
640 " Device ............................................. 0x%02x\n",\r
641 PciPath[PciPathIndex].Device\r
642 ));\r
643 DEBUG ((DEBUG_INFO,\r
644 " Function ........................................... 0x%02x\n",\r
645 PciPath[PciPathIndex].Function\r
646 ));\r
647 }\r
648\r
649 DEBUG ((DEBUG_INFO,\r
650 " *************************************************************************\n\n"\r
651 ));\r
652\r
653 return;\r
654}\r
655\r
656/**\r
657 Dump DMAR RMRR table.\r
658\r
659 @param[in] Rmrr DMAR RMRR table\r
660**/\r
661VOID\r
662DumpDmarRmrr (\r
663 IN EFI_ACPI_DMAR_RMRR_HEADER *Rmrr\r
664 )\r
665{\r
666 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
667 INTN RmrrLen;\r
668\r
669 if (Rmrr == NULL) {\r
670 return;\r
671 }\r
672\r
673 DEBUG ((DEBUG_INFO,\r
674 " ***************************************************************************\n"\r
675 ));\r
676 DEBUG ((DEBUG_INFO,\r
677 " * Reserved Memory Region Reporting Structure *\n"\r
678 ));\r
679 DEBUG ((DEBUG_INFO,\r
680 " ***************************************************************************\n"\r
681 ));\r
682 DEBUG ((DEBUG_INFO,\r
683 (sizeof(UINTN) == sizeof(UINT64)) ?\r
684 " RMRR address ........................................... 0x%016lx\n" :\r
685 " RMRR address ........................................... 0x%08x\n",\r
686 Rmrr\r
687 ));\r
688 DEBUG ((DEBUG_INFO,\r
689 " Type ................................................. 0x%04x\n",\r
690 Rmrr->Header.Type\r
691 ));\r
692 DEBUG ((DEBUG_INFO,\r
693 " Length ............................................... 0x%04x\n",\r
694 Rmrr->Header.Length\r
695 ));\r
696 DEBUG ((DEBUG_INFO,\r
697 " Segment Number ....................................... 0x%04x\n",\r
698 Rmrr->SegmentNumber\r
699 ));\r
700 DEBUG ((DEBUG_INFO,\r
701 " Reserved Memory Region Base Address .................. 0x%016lx\n",\r
702 Rmrr->ReservedMemoryRegionBaseAddress\r
703 ));\r
704 DEBUG ((DEBUG_INFO,\r
705 " Reserved Memory Region Limit Address ................. 0x%016lx\n",\r
706 Rmrr->ReservedMemoryRegionLimitAddress\r
707 ));\r
708\r
709 RmrrLen = Rmrr->Header.Length - sizeof(EFI_ACPI_DMAR_RMRR_HEADER);\r
710 DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Rmrr + 1);\r
711 while (RmrrLen > 0) {\r
712 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
713 RmrrLen -= DmarDeviceScopeEntry->Length;\r
714 DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
715 }\r
716\r
717 DEBUG ((DEBUG_INFO,\r
718 " ***************************************************************************\n\n"\r
719 ));\r
720\r
721 return;\r
722}\r
723\r
724/**\r
725 Dump DMAR DRHD table.\r
726\r
727 @param[in] Drhd DMAR DRHD table\r
728**/\r
729VOID\r
730DumpDmarDrhd (\r
731 IN EFI_ACPI_DMAR_DRHD_HEADER *Drhd\r
732 )\r
733{\r
734 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDeviceScopeEntry;\r
735 INTN DrhdLen;\r
736\r
737 if (Drhd == NULL) {\r
738 return;\r
739 }\r
740\r
741 DEBUG ((DEBUG_INFO,\r
742 " ***************************************************************************\n"\r
743 ));\r
744 DEBUG ((DEBUG_INFO,\r
745 " * DMA-Remapping Hardware Definition Structure *\n"\r
746 ));\r
747 DEBUG ((DEBUG_INFO,\r
748 " ***************************************************************************\n"\r
749 ));\r
750 DEBUG ((DEBUG_INFO,\r
751 (sizeof(UINTN) == sizeof(UINT64)) ?\r
752 " DRHD address ........................................... 0x%016lx\n" :\r
753 " DRHD address ........................................... 0x%08x\n",\r
754 Drhd\r
755 ));\r
756 DEBUG ((DEBUG_INFO,\r
757 " Type ................................................. 0x%04x\n",\r
758 Drhd->Header.Type\r
759 ));\r
760 DEBUG ((DEBUG_INFO,\r
761 " Length ............................................... 0x%04x\n",\r
762 Drhd->Header.Length\r
763 ));\r
764 DEBUG ((DEBUG_INFO,\r
765 " Flags ................................................ 0x%02x\n",\r
766 Drhd->Flags\r
767 ));\r
768 DEBUG ((DEBUG_INFO,\r
769 " INCLUDE_PCI_ALL .................................... 0x%02x\n",\r
770 Drhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL\r
771 ));\r
772 DEBUG ((DEBUG_INFO,\r
773 " Segment Number ....................................... 0x%04x\n",\r
774 Drhd->SegmentNumber\r
775 ));\r
776 DEBUG ((DEBUG_INFO,\r
777 " Register Base Address ................................ 0x%016lx\n",\r
778 Drhd->RegisterBaseAddress\r
779 ));\r
780\r
781 DrhdLen = Drhd->Header.Length - sizeof(EFI_ACPI_DMAR_DRHD_HEADER);\r
782 DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)(Drhd + 1);\r
783 while (DrhdLen > 0) {\r
784 DumpDmarDeviceScopeEntry (DmarDeviceScopeEntry);\r
785 DrhdLen -= DmarDeviceScopeEntry->Length;\r
786 DmarDeviceScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDeviceScopeEntry + DmarDeviceScopeEntry->Length);\r
787 }\r
788\r
789 DEBUG ((DEBUG_INFO,\r
790 " ***************************************************************************\n\n"\r
791 ));\r
792\r
793 return;\r
794}\r
795\r
796/**\r
797 Dump DMAR ACPI table.\r
798\r
799 @param[in] Dmar DMAR ACPI table\r
800**/\r
801VOID\r
802DumpAcpiDMAR (\r
803 IN EFI_ACPI_DMAR_HEADER *Dmar\r
804 )\r
805{\r
806 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
807 INTN DmarLen;\r
808\r
809 if (Dmar == NULL) {\r
810 return;\r
811 }\r
812\r
813 //\r
814 // Dump Dmar table\r
815 //\r
816 DEBUG ((DEBUG_INFO,\r
817 "*****************************************************************************\n"\r
818 ));\r
819 DEBUG ((DEBUG_INFO,\r
820 "* DMAR Table *\n"\r
821 ));\r
822 DEBUG ((DEBUG_INFO,\r
823 "*****************************************************************************\n"\r
824 ));\r
825\r
826 DEBUG ((DEBUG_INFO,\r
827 (sizeof(UINTN) == sizeof(UINT64)) ?\r
828 "DMAR address ............................................. 0x%016lx\n" :\r
829 "DMAR address ............................................. 0x%08x\n",\r
830 Dmar\r
831 ));\r
832\r
833 DEBUG ((DEBUG_INFO,\r
834 " Table Contents:\n"\r
835 ));\r
836 DEBUG ((DEBUG_INFO,\r
837 " Host Address Width ................................... 0x%02x\n",\r
838 Dmar->HostAddressWidth\r
839 ));\r
840 DEBUG ((DEBUG_INFO,\r
841 " Flags ................................................ 0x%02x\n",\r
842 Dmar->Flags\r
843 ));\r
844 DEBUG ((DEBUG_INFO,\r
845 " INTR_REMAP ......................................... 0x%02x\n",\r
846 Dmar->Flags & EFI_ACPI_DMAR_FLAGS_INTR_REMAP\r
847 ));\r
848 DEBUG ((DEBUG_INFO,\r
849 " X2APIC_OPT_OUT_SET ................................. 0x%02x\n",\r
850 Dmar->Flags & EFI_ACPI_DMAR_FLAGS_X2APIC_OPT_OUT\r
851 ));\r
852\r
853 DmarLen = Dmar->Header.Length - sizeof(EFI_ACPI_DMAR_HEADER);\r
854 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)(Dmar + 1);\r
855 while (DmarLen > 0) {\r
856 switch (DmarHeader->Type) {\r
857 case EFI_ACPI_DMAR_TYPE_DRHD:\r
858 DumpDmarDrhd ((EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
859 break;\r
860 case EFI_ACPI_DMAR_TYPE_RMRR:\r
861 DumpDmarRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
862 break;\r
863 default:\r
864 break;\r
865 }\r
866 DmarLen -= DmarHeader->Length;\r
867 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
868 }\r
869\r
870 DEBUG ((DEBUG_INFO,\r
871 "*****************************************************************************\n\n"\r
872 ));\r
873\r
874 return;\r
875}\r
876\r
877/**\r
878 Get VTd engine number.\r
879\r
880 @return the VTd engine number.\r
881**/\r
882UINTN\r
883GetVtdEngineNumber (\r
884 VOID\r
885 )\r
886{\r
887 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
888 UINTN VtdIndex;\r
889\r
890 VtdIndex = 0;\r
891 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
892 while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
893 switch (DmarHeader->Type) {\r
894 case EFI_ACPI_DMAR_TYPE_DRHD:\r
895 VtdIndex++;\r
896 break;\r
897 default:\r
898 break;\r
899 }\r
900 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
901 }\r
902 return VtdIndex ;\r
903}\r
904\r
905/**\r
906 Process DMAR DHRD table.\r
907\r
908 @param[in] VtdIndex The index of VTd engine.\r
909 @param[in] DmarDrhd The DRHD table.\r
910**/\r
911VOID\r
912ProcessDhrd (\r
913 IN UINTN VtdIndex,\r
914 IN EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd\r
915 )\r
916{\r
917 DEBUG ((DEBUG_INFO," VTD (%d) BaseAddress - 0x%016lx\n", VtdIndex, DmarDrhd->RegisterBaseAddress));\r
918 mVTdInfo->VTdEngineAddress[VtdIndex] = DmarDrhd->RegisterBaseAddress;\r
919}\r
920\r
921/**\r
922 Parse DMAR DRHD table.\r
923\r
924 @return EFI_SUCCESS The DMAR DRHD table is parsed.\r
925**/\r
926EFI_STATUS\r
927ParseDmarAcpiTableDrhd (\r
928 VOID\r
929 )\r
930{\r
931 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
932 UINTN VtdUnitNumber;\r
933 UINTN VtdIndex;\r
934\r
935 VtdUnitNumber = GetVtdEngineNumber ();\r
936 if (VtdUnitNumber == 0) {\r
937 return EFI_UNSUPPORTED;\r
938 }\r
939\r
940 mVTdInfo = AllocateZeroPool (sizeof(VTD_INFO) + (VtdUnitNumber - 1) * sizeof(UINT64));\r
941 if (mVTdInfo == NULL) {\r
942 return EFI_OUT_OF_RESOURCES;\r
943 }\r
944 mVTdInfo->HostAddressWidth = mAcpiDmarTable->HostAddressWidth;\r
945 mVTdInfo->VTdEngineCount = VtdUnitNumber;\r
946\r
947 VtdIndex = 0;\r
948 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
949 while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
950 switch (DmarHeader->Type) {\r
951 case EFI_ACPI_DMAR_TYPE_DRHD:\r
952 ASSERT (VtdIndex < VtdUnitNumber);\r
953 ProcessDhrd (VtdIndex, (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader);\r
954 VtdIndex++;\r
955\r
956 break;\r
957\r
958 default:\r
959 break;\r
960 }\r
961 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
962 }\r
963 ASSERT (VtdIndex == VtdUnitNumber);\r
964\r
965 //\r
966 // Initialize the engine mask to all.\r
967 //\r
968 mEngineMask = LShiftU64 (1, VtdUnitNumber) - 1;\r
969\r
970 return EFI_SUCCESS;\r
971}\r
972\r
973/**\r
974 Return the VTd engine index according to the Segment and DevScopeEntry.\r
975\r
976 @param Segment The segment of the VTd engine\r
977 @param DevScopeEntry The DevScopeEntry of the VTd engine\r
978\r
979 @return The VTd engine index according to the Segment and DevScopeEntry.\r
980 @retval -1 The VTd engine is not found.\r
981**/\r
982UINTN\r
983GetVTdEngineFromDevScopeEntry (\r
984 IN UINT16 Segment,\r
985 IN EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DevScopeEntry\r
986 )\r
987{\r
988 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
989 UINTN VtdIndex;\r
990 EFI_ACPI_DMAR_DRHD_HEADER *DmarDrhd;\r
991 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *ThisDevScopeEntry;\r
992\r
993 VtdIndex = 0;\r
994 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
995 while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
996 switch (DmarHeader->Type) {\r
997 case EFI_ACPI_DMAR_TYPE_DRHD:\r
998 DmarDrhd = (EFI_ACPI_DMAR_DRHD_HEADER *)DmarHeader;\r
999 if (DmarDrhd->SegmentNumber != Segment) {\r
1000 // Mismatch\r
1001 break;\r
1002 }\r
1003 if ((DmarDrhd->Header.Length == sizeof(EFI_ACPI_DMAR_DRHD_HEADER)) ||\r
1004 ((DmarDrhd->Flags & EFI_ACPI_DMAR_DRHD_FLAGS_INCLUDE_PCI_ALL) != 0)) {\r
1005 // No DevScopeEntry\r
1006 // Do not handle PCI_ALL\r
1007 break;\r
1008 }\r
1009 ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarDrhd + 1));\r
1010 while ((UINTN)ThisDevScopeEntry < (UINTN)DmarDrhd + DmarDrhd->Header.Length) {\r
1011 if ((ThisDevScopeEntry->Length == DevScopeEntry->Length) &&\r
1012 (CompareMem (ThisDevScopeEntry, DevScopeEntry, DevScopeEntry->Length) == 0)) {\r
1013 return VtdIndex;\r
1014 }\r
1015 ThisDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)ThisDevScopeEntry + ThisDevScopeEntry->Length);\r
1016 }\r
1017 break;\r
1018 default:\r
1019 break;\r
1020 }\r
1021 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
1022 }\r
1023 return (UINTN)-1;\r
1024}\r
1025\r
1026/**\r
1027 Process DMAR RMRR table.\r
1028\r
1029 @param[in] DmarRmrr The RMRR table.\r
1030**/\r
1031VOID\r
1032ProcessRmrr (\r
1033 IN EFI_ACPI_DMAR_RMRR_HEADER *DmarRmrr\r
1034 )\r
1035{\r
1036 EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *DmarDevScopeEntry;\r
1037 UINTN VTdIndex;\r
1038 UINT64 RmrrMask;\r
1039 UINTN LowBottom;\r
1040 UINTN LowTop;\r
1041 UINTN HighBottom;\r
1042 UINT64 HighTop;\r
1043\r
1044 DEBUG ((DEBUG_INFO," RMRR (Base 0x%016lx, Limit 0x%016lx)\n", DmarRmrr->ReservedMemoryRegionBaseAddress, DmarRmrr->ReservedMemoryRegionLimitAddress));\r
1045\r
1046 if ((DmarRmrr->ReservedMemoryRegionBaseAddress == 0) ||\r
1047 (DmarRmrr->ReservedMemoryRegionLimitAddress == 0)) {\r
1048 return ;\r
1049 }\r
1050\r
1051 DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)(DmarRmrr + 1));\r
1052 while ((UINTN)DmarDevScopeEntry < (UINTN)DmarRmrr + DmarRmrr->Header.Length) {\r
1053 ASSERT (DmarDevScopeEntry->Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT);\r
1054\r
1055 VTdIndex = GetVTdEngineFromDevScopeEntry (DmarRmrr->SegmentNumber, DmarDevScopeEntry);\r
1056 if (VTdIndex != (UINTN)-1) {\r
1057 RmrrMask = LShiftU64 (1, VTdIndex);\r
1058\r
1059 LowBottom = 0;\r
1060 LowTop = (UINTN)DmarRmrr->ReservedMemoryRegionBaseAddress;\r
1061 HighBottom = (UINTN)DmarRmrr->ReservedMemoryRegionLimitAddress + 1;\r
1062 HighTop = GetTopMemory ();\r
1063\r
1064 SetDmaProtectedRange (\r
1065 RmrrMask,\r
1066 0,\r
1067 (UINT32)(LowTop - LowBottom),\r
1068 HighBottom,\r
1069 HighTop - HighBottom\r
1070 );\r
1071\r
1072 //\r
1073 // Remove the engine from the engine mask.\r
1074 // The assumption is that any other PEI driver does not access\r
1075 // the device covered by this engine.\r
1076 //\r
1077 mEngineMask = mEngineMask & (~RmrrMask);\r
1078 }\r
1079\r
1080 DmarDevScopeEntry = (EFI_ACPI_DMAR_DEVICE_SCOPE_STRUCTURE_HEADER *)((UINTN)DmarDevScopeEntry + DmarDevScopeEntry->Length);\r
1081 }\r
1082}\r
1083\r
1084/**\r
1085 Parse DMAR DRHD table.\r
1086**/\r
1087VOID\r
1088ParseDmarAcpiTableRmrr (\r
1089 VOID\r
1090 )\r
1091{\r
1092 EFI_ACPI_DMAR_STRUCTURE_HEADER *DmarHeader;\r
1093\r
1094 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)(mAcpiDmarTable + 1));\r
1095 while ((UINTN)DmarHeader < (UINTN)mAcpiDmarTable + mAcpiDmarTable->Header.Length) {\r
1096 switch (DmarHeader->Type) {\r
1097 case EFI_ACPI_DMAR_TYPE_RMRR:\r
1098 ProcessRmrr ((EFI_ACPI_DMAR_RMRR_HEADER *)DmarHeader);\r
1099 break;\r
1100 default:\r
1101 break;\r
1102 }\r
1103 DmarHeader = (EFI_ACPI_DMAR_STRUCTURE_HEADER *)((UINTN)DmarHeader + DmarHeader->Length);\r
1104 }\r
1105}\r
1106\r
3f5ed3fa
JY
1107/**\r
1108 Initializes the Intel VTd PMR PEIM.\r
1109\r
1110 @param FileHandle Handle of the file being invoked.\r
1111 @param PeiServices Describes the list of possible PEI Services.\r
1112\r
1113 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
1114 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
1115\r
1116**/\r
1117EFI_STATUS\r
1118EFIAPI\r
1119IntelVTdPmrInitialize (\r
1120 IN EFI_PEI_FILE_HANDLE FileHandle,\r
1121 IN CONST EFI_PEI_SERVICES **PeiServices\r
1122 )\r
1123{\r
1124 EFI_STATUS Status;\r
1125\r
1126 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
1127 return EFI_UNSUPPORTED;\r
1128 }\r
1129\r
1130 Status = PeiServicesLocatePpi (\r
1131 &gEdkiiVTdInfoPpiGuid,\r
1132 0,\r
1133 NULL,\r
8e9da4ba 1134 (VOID **)&mAcpiDmarTable\r
3f5ed3fa
JY
1135 );\r
1136 ASSERT_EFI_ERROR(Status);\r
1137\r
8e9da4ba
JY
1138 DumpAcpiDMAR (mAcpiDmarTable);\r
1139\r
1140 //\r
1141 // Get DMAR information to local VTdInfo\r
1142 //\r
1143 Status = ParseDmarAcpiTableDrhd ();\r
1144 if (EFI_ERROR(Status)) {\r
1145 return Status;\r
1146 }\r
1147\r
1148 //\r
1149 // If there is RMRR memory, parse it here.\r
1150 //\r
1151 ParseDmarAcpiTableRmrr ();\r
1152\r
3f5ed3fa
JY
1153 //\r
1154 // Find a pre-memory in resource hob as DMA buffer\r
1155 // Mark PEI memory to be DMA protected.\r
1156 //\r
1157 Status = InitDmaProtection (mDmaBufferSize, &mDmaBufferBase);\r
1158 if (EFI_ERROR(Status)) {\r
1159 return Status;\r
1160 }\r
1161\r
1162 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", mDmaBufferBase));\r
1163 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", mDmaBufferSize));\r
1164\r
1165 mDmaBufferCurrentTop = mDmaBufferBase + mDmaBufferSize;\r
1166 mDmaBufferCurrentBottom = mDmaBufferBase;\r
1167\r
1168 //\r
1169 // Install PPI.\r
1170 //\r
1171 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
1172 ASSERT_EFI_ERROR(Status);\r
1173\r
1174 return Status;\r
1175}\r
1176\r