]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelSiliconPkg/Feature/VTd/IntelVTdPmrPei/IntelVTdPmrPei.c
IntelSiliconPkg IntelVTdPmrPei: Get high top by host address width
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdPmrPei / IntelVTdPmrPei.c
... / ...
CommitLineData
1/** @file\r
2\r
3 Copyright (c) 2017 - 2018, 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
26#include <Ppi/VtdInfo.h>\r
27#include <Ppi/MemoryDiscovered.h>\r
28#include <Ppi/EndOfPeiPhase.h>\r
29\r
30#include "IntelVTdPmrPei.h"\r
31\r
32#define TOTAL_DMA_BUFFER_SIZE SIZE_4MB\r
33#define TOTAL_DMA_BUFFER_SIZE_S3 SIZE_1MB\r
34\r
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
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
63 +------------------+ <=============== PHMR.Limit (+ alignment) (1 << (HostAddressWidth + 1))\r
64 | Mem Resource |\r
65 | |\r
66\r
67 +------------------+ <------- EfiMemoryTop\r
68 | PEI allocated |\r
69 =========== +==================+ <=============== PHMR.Base\r
70 ^ | Commom Buf |\r
71 | | -------------- |\r
72 DMA Buffer | * DMA FREE * |\r
73 | | -------------- |\r
74 V | Read/Write Buf |\r
75 =========== +==================+ <=============== PLMR.Limit (+ alignment)\r
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
89 | |\r
90 | Mem Resource |\r
91 +------------------+ <=============== PLMR.Base (0)\r
92**/\r
93\r
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
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
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
175 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
176 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
177\r
178 Length = *NumberOfBytes + sizeof(MAP_INFO);\r
179 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
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
185 *DeviceAddress = DmaBufferInfo->DmaBufferCurrentBottom;\r
186 DmaBufferInfo->DmaBufferCurrentBottom += Length;\r
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
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
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
244 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
245 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
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
266 if (DmaBufferInfo->DmaBufferCurrentBottom == MapInfo->DeviceAddress + Length) {\r
267 DmaBufferInfo->DmaBufferCurrentBottom -= Length;\r
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, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.\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
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
308\r
309 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuAllocateBuffer - page - %x\n", Pages));\r
310 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
311 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
312\r
313 Length = EFI_PAGES_TO_SIZE(Pages);\r
314 if (Length > DmaBufferInfo->DmaBufferCurrentTop - DmaBufferInfo->DmaBufferCurrentBottom) {\r
315 DEBUG ((DEBUG_ERROR, "PeiIoMmuAllocateBuffer - OUT_OF_RESOURCE\n"));\r
316 ASSERT (FALSE);\r
317 return EFI_OUT_OF_RESOURCES;\r
318 }\r
319 *HostAddress = (VOID *)(UINTN)(DmaBufferInfo->DmaBufferCurrentTop - Length);\r
320 DmaBufferInfo->DmaBufferCurrentTop -= Length;\r
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
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
352\r
353 DEBUG ((DEBUG_VERBOSE, "PeiIoMmuFreeBuffer - page - %x, HostAddr - %x\n", Pages, HostAddress));\r
354 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentTop - %x\n", DmaBufferInfo->DmaBufferCurrentTop));\r
355 DEBUG ((DEBUG_VERBOSE, " DmaBufferCurrentBottom - %x\n", DmaBufferInfo->DmaBufferCurrentBottom));\r
356\r
357 Length = EFI_PAGES_TO_SIZE(Pages);\r
358 if ((UINTN)HostAddress == DmaBufferInfo->DmaBufferCurrentTop) {\r
359 DmaBufferInfo->DmaBufferCurrentTop += Length;\r
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/**\r
381 Initialize DMA protection.\r
382\r
383 @param VTdInfo The VTd engine context information.\r
384 @param DmaBufferSize the DMA buffer size\r
385 @param DmaBufferBase the DMA buffer base\r
386\r
387 @retval EFI_SUCCESS the DMA protection is initialized.\r
388 @retval EFI_OUT_OF_RESOURCES no enough resource to initialize DMA protection.\r
389**/\r
390EFI_STATUS\r
391InitDmaProtection (\r
392 IN VTD_INFO *VTdInfo,\r
393 IN UINTN DmaBufferSize,\r
394 OUT UINTN *DmaBufferBase\r
395 )\r
396{\r
397 EFI_STATUS Status;\r
398 UINT32 LowMemoryAlignment;\r
399 UINT64 HighMemoryAlignment;\r
400 UINTN MemoryAlignment;\r
401 UINTN LowBottom;\r
402 UINTN LowTop;\r
403 UINTN HighBottom;\r
404 UINT64 HighTop;\r
405\r
406 LowMemoryAlignment = GetLowMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
407 HighMemoryAlignment = GetHighMemoryAlignment (VTdInfo, VTdInfo->EngineMask);\r
408 if (LowMemoryAlignment < HighMemoryAlignment) {\r
409 MemoryAlignment = (UINTN)HighMemoryAlignment;\r
410 } else {\r
411 MemoryAlignment = LowMemoryAlignment;\r
412 }\r
413 ASSERT (DmaBufferSize == ALIGN_VALUE(DmaBufferSize, MemoryAlignment));\r
414 *DmaBufferBase = (UINTN)AllocateAlignedPages (EFI_SIZE_TO_PAGES(DmaBufferSize), MemoryAlignment);\r
415 ASSERT (*DmaBufferBase != 0);\r
416 if (*DmaBufferBase == 0) {\r
417 DEBUG ((DEBUG_INFO, " InitDmaProtection : OutOfResource\n"));\r
418 return EFI_OUT_OF_RESOURCES;\r
419 }\r
420\r
421 LowBottom = 0;\r
422 LowTop = *DmaBufferBase;\r
423 HighBottom = *DmaBufferBase + DmaBufferSize;\r
424 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
425\r
426 Status = SetDmaProtectedRange (\r
427 VTdInfo,\r
428 VTdInfo->EngineMask,\r
429 (UINT32)LowBottom,\r
430 (UINT32)(LowTop - LowBottom),\r
431 HighBottom,\r
432 HighTop - HighBottom\r
433 );\r
434\r
435 if (EFI_ERROR(Status)) {\r
436 FreePages ((VOID *)*DmaBufferBase, EFI_SIZE_TO_PAGES(DmaBufferSize));\r
437 }\r
438\r
439 return Status;\r
440}\r
441\r
442/**\r
443 Initializes the Intel VTd Info.\r
444\r
445 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
446 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
447\r
448**/\r
449EFI_STATUS\r
450InitVTdInfo (\r
451 VOID\r
452 )\r
453{\r
454 EFI_STATUS Status;\r
455 EFI_ACPI_DMAR_HEADER *AcpiDmarTable;\r
456 VOID *Hob;\r
457\r
458 Status = PeiServicesLocatePpi (\r
459 &gEdkiiVTdInfoPpiGuid,\r
460 0,\r
461 NULL,\r
462 (VOID **)&AcpiDmarTable\r
463 );\r
464 ASSERT_EFI_ERROR(Status);\r
465\r
466 DumpAcpiDMAR (AcpiDmarTable);\r
467\r
468 //\r
469 // Clear old VTdInfo Hob.\r
470 //\r
471 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
472 if (Hob != NULL) {\r
473 ZeroMem (&((EFI_HOB_GUID_TYPE *)Hob)->Name, sizeof(EFI_GUID));\r
474 }\r
475\r
476 //\r
477 // Get DMAR information to local VTdInfo\r
478 //\r
479 Status = ParseDmarAcpiTableDrhd (AcpiDmarTable);\r
480 if (EFI_ERROR(Status)) {\r
481 return Status;\r
482 }\r
483\r
484 //\r
485 // NOTE: Do not parse RMRR here, because RMRR may cause PMR programming.\r
486 //\r
487\r
488 return EFI_SUCCESS;\r
489}\r
490\r
491/**\r
492 Initializes the Intel VTd PMR for all memory.\r
493\r
494 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
495 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
496\r
497**/\r
498EFI_STATUS\r
499InitVTdPmrForAll (\r
500 VOID\r
501 )\r
502{\r
503 EFI_STATUS Status;\r
504 VOID *Hob;\r
505 VTD_INFO *VTdInfo;\r
506 UINTN LowBottom;\r
507 UINTN LowTop;\r
508 UINTN HighBottom;\r
509 UINT64 HighTop;\r
510\r
511 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
512 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
513\r
514 LowBottom = 0;\r
515 LowTop = 0;\r
516 HighBottom = 0;\r
517 HighTop = LShiftU64 (1, VTdInfo->HostAddressWidth + 1);\r
518\r
519 Status = SetDmaProtectedRange (\r
520 VTdInfo,\r
521 VTdInfo->EngineMask,\r
522 (UINT32)LowBottom,\r
523 (UINT32)(LowTop - LowBottom),\r
524 HighBottom,\r
525 HighTop - HighBottom\r
526 );\r
527\r
528 return Status;\r
529}\r
530\r
531/**\r
532 Initializes the Intel VTd PMR for DMA buffer.\r
533\r
534 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
535 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
536\r
537**/\r
538EFI_STATUS\r
539InitVTdPmrForDma (\r
540 VOID\r
541 )\r
542{\r
543 EFI_STATUS Status;\r
544 VOID *Hob;\r
545 VTD_INFO *VTdInfo;\r
546 DMA_BUFFER_INFO *DmaBufferInfo;\r
547\r
548 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
549 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
550\r
551 //\r
552 // If there is RMRR memory, parse it here.\r
553 //\r
554 ParseDmarAcpiTableRmrr (VTdInfo);\r
555\r
556 Hob = GetFirstGuidHob (&mDmaBufferInfoGuid);\r
557 DmaBufferInfo = GET_GUID_HOB_DATA(Hob);\r
558\r
559 DEBUG ((DEBUG_INFO, " DmaBufferSize : 0x%x\n", DmaBufferInfo->DmaBufferSize));\r
560 //\r
561 // Find a pre-memory in resource hob as DMA buffer\r
562 // Mark PEI memory to be DMA protected.\r
563 //\r
564 Status = InitDmaProtection (VTdInfo, DmaBufferInfo->DmaBufferSize, &DmaBufferInfo->DmaBufferBase);\r
565 if (EFI_ERROR(Status)) {\r
566 return Status;\r
567 }\r
568\r
569 DEBUG ((DEBUG_INFO, " DmaBufferBase : 0x%x\n", DmaBufferInfo->DmaBufferBase));\r
570\r
571 DmaBufferInfo->DmaBufferCurrentTop = DmaBufferInfo->DmaBufferBase + DmaBufferInfo->DmaBufferSize;\r
572 DmaBufferInfo->DmaBufferCurrentBottom = DmaBufferInfo->DmaBufferBase;\r
573\r
574 //\r
575 // Install PPI.\r
576 //\r
577 Status = PeiServicesInstallPpi (&mIoMmuPpiList);\r
578 ASSERT_EFI_ERROR(Status);\r
579\r
580 return Status;\r
581}\r
582\r
583/**\r
584 This function handles S3 resume task at the end of PEI\r
585\r
586 @param[in] PeiServices Pointer to PEI Services Table.\r
587 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
588 caused this function to execute.\r
589 @param[in] Ppi Pointer to the PPI data associated with this function.\r
590\r
591 @retval EFI_STATUS Always return EFI_SUCCESS\r
592**/\r
593EFI_STATUS\r
594EFIAPI\r
595S3EndOfPeiNotify(\r
596 IN EFI_PEI_SERVICES **PeiServices,\r
597 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
598 IN VOID *Ppi\r
599 )\r
600{\r
601 VOID *Hob;\r
602 VTD_INFO *VTdInfo;\r
603 UINT64 EngineMask;\r
604\r
605 DEBUG((DEBUG_INFO, "VTdPmr S3EndOfPeiNotify\n"));\r
606\r
607 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
608 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
609 if (Hob == NULL) {\r
610 return EFI_SUCCESS;\r
611 }\r
612 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
613\r
614 EngineMask = LShiftU64 (1, VTdInfo->VTdEngineCount) - 1;\r
615 DisableDmaProtection (VTdInfo, EngineMask);\r
616 }\r
617 return EFI_SUCCESS;\r
618}\r
619\r
620EFI_PEI_NOTIFY_DESCRIPTOR mS3EndOfPeiNotifyDesc = {\r
621 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
622 &gEfiEndOfPeiSignalPpiGuid,\r
623 S3EndOfPeiNotify\r
624};\r
625\r
626/**\r
627 This function handles VTd engine setup\r
628\r
629 @param[in] PeiServices Pointer to PEI Services Table.\r
630 @param[in] NotifyDesc Pointer to the descriptor for the Notification event that\r
631 caused this function to execute.\r
632 @param[in] Ppi Pointer to the PPI data associated with this function.\r
633\r
634 @retval EFI_STATUS Always return EFI_SUCCESS\r
635**/\r
636EFI_STATUS\r
637EFIAPI\r
638VTdInfoNotify (\r
639 IN EFI_PEI_SERVICES **PeiServices,\r
640 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,\r
641 IN VOID *Ppi\r
642 )\r
643{\r
644 EFI_STATUS Status;\r
645 VOID *MemoryDiscovered;\r
646 UINT64 EnabledEngineMask;\r
647 VOID *Hob;\r
648 VTD_INFO *VTdInfo;\r
649 BOOLEAN MemoryInitialized;\r
650\r
651 DEBUG ((DEBUG_INFO, "VTdInfoNotify\n"));\r
652\r
653 //\r
654 // Check if memory is initialized.\r
655 //\r
656 MemoryInitialized = FALSE;\r
657 Status = PeiServicesLocatePpi (\r
658 &gEfiPeiMemoryDiscoveredPpiGuid,\r
659 0,\r
660 NULL,\r
661 &MemoryDiscovered\r
662 );\r
663 if (!EFI_ERROR(Status)) {\r
664 MemoryInitialized = TRUE;\r
665 }\r
666\r
667 DEBUG ((DEBUG_INFO, "MemoryInitialized - %x\n", MemoryInitialized));\r
668\r
669 if (!MemoryInitialized) {\r
670 //\r
671 // If the memory is not initialized,\r
672 // Protect all system memory\r
673 //\r
674 InitVTdInfo ();\r
675 InitVTdPmrForAll ();\r
676 } else {\r
677 //\r
678 // If the memory is initialized,\r
679 // Allocate DMA buffer and protect rest system memory\r
680 //\r
681\r
682 //\r
683 // NOTE: We need reinit VTdInfo because previous information might be overriden.\r
684 //\r
685 InitVTdInfo ();\r
686\r
687 Hob = GetFirstGuidHob (&mVTdInfoGuid);\r
688 VTdInfo = GET_GUID_HOB_DATA(Hob);\r
689\r
690 //\r
691 // NOTE: We need check if PMR is enabled or not.\r
692 //\r
693 EnabledEngineMask = GetDmaProtectionEnabledEngineMask (VTdInfo, VTdInfo->EngineMask);\r
694 if (EnabledEngineMask != 0) {\r
695 EnableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
696 DisableDmaProtection (VTdInfo, EnabledEngineMask);\r
697 }\r
698 InitVTdPmrForDma ();\r
699 if (EnabledEngineMask != 0) {\r
700 DisableVTdTranslationProtection (VTdInfo, EnabledEngineMask);\r
701 }\r
702\r
703 }\r
704\r
705 return EFI_SUCCESS;\r
706}\r
707\r
708EFI_PEI_NOTIFY_DESCRIPTOR mVTdInfoNotifyDesc = {\r
709 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
710 &gEdkiiVTdInfoPpiGuid,\r
711 VTdInfoNotify\r
712};\r
713\r
714/**\r
715 Initializes the Intel VTd PMR PEIM.\r
716\r
717 @param FileHandle Handle of the file being invoked.\r
718 @param PeiServices Describes the list of possible PEI Services.\r
719\r
720 @retval EFI_SUCCESS Usb bot driver is successfully initialized.\r
721 @retval EFI_OUT_OF_RESOURCES Can't initialize the driver.\r
722\r
723**/\r
724EFI_STATUS\r
725EFIAPI\r
726IntelVTdPmrInitialize (\r
727 IN EFI_PEI_FILE_HANDLE FileHandle,\r
728 IN CONST EFI_PEI_SERVICES **PeiServices\r
729 )\r
730{\r
731 EFI_STATUS Status;\r
732 EFI_BOOT_MODE BootMode;\r
733 DMA_BUFFER_INFO *DmaBufferInfo;\r
734\r
735 DEBUG ((DEBUG_INFO, "IntelVTdPmrInitialize\n"));\r
736\r
737 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT0) == 0) {\r
738 return EFI_UNSUPPORTED;\r
739 }\r
740\r
741 DmaBufferInfo = BuildGuidHob (&mDmaBufferInfoGuid, sizeof(DMA_BUFFER_INFO));\r
742 ASSERT(DmaBufferInfo != NULL);\r
743 if (DmaBufferInfo == NULL) {\r
744 return EFI_OUT_OF_RESOURCES;\r
745 }\r
746 ZeroMem (DmaBufferInfo, sizeof(DMA_BUFFER_INFO));\r
747\r
748 PeiServicesGetBootMode (&BootMode);\r
749\r
750 if (BootMode == BOOT_ON_S3_RESUME) {\r
751 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE_S3;\r
752 } else {\r
753 DmaBufferInfo->DmaBufferSize = TOTAL_DMA_BUFFER_SIZE;\r
754 }\r
755\r
756 Status = PeiServicesNotifyPpi (&mVTdInfoNotifyDesc);\r
757 ASSERT_EFI_ERROR (Status);\r
758\r
759 //\r
760 // Register EndOfPei Notify for S3\r
761 //\r
762 if (BootMode == BOOT_ON_S3_RESUME) {\r
763 Status = PeiServicesNotifyPpi (&mS3EndOfPeiNotifyDesc);\r
764 ASSERT_EFI_ERROR (Status);\r
765 }\r
766\r
767 return EFI_SUCCESS;\r
768}\r
769\r