]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
CommitLineData
3f5ed3fa
JY
1/** @file\r
2\r
e8097a74 3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
3f5ed3fa 4\r
8f7a05e1 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
3f5ed3fa
JY
6\r
7**/\r
8\r
9#include <Uefi.h>\r
10#include <PiPei.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/MemoryAllocationLib.h>\r
14#include <Library/IoLib.h>\r
15#include <Library/DebugLib.h>\r
16#include <Library/PeiServicesLib.h>\r
17#include <Library/HobLib.h>\r
18#include <IndustryStandard/Vtd.h>\r
19#include <Ppi/IoMmu.h>\r
4084ccfa 20#include <Ppi/VtdInfo.h>\r
a1e7cd0b 21#include <Ppi/MemoryDiscovered.h>\r
fc8be1ad 22#include <Ppi/EndOfPeiPhase.h>\r
3f5ed3fa
JY
23\r
24#include "IntelVTdPmrPei.h"\r
25\r
a1e7cd0b
JY
26EFI_GUID mVTdInfoGuid = {\r
27 0x222f5e30, 0x5cd, 0x49c6, { 0x8a, 0xc, 0x36, 0xd6, 0x58, 0x41, 0xe0, 0x82 }\r
28};\r
29\r
30EFI_GUID mDmaBufferInfoGuid = {\r
31 0x7b624ec7, 0xfb67, 0x4f9c, { 0xb6, 0xb0, 0x4d, 0xfa, 0x9c, 0x88, 0x20, 0x39 }\r
32};\r
33\r
34typedef struct {\r
35 UINTN DmaBufferBase;\r
36 UINTN DmaBufferSize;\r
37 UINTN DmaBufferCurrentTop;\r
38 UINTN DmaBufferCurrentBottom;\r
39} DMA_BUFFER_INFO;\r
3f5ed3fa
JY
40\r
41#define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')\r
42typedef struct {\r
43 UINT32 Signature;\r
44 EDKII_IOMMU_OPERATION Operation;\r
45 UINTN NumberOfBytes;\r
46 EFI_PHYSICAL_ADDRESS HostAddress;\r
47 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
48} MAP_INFO;\r
49\r
50/**\r
51\r
52 PEI Memory Layout:\r
53\r
b2725f57 54 +------------------+ <=============== PHMR.Limit (+ alignment) (1 << (HostAddressWidth + 1))\r
8e9da4ba
JY
55 | Mem Resource |\r
56 | |\r
57\r
3f5ed3fa
JY
58 +------------------+ <------- EfiMemoryTop\r
59 | PEI allocated |\r
8e9da4ba 60 =========== +==================+ <=============== PHMR.Base\r
3f5ed3fa
JY
61 ^ | Commom Buf |\r
62 | | -------------- |\r
63 DMA Buffer | * DMA FREE * |\r
64 | | -------------- |\r
65 V | Read/Write Buf |\r
e8097a74 66 =========== +==================+ <=============== PLMR.Limit (+ alignment)\r
3f5ed3fa
JY
67 | PEI allocated |\r
68 | -------------- | <------- EfiFreeMemoryTop\r
69 | * PEI FREE * |\r
70 | -------------- | <------- EfiFreeMemoryBottom\r
71 | hob |\r
72 | -------------- |\r
73 | Stack |\r
74 +------------------+ <------- EfiMemoryBottom / Stack Bottom\r
75\r
76 +------------------+\r
77 | Mem Alloc Hob |\r
78 +------------------+\r
79\r
8e9da4ba
JY
80 | |\r
81 | Mem Resource |\r
82 +------------------+ <=============== PLMR.Base (0)\r
3f5ed3fa
JY
83**/\r
84\r
3f5ed3fa
JY
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
940dbd07
SZ
106 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
107 not available to be allocated yet.\r
3f5ed3fa
JY
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
940dbd07
SZ
118 VOID *Hob;\r
119 DMA_BUFFER_INFO *DmaBufferInfo;\r
120\r
121 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
122 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
123\r
124 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
125 return EFI_NOT_AVAILABLE_YET;\r
126 }\r
127\r
3f5ed3fa
JY
128 return EFI_SUCCESS;\r
129}\r
130\r
131/**\r
132 Provides the controller-specific addresses required to access system memory from a\r
133 DMA bus master.\r
134\r
135 @param This The PPI instance pointer.\r
136 @param Operation Indicates if the bus master is going to read or write to system memory.\r
137 @param HostAddress The system memory address to map to the PCI controller.\r
138 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes\r
139 that were mapped.\r
140 @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
141 access the hosts HostAddress.\r
142 @param Mapping A resulting value to pass to Unmap().\r
143\r
144 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
145 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.\r
146 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
147 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
148 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
940dbd07
SZ
149 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
150 not available to be allocated yet.\r
3f5ed3fa
JY
151\r
152**/\r
153EFI_STATUS\r
154EFIAPI\r
155PeiIoMmuMap (\r
156 IN EDKII_IOMMU_PPI *This,\r
157 IN EDKII_IOMMU_OPERATION Operation,\r
158 IN VOID *HostAddress,\r
159 IN OUT UINTN *NumberOfBytes,\r
160 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
161 OUT VOID **Mapping\r
162 )\r
163{\r
a1e7cd0b
JY
164 MAP_INFO *MapInfo;\r
165 UINTN Length;\r
166 VOID *Hob;\r
167 DMA_BUFFER_INFO *DmaBufferInfo;\r
168\r
169 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
170 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa 171\r
940dbd07
SZ
172 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuMap - HostAddress - 0x%x, NumberOfBytes - %x\n", HostAddress, *NumberOfBytes));\r
173 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
174 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
175\r
176 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
177 return EFI_NOT_AVAILABLE_YET;\r
178 }\r
179\r
3f5ed3fa
JY
180 if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
181 Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
182 *DeviceAddress = (UINTN)HostAddress;\r
abe63fa7 183 *Mapping = NULL;\r
3f5ed3fa
JY
184 return EFI_SUCCESS;\r
185 }\r
186\r
3f5ed3fa 187 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b 188 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
189 DEBUG ((DEBUG_ERROR, "PeiIoMmuMap - OUT_OF_RESOURCE\n"));\r
190 ASSERT (FALSE);\r
191 return EFI_OUT_OF_RESOURCES;\r
192 }\r
193\r
a1e7cd0b
JY
194 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
195 DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
3f5ed3fa
JY
196\r
197 MapInfo = (VOID *)(UINTN)(*DeviceAddress + *NumberOfBytes);\r
198 MapInfo->Signature = MAP_INFO_SIGNATURE;\r
199 MapInfo->Operation = Operation;\r
200 MapInfo->NumberOfBytes = *NumberOfBytes;\r
201 MapInfo->HostAddress = (UINTN)HostAddress;\r
202 MapInfo->DeviceAddress = *DeviceAddress;\r
203 *Mapping = MapInfo;\r
204 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, Mapping - %x\n", Operation, (UINTN)*DeviceAddress, MapInfo));\r
205\r
206 //\r
207 // If this is a read operation from the Bus Master's point of view,\r
208 // then copy the contents of the real buffer into the mapped buffer\r
209 // so the Bus Master can read the contents of the real buffer.\r
210 //\r
211 if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
212 Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
213 CopyMem (\r
214 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
215 (VOID *) (UINTN) MapInfo->HostAddress,\r
216 MapInfo->NumberOfBytes\r
217 );\r
218 }\r
219\r
220 return EFI_SUCCESS;\r
221}\r
222\r
223/**\r
224 Completes the Map() operation and releases any corresponding resources.\r
225\r
226 @param This The PPI instance pointer.\r
227 @param Mapping The mapping value returned from Map().\r
228\r
229 @retval EFI_SUCCESS The range was unmapped.\r
230 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().\r
231 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
940dbd07
SZ
232 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
233 not available to be allocated yet.\r
234\r
3f5ed3fa
JY
235**/\r
236EFI_STATUS\r
237EFIAPI\r
238PeiIoMmuUnmap (\r
239 IN EDKII_IOMMU_PPI *This,\r
240 IN VOID *Mapping\r
241 )\r
242{\r
a1e7cd0b
JY
243 MAP_INFO *MapInfo;\r
244 UINTN Length;\r
245 VOID *Hob;\r
246 DMA_BUFFER_INFO *DmaBufferInfo;\r
247\r
248 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
249 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa 250\r
3f5ed3fa 251 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuUnmap - Mapping - %x\n", Mapping));\r
a1e7cd0b
JY
252 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
253 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 254\r
940dbd07
SZ
255 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
256 return EFI_NOT_AVAILABLE_YET;\r
257 }\r
258\r
259 if (Mapping == NULL) {\r
abe63fa7 260 return EFI_SUCCESS;\r
940dbd07
SZ
261 }\r
262\r
3f5ed3fa
JY
263 MapInfo = Mapping;\r
264 ASSERT (MapInfo->Signature == MAP_INFO_SIGNATURE);\r
265 DEBUG ((DEBUG_VERBOSE, " Op(%x):DeviceAddress - %x, NumberOfBytes - %x\n", MapInfo->Operation, (UINTN)MapInfo->DeviceAddress, MapInfo->NumberOfBytes));\r
266\r
267 //\r
268 // If this is a write operation from the Bus Master's point of view,\r
269 // then copy the contents of the mapped buffer into the real buffer\r
270 // so the processor can read the contents of the real buffer.\r
271 //\r
272 if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
273 MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
274 CopyMem (\r
275 (VOID *) (UINTN) MapInfo->HostAddress,\r
276 (VOID *) (UINTN) MapInfo->DeviceAddress,\r
277 MapInfo->NumberOfBytes\r
278 );\r
279 }\r
280\r
281 Length = MapInfo->NumberOfBytes + sizeof(MAP_INFO);\r
a1e7cd0b
JY
282 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
283 DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
3f5ed3fa
JY
284 }\r
285\r
286 return EFI_SUCCESS;\r
287}\r
288\r
289/**\r
290 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or\r
291 OperationBusMasterCommonBuffer64 mapping.\r
292\r
293 @param This The PPI instance pointer.\r
294 @param MemoryType The type of memory to allocate, EfiBootServicesData or\r
295 EfiRuntimeServicesData.\r
296 @param Pages The number of pages to allocate.\r
297 @param HostAddress A pointer to store the base system memory address of the\r
298 allocated range.\r
299 @param Attributes The requested bit mask of attributes for the allocated range.\r
300\r
301 @retval EFI_SUCCESS The requested memory pages were allocated.\r
302 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
34e18d17 303 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\r
3f5ed3fa
JY
304 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
305 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
940dbd07
SZ
306 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
307 not available to be allocated yet.\r
3f5ed3fa
JY
308\r
309**/\r
310EFI_STATUS\r
311EFIAPI\r
312PeiIoMmuAllocateBuffer (\r
313 IN EDKII_IOMMU_PPI *This,\r
314 IN EFI_MEMORY_TYPE MemoryType,\r
315 IN UINTN Pages,\r
316 IN OUT VOID **HostAddress,\r
317 IN UINT64 Attributes\r
318 )\r
319{\r
a1e7cd0b
JY
320 UINTN Length;\r
321 VOID *Hob;\r
322 DMA_BUFFER_INFO *DmaBufferInfo;\r
323\r
324 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
325 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
326\r
327 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
a1e7cd0b
JY
328 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
329 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 330\r
940dbd07
SZ
331 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
332 return EFI_NOT_AVAILABLE_YET;\r
333 }\r
334\r
3f5ed3fa 335 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b 336 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
3f5ed3fa
JY
337 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
338 ASSERT (FALSE);\r
339 return EFI_OUT_OF_RESOURCES;\r
340 }\r
a1e7cd0b
JY
341 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
342 DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
3f5ed3fa
JY
343\r
344 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - allocate - %x\n", *HostAddress));\r
345 return EFI_SUCCESS;\r
346}\r
347\r
348/**\r
349 Frees memory that was allocated with AllocateBuffer().\r
350\r
351 @param This The PPI instance pointer.\r
352 @param Pages The number of pages to free.\r
353 @param HostAddress The base system memory address of the allocated range.\r
354\r
355 @retval EFI_SUCCESS The requested memory pages were freed.\r
356 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages\r
357 was not allocated with AllocateBuffer().\r
940dbd07
SZ
358 @retval EFI_NOT_AVAILABLE_YET DMA protection has been enabled, but DMA buffer are\r
359 not available to be allocated yet.\r
3f5ed3fa
JY
360\r
361**/\r
362EFI_STATUS\r
363EFIAPI\r
364PeiIoMmuFreeBuffer (\r
365 IN EDKII_IOMMU_PPI *This,\r
366 IN UINTN Pages,\r
367 IN VOID *HostAddress\r
368 )\r
369{\r
a1e7cd0b
JY
370 UINTN Length;\r
371 VOID *Hob;\r
372 DMA_BUFFER_INFO *DmaBufferInfo;\r
373\r
374 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
375 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
3f5ed3fa
JY
376\r
377 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
a1e7cd0b
JY
378 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
379 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
3f5ed3fa 380\r
940dbd07
SZ
381 if (DmaBufferInfo->DmaBufferCurrentTop == 0) {\r
382 return EFI_NOT_AVAILABLE_YET;\r
383 }\r
384\r
3f5ed3fa 385 Length = EFI_PAGES_TO_SIZE(Pages);\r
a1e7cd0b
JY
386 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
387 DmaBufferInfo->DmaBufferCurrentTop += Length;\r
3f5ed3fa
JY
388 }\r
389\r
390 return EFI_SUCCESS;\r
391}\r
392\r
393EDKII_IOMMU_PPI mIoMmuPpi = {\r
394 EDKII_IOMMU_PPI_REVISION,\r
395 PeiIoMmuSetAttribute,\r
396 PeiIoMmuMap,\r
397 PeiIoMmuUnmap,\r
398 PeiIoMmuAllocateBuffer,\r
399 PeiIoMmuFreeBuffer,\r
400};\r
401\r
402CONST EFI_PEI_PPI_DESCRIPTOR mIoMmuPpiList = {\r
403 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
404 &gEdkiiIoMmuPpiGuid,\r
405 (VOID *) &mIoMmuPpi\r
406};\r
407\r
3f5ed3fa
JY
408/**\r
409 Initialize DMA protection.\r
410\r
a1e7cd0b 411 @param VTdInfo The VTd engine context information.\r
3f5ed3fa
JY
412\r
413 @retval EFI_SUCCESS the DMA protection is initialized.\r
414 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
415**/\r
416EFI_STATUS\r
417InitDmaProtection (\r
ed0e52fc 418 IN VTD_INFO *VTdInfo\r
3f5ed3fa
JY
419 )\r
420{\r
421 EFI_STATUS Status;\r
3f5ed3fa
JY
422 UINT32 LowMemoryAlignment;\r
423 UINT64 HighMemoryAlignment;\r
424 UINTN MemoryAlignment;\r
425 UINTN LowBottom;\r
426 UINTN LowTop;\r
427 UINTN HighBottom;\r
428 UINT64 HighTop;\r
ed0e52fc
SZ
429 DMA_BUFFER_INFO *DmaBufferInfo;\r
430 VOID *Hob;\r
940dbd07
SZ
431 EFI_PEI_PPI_DESCRIPTOR *OldDescriptor;\r
432 EDKII_IOMMU_PPI *OldIoMmuPpi;\r
ed0e52fc
SZ
433\r
434 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
435 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
436\r
437 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa 438\r
a1e7cd0b
JY
439 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
440 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
3f5ed3fa
JY
441 if (LowMemoryAlignment < HighMemoryAlignment) {\r
442 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
443 } else {\r
444 MemoryAlignment = LowMemoryAlignment;\r
445 }\r
ed0e52fc
SZ
446 ASSERT (DmaBufferInfo->DmaBufferSize == ALIGN_VALUE(DmaBufferInfo->DmaBufferSize, MemoryAlignment));\r
447 DmaBufferInfo->DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize), MemoryAlignment);\r
448 ASSERT (DmaBufferInfo->DmaBufferBase != 0);\r
449 if (DmaBufferInfo->DmaBufferBase == 0) {\r
3f5ed3fa
JY
450 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
451 return EFI_OUT_OF_RESOURCES;\r
452 }\r
453\r
ed0e52fc
SZ
454 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\r
455\r
456 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
457 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
458\r
459 //\r
940dbd07 460 // (Re)Install PPI.\r
ed0e52fc 461 //\r
940dbd07
SZ
462 Status = PeiServicesLocatePpi (\r
463 &gEdkiiIoMmuPpiGuid,\r
464 0,\r
465 &OldDescriptor,\r
466 (VOID **) &OldIoMmuPpi\r
467 );\r
468 if (!EFI_ERROR (Status)) {\r
469 Status = PeiServicesReInstallPpi (OldDescriptor, &mIoMmuPpiList);\r
470 } else {\r
471 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
472 }\r
473 ASSERT_EFI_ERROR (Status);\r
ed0e52fc 474\r
3f5ed3fa 475 LowBottom = 0;\r
ed0e52fc
SZ
476 LowTop = DmaBufferInfo->DmaBufferBase;\r
477 HighBottom = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
b2725f57 478 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
3f5ed3fa
JY
479\r
480 Status = SetDmaProtectedRange (\r
a1e7cd0b
JY
481 VTdInfo,\r
482 VTdInfo->EngineMask,\r
483 (UINT32)LowBottom,\r
484 (UINT32)(LowTop - LowBottom),\r
485 HighBottom,\r
486 HighTop - HighBottom\r
487 );\r
3f5ed3fa
JY
488\r
489 if (EFI_ERROR(Status)) {\r
ed0e52fc 490 FreePages ((VOID *)DmaBufferInfo->DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferInfo->DmaBufferSize));\r
3f5ed3fa
JY
491 }\r
492\r
493 return Status;\r
494}\r
495\r
8e9da4ba 496/**\r
a1e7cd0b
JY
497 Initializes the Intel VTd Info.\r
498\r
499 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
500 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 501\r
8e9da4ba 502**/\r
a1e7cd0b
JY
503EFI_STATUS\r
504InitVTdInfo (\r
505 VOID\r
8e9da4ba
JY
506 )\r
507{\r
a1e7cd0b
JY
508 EFI_STATUS Status;\r
509 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
510 VOID *Hob;\r
8e9da4ba 511\r
a1e7cd0b
JY
512 Status = PeiServicesLocatePpi (\r
513 &gEdkiiVTdInfoPpiGuid,\r
514 0,\r
515 NULL,\r
516 (VOID **)&AcpiDmarTable\r
517 );\r
518 ASSERT_EFI_ERROR(Status);\r
8e9da4ba 519\r
a1e7cd0b 520 DumpAcpiDMAR (AcpiDmarTable);\r
8e9da4ba 521\r
a1e7cd0b
JY
522 //\r
523 // Clear old VTdInfo Hob.\r
524 //\r
525 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
526 if (Hob != NULL) {\r
527 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\r
8e9da4ba
JY
528 }\r
529\r
a1e7cd0b
JY
530 //\r
531 // Get DMAR information to local VTdInfo\r
532 //\r
533 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
534 if (EFI_ERROR(Status)) {\r
535 return Status;\r
8e9da4ba
JY
536 }\r
537\r
a1e7cd0b
JY
538 //\r
539 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
540 //\r
8e9da4ba 541\r
a1e7cd0b 542 return EFI_SUCCESS;\r
8e9da4ba
JY
543}\r
544\r
545/**\r
a1e7cd0b
JY
546 Initializes the Intel VTd PMR for all memory.\r
547\r
548 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
549 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 550\r
8e9da4ba 551**/\r
a1e7cd0b
JY
552EFI_STATUS\r
553InitVTdPmrForAll (\r
554 VOID\r
8e9da4ba
JY
555 )\r
556{\r
a1e7cd0b
JY
557 EFI_STATUS Status;\r
558 VOID *Hob;\r
559 VTD_INFO *VTdInfo;\r
560 UINTN LowBottom;\r
561 UINTN LowTop;\r
562 UINTN HighBottom;\r
563 UINT64 HighTop;\r
8e9da4ba 564\r
a1e7cd0b
JY
565 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
566 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 567\r
a1e7cd0b
JY
568 LowBottom = 0;\r
569 LowTop = 0;\r
570 HighBottom = 0;\r
9dd8b190 571 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
8e9da4ba 572\r
a1e7cd0b
JY
573 Status = SetDmaProtectedRange (\r
574 VTdInfo,\r
575 VTdInfo->EngineMask,\r
576 (UINT32)LowBottom,\r
577 (UINT32)(LowTop - LowBottom),\r
578 HighBottom,\r
579 HighTop - HighBottom\r
580 );\r
8e9da4ba 581\r
a1e7cd0b 582 return Status;\r
8e9da4ba
JY
583}\r
584\r
585/**\r
a1e7cd0b
JY
586 Initializes the Intel VTd PMR for DMA buffer.\r
587\r
588 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
589 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
8e9da4ba 590\r
8e9da4ba 591**/\r
a1e7cd0b
JY
592EFI_STATUS\r
593InitVTdPmrForDma (\r
594 VOID\r
8e9da4ba
JY
595 )\r
596{\r
a1e7cd0b
JY
597 EFI_STATUS Status;\r
598 VOID *Hob;\r
599 VTD_INFO *VTdInfo;\r
8e9da4ba 600\r
a1e7cd0b
JY
601 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
602 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba
JY
603\r
604 //\r
a1e7cd0b 605 // If there is RMRR memory, parse it here.\r
8e9da4ba 606 //\r
a1e7cd0b 607 ParseDmarAcpiTableRmrr (VTdInfo);\r
8e9da4ba 608\r
8e9da4ba 609 //\r
ed0e52fc
SZ
610 // Allocate a range in PEI memory as DMA buffer\r
611 // Mark others to be DMA protected.\r
8e9da4ba 612 //\r
ed0e52fc 613 Status = InitDmaProtection (VTdInfo);\r
8e9da4ba 614\r
a1e7cd0b 615 return Status;\r
8e9da4ba
JY
616}\r
617\r
618/**\r
a1e7cd0b 619 This function handles S3 resume task at the end of PEI\r
8e9da4ba 620\r
a1e7cd0b
JY
621 @param[in] PeiServices Pointer to PEI Services Table.\r
622 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
623 caused this function to execute.\r
624 @param[in] Ppi Pointer to the PPI data associated with this function.\r
8e9da4ba 625\r
a1e7cd0b 626 @retval EFI_STATUS Always return EFI_SUCCESS\r
8e9da4ba 627**/\r
a1e7cd0b
JY
628EFI_STATUS\r
629EFIAPI\r
630S3EndOfPeiNotify(\r
631 IN EFI_PEI_SERVICES **PeiServices,\r
632 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
633 IN VOID *Ppi\r
8e9da4ba
JY
634 )\r
635{\r
a1e7cd0b
JY
636 VOID *Hob;\r
637 VTD_INFO *VTdInfo;\r
638 UINT64 EngineMask;\r
8e9da4ba 639\r
a1e7cd0b 640 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
8e9da4ba 641\r
a1e7cd0b
JY
642 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
643 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
644 if (Hob == NULL) {\r
645 return EFI_SUCCESS;\r
8e9da4ba 646 }\r
a1e7cd0b 647 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
8e9da4ba 648\r
a1e7cd0b
JY
649 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
650 DisableDmaProtection (VTdInfo, EngineMask);\r
8e9da4ba 651 }\r
a1e7cd0b 652 return EFI_SUCCESS;\r
8e9da4ba
JY
653}\r
654\r
a1e7cd0b
JY
655EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
656 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
657 &gEfiEndOfPeiSignalPpiGuid,\r
658 S3EndOfPeiNotify\r
659};\r
8e9da4ba 660\r
fc8be1ad 661/**\r
a1e7cd0b 662 This function handles VTd engine setup\r
fc8be1ad
JY
663\r
664 @param[in] PeiServices Pointer to PEI Services Table.\r
665 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
666 caused this function to execute.\r
667 @param[in] Ppi Pointer to the PPI data associated with this function.\r
668\r
669 @retval EFI_STATUS Always return EFI_SUCCESS\r
670**/\r
671EFI_STATUS\r
672EFIAPI\r
a1e7cd0b 673VTdInfoNotify (\r
fc8be1ad
JY
674 IN EFI_PEI_SERVICES **PeiServices,\r
675 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
676 IN VOID *Ppi\r
677 )\r
678{\r
a1e7cd0b
JY
679 EFI_STATUS Status;\r
680 VOID *MemoryDiscovered;\r
681 UINT64 EnabledEngineMask;\r
682 VOID *Hob;\r
683 VTD_INFO *VTdInfo;\r
684 BOOLEAN MemoryInitialized;\r
fc8be1ad 685\r
a1e7cd0b
JY
686 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
687\r
688 //\r
689 // Check if memory is initialized.\r
690 //\r
691 MemoryInitialized = FALSE;\r
692 Status = PeiServicesLocatePpi (\r
693 &gEfiPeiMemoryDiscoveredPpiGuid,\r
694 0,\r
695 NULL,\r
696 &MemoryDiscovered\r
697 );\r
698 if (!EFI_ERROR(Status)) {\r
699 MemoryInitialized = TRUE;\r
700 }\r
701\r
702 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
703\r
704 if (!MemoryInitialized) {\r
705 //\r
706 // If the memory is not initialized,\r
707 // Protect all system memory\r
708 //\r
709 InitVTdInfo ();\r
710 InitVTdPmrForAll ();\r
940dbd07
SZ
711\r
712 //\r
713 // Install PPI.\r
714 //\r
715 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
716 ASSERT_EFI_ERROR(Status);\r
a1e7cd0b
JY
717 } else {\r
718 //\r
719 // If the memory is initialized,\r
720 // Allocate DMA buffer and protect rest system memory\r
721 //\r
722\r
723 //\r
724 // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
725 //\r
726 InitVTdInfo ();\r
727\r
728 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
729 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
730\r
731 //\r
732 // NOTE: We need check if PMR is enabled or not.\r
733 //\r
734 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
735 if (EnabledEngineMask != 0) {\r
736 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
737 DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
738 }\r
739 InitVTdPmrForDma ();\r
740 if (EnabledEngineMask != 0) {\r
741 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
742 }\r
fc8be1ad 743\r
fc8be1ad 744 }\r
a1e7cd0b 745\r
fc8be1ad
JY
746 return EFI_SUCCESS;\r
747}\r
748\r
a1e7cd0b 749EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
fc8be1ad 750 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
a1e7cd0b
JY
751 &gEdkiiVTdInfoPpiGuid,\r
752 VTdInfoNotify\r
fc8be1ad
JY
753};\r
754\r
3f5ed3fa
JY
755/**\r
756 Initializes the Intel VTd PMR PEIM.\r
757\r
758 @param FileHandle Handle of the file being invoked.\r
759 @param PeiServices Describes the list of possible PEI Services.\r
760\r
761 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
762 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
763\r
764**/\r
765EFI_STATUS\r
766EFIAPI\r
767IntelVTdPmrInitialize (\r
768 IN EFI_PEI_FILE_HANDLE FileHandle,\r
769 IN CONST EFI_PEI_SERVICES **PeiServices\r
770 )\r
771{\r
772 EFI_STATUS Status;\r
fc8be1ad 773 EFI_BOOT_MODE BootMode;\r
a1e7cd0b
JY
774 DMA_BUFFER_INFO *DmaBufferInfo;\r
775\r
776 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
3f5ed3fa
JY
777\r
778 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
779 return EFI_UNSUPPORTED;\r
780 }\r
781\r
a1e7cd0b
JY
782 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
783 ASSERT(DmaBufferInfo != NULL);\r
784 if (DmaBufferInfo == NULL) {\r
785 return EFI_OUT_OF_RESOURCES;\r
8e9da4ba 786 }\r
a1e7cd0b 787 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
8e9da4ba 788\r
a1e7cd0b 789 PeiServicesGetBootMode (&BootMode);\r
8e9da4ba 790\r
fc8be1ad 791 if (BootMode == BOOT_ON_S3_RESUME) {\r
339cb0af 792 DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSizeS3);\r
fc8be1ad 793 } else {\r
339cb0af 794 DmaBufferInfo->DmaBufferSize = PcdGet32 (PcdVTdPeiDmaBufferSize);\r
3f5ed3fa
JY
795 }\r
796\r
a1e7cd0b
JY
797 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
798 ASSERT_EFI_ERROR (Status);\r
3f5ed3fa 799\r
fc8be1ad 800 //\r
a1e7cd0b 801 // Register EndOfPei Notify for S3\r
fc8be1ad
JY
802 //\r
803 if (BootMode == BOOT_ON_S3_RESUME) {\r
804 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
805 ASSERT_EFI_ERROR (Status);\r
806 }\r
807\r
a1e7cd0b 808 return EFI_SUCCESS;\r
3f5ed3fa
JY
809}\r
810\r