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