IntelSiliconPkg/VtdPmrPei: Add premem support.
[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
a1e7cd0b 27#include <Ppi/MemoryDiscovered.h>\r
fc8be1ad 28#include <Ppi/EndOfPeiPhase.h>\r
3f5ed3fa
JY
29\r
30#include "IntelVTdPmrPei.h"\r
31\r
32#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB\r
fc8be1ad 33#define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB\r
3f5ed3fa 34\r
a1e7cd0b
JY
35EFI_GUID mVTdInfoGuid = {\r
36 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }\r
37};\r
38\r
39EFI_GUID mDmaBufferInfoGuid = {\r
40 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }\r
41};\r
42\r
43typedef struct {\r
44 UINTN DmaBufferBase;\r
45 UINTN DmaBufferSize;\r
46 UINTN DmaBufferCurrentTop;\r
47 UINTN DmaBufferCurrentBottom;\r
48} DMA_BUFFER_INFO;\r
3f5ed3fa
JY
49\r
50#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
51typedef struct {\r
52 UINT32 Signature;\r
53 EDKII_IOMMU_OPERATION Operation;\r
54 UINTN NumberOfBytes;\r
55 EFI_PHYSICAL_ADDRESS HostAddress;\r
56 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
57} MAP_INFO;\r
58\r
59/**\r
60\r
61 PEI Memory Layout:\r
62\r
8e9da4ba
JY
63 +------------------+ <=============== PHMR.Limit (Top of memory)\r
64 | Mem Resource |\r
65 | |\r
66\r
3f5ed3fa
JY
67 +------------------+ <------- EfiMemoryTop\r
68 | PEI allocated |\r
8e9da4ba 69 =========== +==================+ <=============== PHMR.Base\r
3f5ed3fa
JY
70 ^ | Commom Buf |\r
71 | | -------------- |\r
72 DMA Buffer | * DMA FREE * |\r
73 | | -------------- |\r
74 V | Read/Write Buf |\r
8e9da4ba 75 =========== +==================+ <=============== PLMR.Limit\r
3f5ed3fa
JY
76 | PEI allocated |\r
77 | -------------- | <------- EfiFreeMemoryTop\r
78 | * PEI FREE * |\r
79 | -------------- | <------- EfiFreeMemoryBottom\r
80 | hob |\r
81 | -------------- |\r
82 | Stack |\r
83 +------------------+ <------- EfiMemoryBottom / Stack Bottom\r
84\r
85 +------------------+\r
86 | Mem Alloc Hob |\r
87 +------------------+\r
88\r
8e9da4ba
JY
89 | |\r
90 | Mem Resource |\r
91 +------------------+ <=============== PLMR.Base (0)\r
3f5ed3fa
JY
92**/\r
93\r
3f5ed3fa
JY
94/**\r
95 Set IOMMU attribute for a system memory.\r
96\r
97 If the IOMMU PPI exists, the system memory cannot be used\r
98 for DMA by default.\r
99\r
100 When a device requests a DMA access for a system memory,\r
101 the device driver need use SetAttribute() to update the IOMMU\r
102 attribute to request DMA access (read and/or write).\r
103\r
104 @param[in] This The PPI instance pointer.\r
105 @param[in] Mapping The mapping value returned from Map().\r
106 @param[in] IoMmuAccess The IOMMU access.\r
107\r
108 @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by DeviceAddress and Length.\r
109 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
110 @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.\r
111 @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.\r
112 @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by Mapping.\r
113 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.\r
114 @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.\r
115\r
116**/\r
117EFI_STATUS\r
118EFIAPI\r
119PeiIoMmuSetAttribute (\r
120 IN EDKII_IOMMU_PPI *This,\r
121 IN VOID *Mapping,\r
122 IN UINT64 IoMmuAccess\r
123 )\r
124{\r
125 return EFI_SUCCESS;\r
126}\r
127\r
128/**\r
129 Provides the controller-specific addresses required to access system memory from a\r
130 DMA bus master.\r
131\r
132 @param This The PPI instance pointer.\r
133 @param Operation Indicates if the bus master is going to read or write to system memory.\r
134 @param HostAddress The system memory address to map to the PCI controller.\r
135 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
136 that were mapped.\r
137 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
138 access the hosts HostAddress.\r
139 @param Mapping A resulting value to pass to Unmap().\r
140\r
141 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
142 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
143 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
144 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
145 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
146\r
147**/\r
148EFI_STATUS\r
149EFIAPI\r
150PeiIoMmuMap (\r
151 IN EDKII_IOMMU_PPI *This,\r
152 IN EDKII_IOMMU_OPERATION Operation,\r
153 IN VOID *HostAddress,\r
154 IN OUT UINTN *NumberOfBytes,\r
155 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
156 OUT VOID **Mapping\r
157 )\r
158{\r
a1e7cd0b
JY
159 MAP_INFO *MapInfo;\r
160 UINTN Length;\r
161 VOID *Hob;\r
162 DMA_BUFFER_INFO *DmaBufferInfo;\r
163\r
164 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
165 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
166\r
167 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
168 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
169 *DeviceAddress = (UINTN)HostAddress;\r
170 *Mapping = 0;\r
171 return EFI_SUCCESS;\r
172 }\r
173\r
174 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
a1e7cd0b
JY
175 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
176 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
177\r
178 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b 179 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
180 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
181 ASSERT (FALSE);\r
182 return EFI_OUT_OF_RESOURCES;\r
183 }\r
184\r
a1e7cd0b
JY
185 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
186 DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
3f5ed3fa
JY
187\r
188 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
189 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
190 MapInfo->Operation = Operation;\r
191 MapInfo->NumberOfBytes = *NumberOfBytes;\r
192 MapInfo->HostAddress = (UINTN)HostAddress;\r
193 MapInfo->DeviceAddress = *DeviceAddress;\r
194 *Mapping = MapInfo;\r
195 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));\r
196\r
197 //\r
198 // If this is a read operation from the Bus Master's point of view,\r
199 // then copy the contents of the real buffer into the mapped buffer\r
200 // so the Bus Master can read the contents of the real buffer.\r
201 //\r
202 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
203 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
204 CopyMem (\r
205 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
206 (VOID *) (UINTN) MapInfo->HostAddress,\r
207 MapInfo->NumberOfBytes\r
208 );\r
209 }\r
210\r
211 return EFI_SUCCESS;\r
212}\r
213\r
214/**\r
215 Completes the Map() operation and releases any corresponding resources.\r
216\r
217 @param This The PPI instance pointer.\r
218 @param Mapping The mapping value returned from Map().\r
219\r
220 @retval EFI_SUCCESS The range was unmapped.\r
221 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
222 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
223**/\r
224EFI_STATUS\r
225EFIAPI\r
226PeiIoMmuUnmap (\r
227 IN EDKII_IOMMU_PPI *This,\r
228 IN VOID *Mapping\r
229 )\r
230{\r
a1e7cd0b
JY
231 MAP_INFO *MapInfo;\r
232 UINTN Length;\r
233 VOID *Hob;\r
234 DMA_BUFFER_INFO *DmaBufferInfo;\r
235\r
236 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
237 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
238\r
239 if (Mapping == NULL) {\r
240 return EFI_SUCCESS;\r
241 }\r
242\r
243 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
a1e7cd0b
JY
244 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
245 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
246\r
247 MapInfo = Mapping;\r
248 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
249 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));\r
250\r
251 //\r
252 // If this is a write operation from the Bus Master's point of view,\r
253 // then copy the contents of the mapped buffer into the real buffer\r
254 // so the processor can read the contents of the real buffer.\r
255 //\r
256 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
257 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
258 CopyMem (\r
259 (VOID *) (UINTN) MapInfo->HostAddress,\r
260 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
261 MapInfo->NumberOfBytes\r
262 );\r
263 }\r
264\r
265 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b
JY
266 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
267 DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
3f5ed3fa
JY
268 }\r
269\r
270 return EFI_SUCCESS;\r
271}\r
272\r
273/**\r
274 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
275 OperationBusMasterCommonBuffer64 mapping.\r
276\r
277 @param This The PPI instance pointer.\r
278 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
279 EfiRuntimeServicesData.\r
280 @param Pages The number of pages to allocate.\r
281 @param HostAddress A pointer to store the base system memory address of the\r
282 allocated range.\r
283 @param Attributes The requested bit mask of attributes for the allocated range.\r
284\r
285 @retval EFI_SUCCESS The requested memory pages were allocated.\r
286 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
287 MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
288 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
289 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
290\r
291**/\r
292EFI_STATUS\r
293EFIAPI\r
294PeiIoMmuAllocateBuffer (\r
295 IN EDKII_IOMMU_PPI *This,\r
296 IN EFI_MEMORY_TYPE MemoryType,\r
297 IN UINTN Pages,\r
298 IN OUT VOID **HostAddress,\r
299 IN UINT64 Attributes\r
300 )\r
301{\r
a1e7cd0b
JY
302 UINTN Length;\r
303 VOID *Hob;\r
304 DMA_BUFFER_INFO *DmaBufferInfo;\r
305\r
306 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
307 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
308\r
309 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
a1e7cd0b
JY
310 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
311 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
312\r
313 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b 314 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
315 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
316 ASSERT (FALSE);\r
317 return EFI_OUT_OF_RESOURCES;\r
318 }\r
a1e7cd0b
JY
319 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
320 DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
3f5ed3fa
JY
321\r
322 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
323 return EFI_SUCCESS;\r
324}\r
325\r
326/**\r
327 Frees memory that was allocated with AllocateBuffer().\r
328\r
329 @param This The PPI instance pointer.\r
330 @param Pages The number of pages to free.\r
331 @param HostAddress The base system memory address of the allocated range.\r
332\r
333 @retval EFI_SUCCESS The requested memory pages were freed.\r
334 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
335 was not allocated with AllocateBuffer().\r
336\r
337**/\r
338EFI_STATUS\r
339EFIAPI\r
340PeiIoMmuFreeBuffer (\r
341 IN EDKII_IOMMU_PPI *This,\r
342 IN UINTN Pages,\r
343 IN VOID *HostAddress\r
344 )\r
345{\r
a1e7cd0b
JY
346 UINTN Length;\r
347 VOID *Hob;\r
348 DMA_BUFFER_INFO *DmaBufferInfo;\r
349\r
350 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
351 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
352\r
353 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
a1e7cd0b
JY
354 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
355 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa
JY
356\r
357 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b
JY
358 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
359 DmaBufferInfo->DmaBufferCurrentTop += Length;\r
3f5ed3fa
JY
360 }\r
361\r
362 return EFI_SUCCESS;\r
363}\r
364\r
365EDKII_IOMMU_PPI mIoMmuPpi = {\r
366 EDKII_IOMMU_PPI_REVISION,\r
367 PeiIoMmuSetAttribute,\r
368 PeiIoMmuMap,\r
369 PeiIoMmuUnmap,\r
370 PeiIoMmuAllocateBuffer,\r
371 PeiIoMmuFreeBuffer,\r
372};\r
373\r
374CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {\r
375 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
376 &gEdkiiIoMmuPpiGuid,\r
377 (VOID *) &mIoMmuPpi\r
378};\r
379\r
380#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \\r
381 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \\r
382 EFI_RESOURCE_ATTRIBUTE_TESTED | \\r
383 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \\r
384 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \\r
385 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO \\r
386 )\r
387\r
388#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED | EFI_RESOURCE_ATTRIBUTE_TESTED)\r
389\r
390#define INITIALIZED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED)\r
391\r
392#define PRESENT_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT)\r
393\r
394GLOBAL_REMOVE_IF_UNREFERENCED CHAR8 *mResourceTypeShortName[] = {\r
395 "Mem",\r
396 "MMIO",\r
397 "I/O",\r
398 "FD",\r
399 "MM Port I/O",\r
400 "Reserved Mem",\r
401 "Reserved I/O",\r
402};\r
403\r
404/**\r
405 Return the short name of resource type.\r
406\r
407 @param Type resource type.\r
408\r
409 @return the short name of resource type.\r
410**/\r
411CHAR8 *\r
412ShortNameOfResourceType (\r
413 IN UINT32 Type\r
414 )\r
415{\r
416 if (Type < sizeof(mResourceTypeShortName) / sizeof(mResourceTypeShortName[0])) {\r
417 return mResourceTypeShortName[Type];\r
418 } else {\r
419 return "Unknown";\r
420 }\r
421}\r
422\r
423/**\r
424 Dump resource hob.\r
425\r
426 @param HobList the HOB list.\r
427**/\r
428VOID\r
429DumpResourceHob (\r
430 IN VOID *HobList\r
431 )\r
432{\r
433 EFI_PEI_HOB_POINTERS Hob;\r
434 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
435\r
436 DEBUG ((DEBUG_VERBOSE, "Resource Descriptor HOBs\n"));\r
437 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
438 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
439 ResourceHob = Hob.ResourceDescriptor;\r
440 DEBUG ((DEBUG_VERBOSE,\r
441 " BA=%016lx L=%016lx Attr=%08x ",\r
442 ResourceHob->PhysicalStart,\r
443 ResourceHob->ResourceLength,\r
444 ResourceHob->ResourceAttribute\r
445 ));\r
446 DEBUG ((DEBUG_VERBOSE, ShortNameOfResourceType(ResourceHob->ResourceType)));\r
447 switch (ResourceHob->ResourceType) {\r
448 case EFI_RESOURCE_SYSTEM_MEMORY:\r
449 if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) != 0) {\r
450 DEBUG ((DEBUG_VERBOSE, " (Persistent)"));\r
451 } else if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) != 0) {\r
452 DEBUG ((DEBUG_VERBOSE, " (MoreReliable)"));\r
453 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {\r
454 DEBUG ((DEBUG_VERBOSE, " (Tested)"));\r
455 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {\r
456 DEBUG ((DEBUG_VERBOSE, " (Init)"));\r
457 } else if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {\r
458 DEBUG ((DEBUG_VERBOSE, " (Present)"));\r
459 } else {\r
460 DEBUG ((DEBUG_VERBOSE, " (Unknown)"));\r
461 }\r
462 break;\r
463 default:\r
464 break;\r
465 }\r
466 DEBUG ((DEBUG_VERBOSE, "\n"));\r
467 }\r
468 }\r
469}\r
470\r
471/**\r
472 Dump PHIT hob.\r
473\r
474 @param HobList the HOB list.\r
475**/\r
476VOID\r
477DumpPhitHob (\r
478 IN VOID *HobList\r
479 )\r
480{\r
481 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;\r
482\r
483 PhitHob = HobList;\r
484 ASSERT(GET_HOB_TYPE(HobList) == EFI_HOB_TYPE_HANDOFF);\r
485 DEBUG ((DEBUG_VERBOSE, "PHIT HOB\n"));\r
486 DEBUG ((DEBUG_VERBOSE, " PhitHob - 0x%x\n", PhitHob));\r
487 DEBUG ((DEBUG_VERBOSE, " BootMode - 0x%x\n", PhitHob->BootMode));\r
488 DEBUG ((DEBUG_VERBOSE, " EfiMemoryTop - 0x%016lx\n", PhitHob->EfiMemoryTop));\r
489 DEBUG ((DEBUG_VERBOSE, " EfiMemoryBottom - 0x%016lx\n", PhitHob->EfiMemoryBottom));\r
490 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryTop - 0x%016lx\n", PhitHob->EfiFreeMemoryTop));\r
491 DEBUG ((DEBUG_VERBOSE, " EfiFreeMemoryBottom - 0x%016lx\n", PhitHob->EfiFreeMemoryBottom));\r
492 DEBUG ((DEBUG_VERBOSE, " EfiEndOfHobList - 0x%lx\n", PhitHob->EfiEndOfHobList));\r
493}\r
494\r
495/**\r
496 Get the highest memory.\r
497\r
3f5ed3fa
JY
498 @return the highest memory.\r
499**/\r
500UINT64\r
501GetTopMemory (\r
8e9da4ba 502 VOID\r
3f5ed3fa
JY
503 )\r
504{\r
8e9da4ba 505 VOID *HobList;\r
3f5ed3fa
JY
506 EFI_PEI_HOB_POINTERS Hob;\r
507 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;\r
508 UINT64 TopMemory;\r
509 UINT64 ResourceTop;\r
510\r
8e9da4ba
JY
511 HobList = GetHobList ();\r
512\r
3f5ed3fa
JY
513 TopMemory = 0;\r
514 for (Hob.Raw = HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {\r
515 if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {\r
516 ResourceHob = Hob.ResourceDescriptor;\r
517 switch (ResourceHob->ResourceType) {\r
518 case EFI_RESOURCE_SYSTEM_MEMORY:\r
519 ResourceTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;\r
520 if (TopMemory < ResourceTop) {\r
521 TopMemory = ResourceTop;\r
522 }\r
523 break;\r
524 default:\r
525 break;\r
526 }\r
527 DEBUG ((DEBUG_VERBOSE, "\n"));\r
528 }\r
529 }\r
530 return TopMemory;\r
531}\r
532\r
533/**\r
534 Initialize DMA protection.\r
535\r
a1e7cd0b 536 @param VTdInfo The VTd engine context information.\r
3f5ed3fa
JY
537 @param DmaBufferSize the DMA buffer size\r
538 @param DmaBufferBase the DMA buffer base\r
539\r
540 @retval EFI_SUCCESS the DMA protection is initialized.\r
541 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
542**/\r
543EFI_STATUS\r
544InitDmaProtection (\r
a1e7cd0b
JY
545 IN VTD_INFO *VTdInfo,\r
546 IN UINTN DmaBufferSize,\r
547 OUT UINTN *DmaBufferBase\r
3f5ed3fa
JY
548 )\r
549{\r
550 EFI_STATUS Status;\r
551 VOID *HobList;\r
552 EFI_HOB_HANDOFF_INFO_TABLE *PhitHob;\r
553 UINT32 LowMemoryAlignment;\r
554 UINT64 HighMemoryAlignment;\r
555 UINTN MemoryAlignment;\r
556 UINTN LowBottom;\r
557 UINTN LowTop;\r
558 UINTN HighBottom;\r
559 UINT64 HighTop;\r
560\r
561 HobList = GetHobList ();\r
562 DumpPhitHob (HobList);\r
563 DumpResourceHob (HobList);\r
564\r
565 PhitHob = HobList;\r
566\r
567 ASSERT (PhitHob->EfiMemoryBottom < PhitHob->EfiMemoryTop);\r
568\r
a1e7cd0b
JY
569 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
570 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
3f5ed3fa
JY
571 if (LowMemoryAlignment < HighMemoryAlignment) {\r
572 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
573 } else {\r
574 MemoryAlignment = LowMemoryAlignment;\r
575 }\r
576 ASSERT (DmaBufferSize == ALIGN_VALUE(DmaBufferSize, MemoryAlignment));\r
577 *DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize), MemoryAlignment);\r
fc8be1ad 578 ASSERT (*DmaBufferBase != 0);\r
3f5ed3fa
JY
579 if (*DmaBufferBase == 0) {\r
580 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
581 return EFI_OUT_OF_RESOURCES;\r
582 }\r
583\r
584 LowBottom = 0;\r
585 LowTop = *DmaBufferBase;\r
586 HighBottom = *DmaBufferBase + DmaBufferSize;\r
8e9da4ba 587 HighTop = GetTopMemory ();\r
3f5ed3fa
JY
588\r
589 Status = SetDmaProtectedRange (\r
a1e7cd0b
JY
590 VTdInfo,\r
591 VTdInfo->EngineMask,\r
592 (UINT32)LowBottom,\r
593 (UINT32)(LowTop - LowBottom),\r
594 HighBottom,\r
595 HighTop - HighBottom\r
596 );\r
3f5ed3fa
JY
597\r
598 if (EFI_ERROR(Status)) {\r
599 FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));\r
600 }\r
601\r
602 return Status;\r
603}\r
604\r
8e9da4ba 605/**\r
a1e7cd0b
JY
606 Initializes the Intel VTd Info.\r
607\r
608 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
609 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 610\r
8e9da4ba 611**/\r
a1e7cd0b
JY
612EFI_STATUS\r
613InitVTdInfo (\r
614 VOID\r
8e9da4ba
JY
615 )\r
616{\r
a1e7cd0b
JY
617 EFI_STATUS Status;\r
618 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
619 VOID *Hob;\r
8e9da4ba 620\r
a1e7cd0b
JY
621 Status = PeiServicesLocatePpi (\r
622 &gEdkiiVTdInfoPpiGuid,\r
623 0,\r
624 NULL,\r
625 (VOID **)&AcpiDmarTable\r
626 );\r
627 ASSERT_EFI_ERROR(Status);\r
8e9da4ba 628\r
a1e7cd0b 629 DumpAcpiDMAR (AcpiDmarTable);\r
8e9da4ba 630\r
a1e7cd0b
JY
631 //\r
632 // Clear old VTdInfo Hob.\r
633 //\r
634 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
635 if (Hob != NULL) {\r
636 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\r
8e9da4ba
JY
637 }\r
638\r
a1e7cd0b
JY
639 //\r
640 // Get DMAR information to local VTdInfo\r
641 //\r
642 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
643 if (EFI_ERROR(Status)) {\r
644 return Status;\r
8e9da4ba
JY
645 }\r
646\r
a1e7cd0b
JY
647 //\r
648 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
649 //\r
8e9da4ba 650\r
a1e7cd0b 651 return EFI_SUCCESS;\r
8e9da4ba
JY
652}\r
653\r
654/**\r
a1e7cd0b
JY
655 Initializes the Intel VTd PMR for all memory.\r
656\r
657 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
658 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 659\r
8e9da4ba 660**/\r
a1e7cd0b
JY
661EFI_STATUS\r
662InitVTdPmrForAll (\r
663 VOID\r
8e9da4ba
JY
664 )\r
665{\r
a1e7cd0b
JY
666 EFI_STATUS Status;\r
667 VOID *Hob;\r
668 VTD_INFO *VTdInfo;\r
669 UINTN LowBottom;\r
670 UINTN LowTop;\r
671 UINTN HighBottom;\r
672 UINT64 HighTop;\r
8e9da4ba 673\r
a1e7cd0b
JY
674 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
675 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 676\r
a1e7cd0b
JY
677 LowBottom = 0;\r
678 LowTop = 0;\r
679 HighBottom = 0;\r
680 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth);\r
8e9da4ba 681\r
a1e7cd0b
JY
682 Status = SetDmaProtectedRange (\r
683 VTdInfo,\r
684 VTdInfo->EngineMask,\r
685 (UINT32)LowBottom,\r
686 (UINT32)(LowTop - LowBottom),\r
687 HighBottom,\r
688 HighTop - HighBottom\r
689 );\r
8e9da4ba 690\r
a1e7cd0b 691 return Status;\r
8e9da4ba
JY
692}\r
693\r
694/**\r
a1e7cd0b
JY
695 Initializes the Intel VTd PMR for DMA buffer.\r
696\r
697 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
698 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 699\r
8e9da4ba 700**/\r
a1e7cd0b
JY
701EFI_STATUS\r
702InitVTdPmrForDma (\r
703 VOID\r
8e9da4ba
JY
704 )\r
705{\r
a1e7cd0b
JY
706 EFI_STATUS Status;\r
707 VOID *Hob;\r
708 VTD_INFO *VTdInfo;\r
709 DMA_BUFFER_INFO *DmaBufferInfo;\r
8e9da4ba 710\r
a1e7cd0b
JY
711 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
712 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba
JY
713\r
714 //\r
a1e7cd0b 715 // If there is RMRR memory, parse it here.\r
8e9da4ba 716 //\r
a1e7cd0b 717 ParseDmarAcpiTableRmrr (VTdInfo);\r
8e9da4ba 718\r
a1e7cd0b
JY
719 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
720 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 721\r
a1e7cd0b
JY
722 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
723 //\r
724 // Find a pre-memory in resource hob as DMA buffer\r
725 // Mark PEI memory to be DMA protected.\r
726 //\r
727 Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);\r
728 if (EFI_ERROR(Status)) {\r
729 return Status;\r
8e9da4ba 730 }\r
8e9da4ba 731\r
a1e7cd0b 732 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\r
8e9da4ba 733\r
a1e7cd0b
JY
734 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
735 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
8e9da4ba
JY
736\r
737 //\r
a1e7cd0b 738 // Install PPI.\r
8e9da4ba 739 //\r
a1e7cd0b
JY
740 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
741 ASSERT_EFI_ERROR(Status);\r
8e9da4ba 742\r
a1e7cd0b 743 return Status;\r
8e9da4ba
JY
744}\r
745\r
746/**\r
a1e7cd0b 747 This function handles S3 resume task at the end of PEI\r
8e9da4ba 748\r
a1e7cd0b
JY
749 @param[in] PeiServices Pointer to PEI Services Table.\r
750 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
751 caused this function to execute.\r
752 @param[in] Ppi Pointer to the PPI data associated with this function.\r
8e9da4ba 753\r
a1e7cd0b 754 @retval EFI_STATUS Always return EFI_SUCCESS\r
8e9da4ba 755**/\r
a1e7cd0b
JY
756EFI_STATUS\r
757EFIAPI\r
758S3EndOfPeiNotify(\r
759 IN EFI_PEI_SERVICES **PeiServices,\r
760 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
761 IN VOID *Ppi\r
8e9da4ba
JY
762 )\r
763{\r
a1e7cd0b
JY
764 VOID *Hob;\r
765 VTD_INFO *VTdInfo;\r
766 UINT64 EngineMask;\r
8e9da4ba 767\r
a1e7cd0b 768 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
8e9da4ba 769\r
a1e7cd0b
JY
770 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
771 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
772 if (Hob == NULL) {\r
773 return EFI_SUCCESS;\r
8e9da4ba 774 }\r
a1e7cd0b 775 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 776\r
a1e7cd0b
JY
777 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
778 DisableDmaProtection (VTdInfo, EngineMask);\r
8e9da4ba 779 }\r
a1e7cd0b 780 return EFI_SUCCESS;\r
8e9da4ba
JY
781}\r
782\r
a1e7cd0b
JY
783EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
784 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
785 &gEfiEndOfPeiSignalPpiGuid,\r
786 S3EndOfPeiNotify\r
787};\r
8e9da4ba 788\r
fc8be1ad 789/**\r
a1e7cd0b 790 This function handles VTd engine setup\r
fc8be1ad
JY
791\r
792 @param[in] PeiServices Pointer to PEI Services Table.\r
793 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
794 caused this function to execute.\r
795 @param[in] Ppi Pointer to the PPI data associated with this function.\r
796\r
797 @retval EFI_STATUS Always return EFI_SUCCESS\r
798**/\r
799EFI_STATUS\r
800EFIAPI\r
a1e7cd0b 801VTdInfoNotify (\r
fc8be1ad
JY
802 IN EFI_PEI_SERVICES **PeiServices,\r
803 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
804 IN VOID *Ppi\r
805 )\r
806{\r
a1e7cd0b
JY
807 EFI_STATUS Status;\r
808 VOID *MemoryDiscovered;\r
809 UINT64 EnabledEngineMask;\r
810 VOID *Hob;\r
811 VTD_INFO *VTdInfo;\r
812 BOOLEAN MemoryInitialized;\r
fc8be1ad 813\r
a1e7cd0b
JY
814 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
815\r
816 //\r
817 // Check if memory is initialized.\r
818 //\r
819 MemoryInitialized = FALSE;\r
820 Status = PeiServicesLocatePpi (\r
821 &gEfiPeiMemoryDiscoveredPpiGuid,\r
822 0,\r
823 NULL,\r
824 &MemoryDiscovered\r
825 );\r
826 if (!EFI_ERROR(Status)) {\r
827 MemoryInitialized = TRUE;\r
828 }\r
829\r
830 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
831\r
832 if (!MemoryInitialized) {\r
833 //\r
834 // If the memory is not initialized,\r
835 // Protect all system memory\r
836 //\r
837 InitVTdInfo ();\r
838 InitVTdPmrForAll ();\r
839 } else {\r
840 //\r
841 // If the memory is initialized,\r
842 // Allocate DMA buffer and protect rest system memory\r
843 //\r
844\r
845 //\r
846 // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
847 //\r
848 InitVTdInfo ();\r
849\r
850 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
851 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
852\r
853 //\r
854 // NOTE: We need check if PMR is enabled or not.\r
855 //\r
856 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
857 if (EnabledEngineMask != 0) {\r
858 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
859 DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
860 }\r
861 InitVTdPmrForDma ();\r
862 if (EnabledEngineMask != 0) {\r
863 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
864 }\r
fc8be1ad 865\r
fc8be1ad 866 }\r
a1e7cd0b 867\r
fc8be1ad
JY
868 return EFI_SUCCESS;\r
869}\r
870\r
a1e7cd0b 871EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
fc8be1ad 872 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
a1e7cd0b
JY
873 &gEdkiiVTdInfoPpiGuid,\r
874 VTdInfoNotify\r
fc8be1ad
JY
875};\r
876\r
3f5ed3fa
JY
877/**\r
878 Initializes the Intel VTd PMR PEIM.\r
879\r
880 @param FileHandle Handle of the file being invoked.\r
881 @param PeiServices Describes the list of possible PEI Services.\r
882\r
883 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
884 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
885\r
886**/\r
887EFI_STATUS\r
888EFIAPI\r
889IntelVTdPmrInitialize (\r
890 IN EFI_PEI_FILE_HANDLE FileHandle,\r
891 IN CONST EFI_PEI_SERVICES **PeiServices\r
892 )\r
893{\r
894 EFI_STATUS Status;\r
fc8be1ad 895 EFI_BOOT_MODE BootMode;\r
a1e7cd0b
JY
896 DMA_BUFFER_INFO *DmaBufferInfo;\r
897\r
898 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
3f5ed3fa
JY
899\r
900 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
901 return EFI_UNSUPPORTED;\r
902 }\r
903\r
a1e7cd0b
JY
904 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
905 ASSERT(DmaBufferInfo != NULL);\r
906 if (DmaBufferInfo == NULL) {\r
907 return EFI_OUT_OF_RESOURCES;\r
8e9da4ba 908 }\r
a1e7cd0b 909 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
8e9da4ba 910\r
a1e7cd0b 911 PeiServicesGetBootMode (&BootMode);\r
8e9da4ba 912\r
fc8be1ad 913 if (BootMode == BOOT_ON_S3_RESUME) {\r
a1e7cd0b 914 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
fc8be1ad 915 } else {\r
a1e7cd0b 916 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
3f5ed3fa
JY
917 }\r
918\r
a1e7cd0b
JY
919 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
920 ASSERT_EFI_ERROR (Status);\r
3f5ed3fa 921\r
fc8be1ad 922 //\r
a1e7cd0b 923 // Register EndOfPei Notify for S3\r
fc8be1ad
JY
924 //\r
925 if (BootMode == BOOT_ON_S3_RESUME) {\r
926 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
927 ASSERT_EFI_ERROR (Status);\r
928 }\r
929\r
a1e7cd0b 930 return EFI_SUCCESS;\r
3f5ed3fa
JY
931}\r
932\r