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