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