1 /** @file
2 
3   Copyright (c) 2019, Linaro, Ltd. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include <PiDxe.h>
9 #include <Library/BaseLib.h>
10 #include <Library/DebugLib.h>
11 #include <Library/DmaLib.h>
12 #include <Library/UefiBootServicesTableLib.h>
13 #include <Protocol/IoMmu.h>
14 
15 /**
16   Set IOMMU attribute for a system memory.
17 
18   If the IOMMU protocol exists, the system memory cannot be used
19   for DMA by default.
20 
21   When a device requests a DMA access for a system memory,
22   the device driver need use SetAttribute() to update the IOMMU
23   attribute to request DMA access (read and/or write).
24 
25   The DeviceHandle is used to identify which device submits the request.
26   The IOMMU implementation need translate the device path to an IOMMU device
27   ID, and set IOMMU hardware register accordingly.
28   1) DeviceHandle can be a standard PCI device.
29      The memory for BusMasterRead need set EDKII_IOMMU_ACCESS_READ.
30      The memory for BusMasterWrite need set EDKII_IOMMU_ACCESS_WRITE.
31      The memory for BusMasterCommonBuffer need set
32      EDKII_IOMMU_ACCESS_READ|EDKII_IOMMU_ACCESS_WRITE.
33      After the memory is used, the memory need set 0 to keep it being
34      protected.
35   2) DeviceHandle can be an ACPI device (ISA, I2C, SPI, etc).
36      The memory for DMA access need set EDKII_IOMMU_ACCESS_READ and/or
37      EDKII_IOMMU_ACCESS_WRITE.
38 
39   @param[in]  This              The protocol instance pointer.
40   @param[in]  DeviceHandle      The device who initiates the DMA access
41                                 request.
42   @param[in]  Mapping           The mapping value returned from Map().
43   @param[in]  IoMmuAccess       The IOMMU access.
44 
45   @retval EFI_SUCCESS            The IoMmuAccess is set for the memory range
46                                  specified by DeviceAddress and Length.
47   @retval EFI_INVALID_PARAMETER  DeviceHandle is an invalid handle.
48   @retval EFI_INVALID_PARAMETER  Mapping is not a value that was returned by
49                                  Map().
50   @retval EFI_INVALID_PARAMETER  IoMmuAccess specified an illegal combination
51                                  of access.
52   @retval EFI_UNSUPPORTED        DeviceHandle is unknown by the IOMMU.
53   @retval EFI_UNSUPPORTED        The bit mask of IoMmuAccess is not supported
54                                  by the IOMMU.
55   @retval EFI_UNSUPPORTED        The IOMMU does not support the memory range
56                                  specified by Mapping.
57   @retval EFI_OUT_OF_RESOURCES   There are not enough resources available to
58                                  modify the IOMMU access.
59   @retval EFI_DEVICE_ERROR       The IOMMU device reported an error while
60                                  attempting the operation.
61 
62 **/
63 STATIC
64 EFI_STATUS
65 EFIAPI
NonCoherentIoMmuSetAttribute(IN EDKII_IOMMU_PROTOCOL * This,IN EFI_HANDLE DeviceHandle,IN VOID * Mapping,IN UINT64 IoMmuAccess)66 NonCoherentIoMmuSetAttribute (
67   IN EDKII_IOMMU_PROTOCOL  *This,
68   IN EFI_HANDLE            DeviceHandle,
69   IN VOID                  *Mapping,
70   IN UINT64                IoMmuAccess
71   )
72 {
73   return EFI_UNSUPPORTED;
74 }
75 
76 /**
77   Provides the controller-specific addresses required to access system memory
78   from a DMA bus master. On SEV guest, the DMA operations must be performed on
79   shared buffer hence we allocate a bounce buffer to map the HostAddress to a
80   DeviceAddress. The Encryption attribute is removed from the DeviceAddress
81   buffer.
82 
83   @param  This                  The protocol instance pointer.
84   @param  Operation             Indicates if the bus master is going to read or
85                                 write to system memory.
86   @param  HostAddress           The system memory address to map to the PCI
87                                 controller.
88   @param  NumberOfBytes         On input the number of bytes to map. On output
89                                 the number of bytes that were mapped.
90   @param  DeviceAddress         The resulting map address for the bus master
91                                 PCI controller to use to access the hosts
92                                 HostAddress.
93   @param  Mapping               A resulting value to pass to Unmap().
94 
95   @retval EFI_SUCCESS           The range was mapped for the returned
96                                 NumberOfBytes.
97   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common
98                                 buffer.
99   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
100   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a
101                                 lack of resources.
102   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested
103                                 address.
104 
105 **/
106 STATIC
107 EFI_STATUS
108 EFIAPI
NonCoherentIoMmuMap(IN EDKII_IOMMU_PROTOCOL * This,IN EDKII_IOMMU_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)109 NonCoherentIoMmuMap (
110   IN     EDKII_IOMMU_PROTOCOL                       *This,
111   IN     EDKII_IOMMU_OPERATION                      Operation,
112   IN     VOID                                       *HostAddress,
113   IN OUT UINTN                                      *NumberOfBytes,
114   OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
115   OUT    VOID                                       **Mapping
116   )
117 {
118   DMA_MAP_OPERATION     DmaOperation;
119 
120   switch (Operation) {
121     case EdkiiIoMmuOperationBusMasterRead:
122     case EdkiiIoMmuOperationBusMasterRead64:
123       DmaOperation = MapOperationBusMasterRead;
124       break;
125 
126     case EdkiiIoMmuOperationBusMasterWrite:
127     case EdkiiIoMmuOperationBusMasterWrite64:
128       DmaOperation = MapOperationBusMasterWrite;
129       break;
130 
131     case EdkiiIoMmuOperationBusMasterCommonBuffer:
132     case EdkiiIoMmuOperationBusMasterCommonBuffer64:
133       DmaOperation = MapOperationBusMasterCommonBuffer;
134       break;
135 
136     default:
137       ASSERT (FALSE);
138       return EFI_INVALID_PARAMETER;
139   }
140 
141   return DmaMap (DmaOperation, HostAddress, NumberOfBytes,
142            DeviceAddress, Mapping);
143 }
144 
145 /**
146   Completes the Map() operation and releases any corresponding resources.
147 
148   @param  This                  The protocol instance pointer.
149   @param  Mapping               The mapping value returned from Map().
150 
151   @retval EFI_SUCCESS           The range was unmapped.
152   @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by
153                                 Map().
154   @retval EFI_DEVICE_ERROR      The data was not committed to the target system
155                                 memory.
156 **/
157 STATIC
158 EFI_STATUS
159 EFIAPI
NonCoherentIoMmuUnmap(IN EDKII_IOMMU_PROTOCOL * This,IN VOID * Mapping)160 NonCoherentIoMmuUnmap (
161   IN  EDKII_IOMMU_PROTOCOL                     *This,
162   IN  VOID                                     *Mapping
163   )
164 {
165   return DmaUnmap (Mapping);
166 }
167 
168 /**
169   Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
170   OperationBusMasterCommonBuffer64 mapping.
171 
172   @param  This                  The protocol instance pointer.
173   @param  Type                  This parameter is not used and must be ignored.
174   @param  MemoryType            The type of memory to allocate,
175                                 EfiBootServicesData or EfiRuntimeServicesData.
176   @param  Pages                 The number of pages to allocate.
177   @param  HostAddress           A pointer to store the base system memory
178                                 address of the allocated range.
179   @param  Attributes            The requested bit mask of attributes for the
180                                 allocated range.
181 
182   @retval EFI_SUCCESS           The requested memory pages were allocated.
183   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal
184                                 attribute bits are MEMORY_WRITE_COMBINE and
185                                 MEMORY_CACHED.
186   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
187   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
188 
189 **/
190 STATIC
191 EFI_STATUS
192 EFIAPI
NonCoherentIoMmuAllocateBuffer(IN EDKII_IOMMU_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,IN OUT VOID ** HostAddress,IN UINT64 Attributes)193 NonCoherentIoMmuAllocateBuffer (
194   IN     EDKII_IOMMU_PROTOCOL                     *This,
195   IN     EFI_ALLOCATE_TYPE                        Type,
196   IN     EFI_MEMORY_TYPE                          MemoryType,
197   IN     UINTN                                    Pages,
198   IN OUT VOID                                     **HostAddress,
199   IN     UINT64                                   Attributes
200   )
201 {
202   return DmaAllocateBuffer (MemoryType, Pages, HostAddress);
203 }
204 
205 /**
206   Frees memory that was allocated with AllocateBuffer().
207 
208   @param  This                  The protocol instance pointer.
209   @param  Pages                 The number of pages to free.
210   @param  HostAddress           The base system memory address of the allocated
211                                 range.
212 
213   @retval EFI_SUCCESS           The requested memory pages were freed.
214   @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
215                                 Pages was not allocated with AllocateBuffer().
216 
217 **/
218 STATIC
219 EFI_STATUS
220 EFIAPI
NonCoherentIoMmuFreeBuffer(IN EDKII_IOMMU_PROTOCOL * This,IN UINTN Pages,IN VOID * HostAddress)221 NonCoherentIoMmuFreeBuffer (
222   IN  EDKII_IOMMU_PROTOCOL                     *This,
223   IN  UINTN                                    Pages,
224   IN  VOID                                     *HostAddress
225   )
226 {
227   return DmaFreeBuffer (Pages, HostAddress);
228 }
229 
230 STATIC EDKII_IOMMU_PROTOCOL  mNonCoherentIoMmuOps = {
231   EDKII_IOMMU_PROTOCOL_REVISION,
232   NonCoherentIoMmuSetAttribute,
233   NonCoherentIoMmuMap,
234   NonCoherentIoMmuUnmap,
235   NonCoherentIoMmuAllocateBuffer,
236   NonCoherentIoMmuFreeBuffer,
237 };
238 
239 
240 EFI_STATUS
241 EFIAPI
NonCoherentIoMmuDxeEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)242 NonCoherentIoMmuDxeEntryPoint (
243   IN EFI_HANDLE         ImageHandle,
244   IN EFI_SYSTEM_TABLE   *SystemTable
245   )
246 {
247   return gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
248                 &gEdkiiIoMmuProtocolGuid, &mNonCoherentIoMmuOps,
249                 NULL);
250 }
251