4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "DmaProtection.h"
17 // TBD: May make it a policy
18 #define DMA_MEMORY_TOP MAX_UINTN
19 //#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL
21 #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
25 EDKII_IOMMU_OPERATION Operation
;
28 EFI_PHYSICAL_ADDRESS HostAddress
;
29 EFI_PHYSICAL_ADDRESS DeviceAddress
;
31 #define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
33 LIST_ENTRY gMaps
= INITIALIZE_LIST_HEAD_VARIABLE(gMaps
);
36 Provides the controller-specific addresses required to access system memory from a
39 @param This The protocol instance pointer.
40 @param Operation Indicates if the bus master is going to read or write to system memory.
41 @param HostAddress The system memory address to map to the PCI controller.
42 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
44 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
45 access the hosts HostAddress.
46 @param Mapping A resulting value to pass to Unmap().
48 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
49 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
50 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
51 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
52 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
58 IN EDKII_IOMMU_PROTOCOL
*This
,
59 IN EDKII_IOMMU_OPERATION Operation
,
61 IN OUT UINTN
*NumberOfBytes
,
62 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
67 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
69 EFI_PHYSICAL_ADDRESS DmaMemoryTop
;
73 if (NumberOfBytes
== NULL
|| DeviceAddress
== NULL
||
75 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER
));
76 return EFI_INVALID_PARAMETER
;
79 DEBUG ((DEBUG_VERBOSE
, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress
, *NumberOfBytes
, Operation
));
82 // Make sure that Operation is valid
84 if ((UINT32
) Operation
>= EdkiiIoMmuOperationMaximum
) {
85 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER
));
86 return EFI_INVALID_PARAMETER
;
89 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
91 DmaMemoryTop
= DMA_MEMORY_TOP
;
96 if ((*NumberOfBytes
!= ALIGN_VALUE(*NumberOfBytes
, SIZE_4KB
)) ||
97 (PhysicalAddress
!= ALIGN_VALUE(PhysicalAddress
, SIZE_4KB
))) {
98 if ((Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
99 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
)) {
101 // The input buffer might be a subset from IoMmuAllocateBuffer.
109 if ((PhysicalAddress
+ *NumberOfBytes
) >= DMA_MEMORY_TOP
) {
113 if (((Operation
!= EdkiiIoMmuOperationBusMasterRead64
&&
114 Operation
!= EdkiiIoMmuOperationBusMasterWrite64
&&
115 Operation
!= EdkiiIoMmuOperationBusMasterCommonBuffer64
)) &&
116 ((PhysicalAddress
+ *NumberOfBytes
) > SIZE_4GB
)) {
118 // If the root bridge or the device cannot handle performing DMA above
119 // 4GB but any part of the DMA transfer being mapped is above 4GB, then
120 // map the DMA transfer to a buffer below 4GB.
123 DmaMemoryTop
= MIN (DmaMemoryTop
, SIZE_4GB
- 1);
126 if (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
||
127 Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
) {
130 // Common Buffer operations can not be remapped. If the common buffer
131 // is above 4GB, then it is not possible to generate a mapping, so return
134 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_UNSUPPORTED
));
135 return EFI_UNSUPPORTED
;
140 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
143 MapInfo
= AllocatePool (sizeof (MAP_INFO
));
144 if (MapInfo
== NULL
) {
146 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES
));
147 return EFI_OUT_OF_RESOURCES
;
151 // Initialize the MAP_INFO structure
153 MapInfo
->Signature
= MAP_INFO_SIGNATURE
;
154 MapInfo
->Operation
= Operation
;
155 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
156 MapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
);
157 MapInfo
->HostAddress
= PhysicalAddress
;
158 MapInfo
->DeviceAddress
= DmaMemoryTop
;
161 // Allocate a buffer below 4GB to map the transfer to.
164 Status
= gBS
->AllocatePages (
167 MapInfo
->NumberOfPages
,
168 &MapInfo
->DeviceAddress
170 if (EFI_ERROR (Status
)) {
173 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", Status
));
178 // If this is a read operation from the Bus Master's point of view,
179 // then copy the contents of the real buffer into the mapped buffer
180 // so the Bus Master can read the contents of the real buffer.
182 if (Operation
== EdkiiIoMmuOperationBusMasterRead
||
183 Operation
== EdkiiIoMmuOperationBusMasterRead64
) {
185 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
186 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
187 MapInfo
->NumberOfBytes
191 MapInfo
->DeviceAddress
= MapInfo
->HostAddress
;
194 OriginalTpl
= gBS
->RaiseTPL (VTD_TPL_LEVEL
);
195 InsertTailList (&gMaps
, &MapInfo
->Link
);
196 gBS
->RestoreTPL (OriginalTpl
);
199 // The DeviceAddress is the address of the maped buffer below 4GB
201 *DeviceAddress
= MapInfo
->DeviceAddress
;
203 // Return a pointer to the MAP_INFO structure in Mapping
207 DEBUG ((DEBUG_VERBOSE
, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress
, *Mapping
));
213 Completes the Map() operation and releases any corresponding resources.
215 @param This The protocol instance pointer.
216 @param Mapping The mapping value returned from Map().
218 @retval EFI_SUCCESS The range was unmapped.
219 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
220 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
225 IN EDKII_IOMMU_PROTOCOL
*This
,
233 DEBUG ((DEBUG_VERBOSE
, "IoMmuUnmap: 0x%08x\n", Mapping
));
235 if (Mapping
== NULL
) {
236 DEBUG ((DEBUG_ERROR
, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER
));
237 return EFI_INVALID_PARAMETER
;
240 OriginalTpl
= gBS
->RaiseTPL (VTD_TPL_LEVEL
);
242 for (Link
= GetFirstNode (&gMaps
)
243 ; !IsNull (&gMaps
, Link
)
244 ; Link
= GetNextNode (&gMaps
, Link
)
246 MapInfo
= MAP_INFO_FROM_LINK (Link
);
247 if (MapInfo
== Mapping
) {
252 // Mapping is not a valid value returned by Map()
254 if (MapInfo
!= Mapping
) {
255 gBS
->RestoreTPL (OriginalTpl
);
256 DEBUG ((DEBUG_ERROR
, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER
));
257 return EFI_INVALID_PARAMETER
;
259 RemoveEntryList (&MapInfo
->Link
);
260 gBS
->RestoreTPL (OriginalTpl
);
262 if (MapInfo
->DeviceAddress
!= MapInfo
->HostAddress
) {
264 // If this is a write operation from the Bus Master's point of view,
265 // then copy the contents of the mapped buffer into the real buffer
266 // so the processor can read the contents of the real buffer.
268 if (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite
||
269 MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite64
) {
271 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
272 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
273 MapInfo
->NumberOfBytes
278 // Free the mapped buffer and the MAP_INFO structure.
280 gBS
->FreePages (MapInfo
->DeviceAddress
, MapInfo
->NumberOfPages
);
288 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
289 OperationBusMasterCommonBuffer64 mapping.
291 @param This The protocol instance pointer.
292 @param Type This parameter is not used and must be ignored.
293 @param MemoryType The type of memory to allocate, EfiBootServicesData or
294 EfiRuntimeServicesData.
295 @param Pages The number of pages to allocate.
296 @param HostAddress A pointer to store the base system memory address of the
298 @param Attributes The requested bit mask of attributes for the allocated range.
300 @retval EFI_SUCCESS The requested memory pages were allocated.
301 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
302 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
303 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
304 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
309 IoMmuAllocateBuffer (
310 IN EDKII_IOMMU_PROTOCOL
*This
,
311 IN EFI_ALLOCATE_TYPE Type
,
312 IN EFI_MEMORY_TYPE MemoryType
,
314 IN OUT VOID
**HostAddress
,
319 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
321 DEBUG ((DEBUG_VERBOSE
, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages
));
324 // Validate Attributes
326 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) != 0) {
327 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED
));
328 return EFI_UNSUPPORTED
;
332 // Check for invalid inputs
334 if (HostAddress
== NULL
) {
335 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER
));
336 return EFI_INVALID_PARAMETER
;
340 // The only valid memory types are EfiBootServicesData and
341 // EfiRuntimeServicesData
343 if (MemoryType
!= EfiBootServicesData
&&
344 MemoryType
!= EfiRuntimeServicesData
) {
345 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER
));
346 return EFI_INVALID_PARAMETER
;
349 PhysicalAddress
= DMA_MEMORY_TOP
;
350 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0) {
352 // Limit allocations to memory below 4GB
354 PhysicalAddress
= MIN (PhysicalAddress
, SIZE_4GB
- 1);
356 Status
= gBS
->AllocatePages (
362 if (!EFI_ERROR (Status
)) {
363 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
366 DEBUG ((DEBUG_VERBOSE
, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress
));
372 Frees memory that was allocated with AllocateBuffer().
374 @param This The protocol instance pointer.
375 @param Pages The number of pages to free.
376 @param HostAddress The base system memory address of the allocated range.
378 @retval EFI_SUCCESS The requested memory pages were freed.
379 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
380 was not allocated with AllocateBuffer().
386 IN EDKII_IOMMU_PROTOCOL
*This
,
391 DEBUG ((DEBUG_VERBOSE
, "IoMmuFreeBuffer: 0x%\n", Pages
));
392 return gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
, Pages
);
396 Get device information from mapping.
398 @param[in] Mapping The mapping.
399 @param[out] DeviceAddress The device address of the mapping.
400 @param[out] NumberOfPages The number of pages of the mapping.
402 @retval EFI_SUCCESS The device information is returned.
403 @retval EFI_INVALID_PARAMETER The mapping is invalid.
406 GetDeviceInfoFromMapping (
408 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
409 OUT UINTN
*NumberOfPages
415 if (Mapping
== NULL
) {
416 return EFI_INVALID_PARAMETER
;
420 for (Link
= GetFirstNode (&gMaps
)
421 ; !IsNull (&gMaps
, Link
)
422 ; Link
= GetNextNode (&gMaps
, Link
)
424 MapInfo
= MAP_INFO_FROM_LINK (Link
);
425 if (MapInfo
== Mapping
) {
430 // Mapping is not a valid value returned by Map()
432 if (MapInfo
!= Mapping
) {
433 return EFI_INVALID_PARAMETER
;
436 *DeviceAddress
= MapInfo
->DeviceAddress
;
437 *NumberOfPages
= MapInfo
->NumberOfPages
;