1 /** @file
2 The DMA memory help functions.
3 
4 Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
5 
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UhcPeim.h"
11 
12 /**
13   Provides the controller-specific addresses required to access system memory from a
14   DMA bus master.
15 
16   @param IoMmu                  Pointer to IOMMU PPI.
17   @param Operation              Indicates if the bus master is going to read or write to system memory.
18   @param HostAddress            The system memory address to map to the PCI controller.
19   @param NumberOfBytes          On input the number of bytes to map. On output the number of bytes
20                                 that were mapped.
21   @param DeviceAddress          The resulting map address for the bus master PCI controller to use to
22                                 access the hosts HostAddress.
23   @param Mapping                A resulting value to pass to Unmap().
24 
25   @retval EFI_SUCCESS           The range was mapped for the returned NumberOfBytes.
26   @retval EFI_UNSUPPORTED       The HostAddress cannot be mapped as a common buffer.
27   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
28   @retval EFI_OUT_OF_RESOURCES  The request could not be completed due to a lack of resources.
29   @retval EFI_DEVICE_ERROR      The system hardware could not map the requested address.
30 
31 **/
32 EFI_STATUS
IoMmuMap(IN EDKII_IOMMU_PPI * IoMmu,IN EDKII_IOMMU_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)33 IoMmuMap (
34   IN EDKII_IOMMU_PPI        *IoMmu,
35   IN EDKII_IOMMU_OPERATION  Operation,
36   IN VOID                   *HostAddress,
37   IN OUT UINTN              *NumberOfBytes,
38   OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
39   OUT VOID                  **Mapping
40   )
41 {
42   EFI_STATUS    Status;
43   UINT64        Attribute;
44 
45   if (IoMmu != NULL) {
46     Status = IoMmu->Map (
47                       IoMmu,
48                       Operation,
49                       HostAddress,
50                       NumberOfBytes,
51                       DeviceAddress,
52                       Mapping
53                       );
54     if (EFI_ERROR (Status)) {
55       return EFI_OUT_OF_RESOURCES;
56     }
57     switch (Operation) {
58     case EdkiiIoMmuOperationBusMasterRead:
59     case EdkiiIoMmuOperationBusMasterRead64:
60       Attribute = EDKII_IOMMU_ACCESS_READ;
61       break;
62     case EdkiiIoMmuOperationBusMasterWrite:
63     case EdkiiIoMmuOperationBusMasterWrite64:
64       Attribute = EDKII_IOMMU_ACCESS_WRITE;
65       break;
66     case EdkiiIoMmuOperationBusMasterCommonBuffer:
67     case EdkiiIoMmuOperationBusMasterCommonBuffer64:
68       Attribute = EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE;
69       break;
70     default:
71       ASSERT(FALSE);
72       return EFI_INVALID_PARAMETER;
73     }
74     Status = IoMmu->SetAttribute (
75                       IoMmu,
76                       *Mapping,
77                       Attribute
78                       );
79     if (EFI_ERROR (Status)) {
80       IoMmu->Unmap (IoMmu, Mapping);
81       *Mapping = NULL;
82       return Status;
83     }
84   } else {
85     *DeviceAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
86     *Mapping = NULL;
87     Status = EFI_SUCCESS;
88   }
89   return Status;
90 }
91 
92 /**
93   Completes the Map() operation and releases any corresponding resources.
94 
95   @param IoMmu              Pointer to IOMMU PPI.
96   @param Mapping            The mapping value returned from Map().
97 
98 **/
99 VOID
IoMmuUnmap(IN EDKII_IOMMU_PPI * IoMmu,IN VOID * Mapping)100 IoMmuUnmap (
101   IN EDKII_IOMMU_PPI        *IoMmu,
102   IN VOID                  *Mapping
103   )
104 {
105   if (IoMmu != NULL) {
106     IoMmu->SetAttribute (IoMmu, Mapping, 0);
107     IoMmu->Unmap (IoMmu, Mapping);
108   }
109 }
110 
111 /**
112   Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
113   OperationBusMasterCommonBuffer64 mapping.
114 
115   @param IoMmu                  Pointer to IOMMU PPI.
116   @param Pages                  The number of pages to allocate.
117   @param HostAddress            A pointer to store the base system memory address of the
118                                 allocated range.
119   @param DeviceAddress          The resulting map address for the bus master PCI controller to use to
120                                 access the hosts HostAddress.
121   @param Mapping                A resulting value to pass to Unmap().
122 
123   @retval EFI_SUCCESS           The requested memory pages were allocated.
124   @retval EFI_UNSUPPORTED       Attributes is unsupported. The only legal attribute bits are
125                                 MEMORY_WRITE_COMBINE and MEMORY_CACHED.
126   @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
127   @retval EFI_OUT_OF_RESOURCES  The memory pages could not be allocated.
128 
129 **/
130 EFI_STATUS
IoMmuAllocateBuffer(IN EDKII_IOMMU_PPI * IoMmu,IN UINTN Pages,OUT VOID ** HostAddress,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)131 IoMmuAllocateBuffer (
132   IN EDKII_IOMMU_PPI        *IoMmu,
133   IN UINTN                  Pages,
134   OUT VOID                  **HostAddress,
135   OUT EFI_PHYSICAL_ADDRESS  *DeviceAddress,
136   OUT VOID                  **Mapping
137   )
138 {
139   EFI_STATUS            Status;
140   UINTN                 NumberOfBytes;
141   EFI_PHYSICAL_ADDRESS  HostPhyAddress;
142 
143   *HostAddress = NULL;
144   *DeviceAddress = 0;
145   *Mapping = NULL;
146 
147   if (IoMmu != NULL) {
148     Status = IoMmu->AllocateBuffer (
149                       IoMmu,
150                       EfiBootServicesData,
151                       Pages,
152                       HostAddress,
153                       0
154                       );
155     if (EFI_ERROR (Status)) {
156       return EFI_OUT_OF_RESOURCES;
157     }
158 
159     NumberOfBytes = EFI_PAGES_TO_SIZE (Pages);
160     Status = IoMmu->Map (
161                       IoMmu,
162                       EdkiiIoMmuOperationBusMasterCommonBuffer,
163                       *HostAddress,
164                       &NumberOfBytes,
165                       DeviceAddress,
166                       Mapping
167                       );
168     if (EFI_ERROR (Status)) {
169       IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
170       *HostAddress = NULL;
171       return EFI_OUT_OF_RESOURCES;
172     }
173     Status = IoMmu->SetAttribute (
174                       IoMmu,
175                       *Mapping,
176                       EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE
177                       );
178     if (EFI_ERROR (Status)) {
179       IoMmu->Unmap (IoMmu, *Mapping);
180       IoMmu->FreeBuffer (IoMmu, Pages, *HostAddress);
181       *Mapping = NULL;
182       *HostAddress = NULL;
183       return Status;
184     }
185   } else {
186     Status = PeiServicesAllocatePages (
187                EfiBootServicesData,
188                Pages,
189                &HostPhyAddress
190                );
191     if (EFI_ERROR (Status)) {
192       return EFI_OUT_OF_RESOURCES;
193     }
194     *HostAddress = (VOID *) (UINTN) HostPhyAddress;
195     *DeviceAddress = HostPhyAddress;
196     *Mapping = NULL;
197   }
198   return Status;
199 }
200 
201 
202 
203 /**
204   Initialize IOMMU.
205 
206   @param IoMmu              Pointer to pointer to IOMMU PPI.
207 
208 **/
209 VOID
IoMmuInit(OUT EDKII_IOMMU_PPI ** IoMmu)210 IoMmuInit (
211   OUT EDKII_IOMMU_PPI       **IoMmu
212   )
213 {
214   *IoMmu = NULL;
215   PeiServicesLocatePpi (
216     &gEdkiiIoMmuPpiGuid,
217     0,
218     NULL,
219     (VOID **) IoMmu
220     );
221 }
222 
223