4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "DmaProtection.h"
11 // TBD: May make it a policy
12 #define DMA_MEMORY_TOP MAX_UINTN
13 //#define DMA_MEMORY_TOP 0x0000000001FFFFFFULL
15 #define MAP_HANDLE_INFO_SIGNATURE SIGNATURE_32 ('H', 'M', 'A', 'P')
19 EFI_HANDLE DeviceHandle
;
22 #define MAP_HANDLE_INFO_FROM_LINK(a) CR (a, MAP_HANDLE_INFO, Link, MAP_HANDLE_INFO_SIGNATURE)
24 #define MAP_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'A', 'P')
28 EDKII_IOMMU_OPERATION Operation
;
31 EFI_PHYSICAL_ADDRESS HostAddress
;
32 EFI_PHYSICAL_ADDRESS DeviceAddress
;
33 LIST_ENTRY HandleList
;
35 #define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
37 LIST_ENTRY gMaps
= INITIALIZE_LIST_HEAD_VARIABLE(gMaps
);
40 This function fills DeviceHandle/IoMmuAccess to the MAP_HANDLE_INFO,
41 based upon the DeviceAddress.
43 @param[in] DeviceHandle The device who initiates the DMA access request.
44 @param[in] DeviceAddress The base of device memory address to be used as the DMA memory.
45 @param[in] Length The length of device memory address to be used as the DMA memory.
46 @param[in] IoMmuAccess The IOMMU access.
50 SyncDeviceHandleToMapInfo (
51 IN EFI_HANDLE DeviceHandle
,
52 IN EFI_PHYSICAL_ADDRESS DeviceAddress
,
58 MAP_HANDLE_INFO
*MapHandleInfo
;
63 // Find MapInfo according to DeviceAddress
65 OriginalTpl
= gBS
->RaiseTPL (VTD_TPL_LEVEL
);
67 for (Link
= GetFirstNode (&gMaps
)
68 ; !IsNull (&gMaps
, Link
)
69 ; Link
= GetNextNode (&gMaps
, Link
)
71 MapInfo
= MAP_INFO_FROM_LINK (Link
);
72 if (MapInfo
->DeviceAddress
== DeviceAddress
) {
76 if ((MapInfo
== NULL
) || (MapInfo
->DeviceAddress
!= DeviceAddress
)) {
77 DEBUG ((DEBUG_ERROR
, "SyncDeviceHandleToMapInfo: DeviceAddress(0x%lx) - not found\n", DeviceAddress
));
78 gBS
->RestoreTPL (OriginalTpl
);
83 // Find MapHandleInfo according to DeviceHandle
86 for (Link
= GetFirstNode (&MapInfo
->HandleList
)
87 ; !IsNull (&MapInfo
->HandleList
, Link
)
88 ; Link
= GetNextNode (&MapInfo
->HandleList
, Link
)
90 MapHandleInfo
= MAP_HANDLE_INFO_FROM_LINK (Link
);
91 if (MapHandleInfo
->DeviceHandle
== DeviceHandle
) {
95 if ((MapHandleInfo
!= NULL
) && (MapHandleInfo
->DeviceHandle
== DeviceHandle
)) {
96 MapHandleInfo
->IoMmuAccess
= IoMmuAccess
;
97 gBS
->RestoreTPL (OriginalTpl
);
103 // Initialize and insert the MAP_HANDLE_INFO structure
105 MapHandleInfo
= AllocatePool (sizeof (MAP_HANDLE_INFO
));
106 if (MapHandleInfo
== NULL
) {
107 DEBUG ((DEBUG_ERROR
, "SyncDeviceHandleToMapInfo: %r\n", EFI_OUT_OF_RESOURCES
));
108 gBS
->RestoreTPL (OriginalTpl
);
112 MapHandleInfo
->Signature
= MAP_HANDLE_INFO_SIGNATURE
;
113 MapHandleInfo
->DeviceHandle
= DeviceHandle
;
114 MapHandleInfo
->IoMmuAccess
= IoMmuAccess
;
116 InsertTailList (&MapInfo
->HandleList
, &MapHandleInfo
->Link
);
117 gBS
->RestoreTPL (OriginalTpl
);
123 Provides the controller-specific addresses required to access system memory from a
126 @param This The protocol instance pointer.
127 @param Operation Indicates if the bus master is going to read or write to system memory.
128 @param HostAddress The system memory address to map to the PCI controller.
129 @param NumberOfBytes On input the number of bytes to map. On output the number of bytes
131 @param DeviceAddress The resulting map address for the bus master PCI controller to use to
132 access the hosts HostAddress.
133 @param Mapping A resulting value to pass to Unmap().
135 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
136 @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
137 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
138 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
139 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
145 IN EDKII_IOMMU_PROTOCOL
*This
,
146 IN EDKII_IOMMU_OPERATION Operation
,
147 IN VOID
*HostAddress
,
148 IN OUT UINTN
*NumberOfBytes
,
149 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
154 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
156 EFI_PHYSICAL_ADDRESS DmaMemoryTop
;
160 if (NumberOfBytes
== NULL
|| DeviceAddress
== NULL
||
162 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER
));
163 return EFI_INVALID_PARAMETER
;
166 DEBUG ((DEBUG_VERBOSE
, "IoMmuMap: ==> 0x%08x - 0x%08x (%x)\n", HostAddress
, *NumberOfBytes
, Operation
));
169 // Make sure that Operation is valid
171 if ((UINT32
) Operation
>= EdkiiIoMmuOperationMaximum
) {
172 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_INVALID_PARAMETER
));
173 return EFI_INVALID_PARAMETER
;
176 PhysicalAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
;
178 DmaMemoryTop
= DMA_MEMORY_TOP
;
183 if ((*NumberOfBytes
!= ALIGN_VALUE(*NumberOfBytes
, SIZE_4KB
)) ||
184 (PhysicalAddress
!= ALIGN_VALUE(PhysicalAddress
, SIZE_4KB
))) {
185 if ((Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
) ||
186 (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
)) {
188 // The input buffer might be a subset from IoMmuAllocateBuffer.
196 if ((PhysicalAddress
+ *NumberOfBytes
) >= DMA_MEMORY_TOP
) {
200 if (((Operation
!= EdkiiIoMmuOperationBusMasterRead64
&&
201 Operation
!= EdkiiIoMmuOperationBusMasterWrite64
&&
202 Operation
!= EdkiiIoMmuOperationBusMasterCommonBuffer64
)) &&
203 ((PhysicalAddress
+ *NumberOfBytes
) > SIZE_4GB
)) {
205 // If the root bridge or the device cannot handle performing DMA above
206 // 4GB but any part of the DMA transfer being mapped is above 4GB, then
207 // map the DMA transfer to a buffer below 4GB.
210 DmaMemoryTop
= MIN (DmaMemoryTop
, SIZE_4GB
- 1);
213 if (Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer
||
214 Operation
== EdkiiIoMmuOperationBusMasterCommonBuffer64
) {
217 // Common Buffer operations can not be remapped. If the common buffer
218 // is above 4GB, then it is not possible to generate a mapping, so return
221 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_UNSUPPORTED
));
222 return EFI_UNSUPPORTED
;
227 // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
230 MapInfo
= AllocatePool (sizeof (MAP_INFO
));
231 if (MapInfo
== NULL
) {
233 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", EFI_OUT_OF_RESOURCES
));
234 return EFI_OUT_OF_RESOURCES
;
238 // Initialize the MAP_INFO structure
240 MapInfo
->Signature
= MAP_INFO_SIGNATURE
;
241 MapInfo
->Operation
= Operation
;
242 MapInfo
->NumberOfBytes
= *NumberOfBytes
;
243 MapInfo
->NumberOfPages
= EFI_SIZE_TO_PAGES (MapInfo
->NumberOfBytes
);
244 MapInfo
->HostAddress
= PhysicalAddress
;
245 MapInfo
->DeviceAddress
= DmaMemoryTop
;
246 InitializeListHead(&MapInfo
->HandleList
);
249 // Allocate a buffer below 4GB to map the transfer to.
252 Status
= gBS
->AllocatePages (
255 MapInfo
->NumberOfPages
,
256 &MapInfo
->DeviceAddress
258 if (EFI_ERROR (Status
)) {
261 DEBUG ((DEBUG_ERROR
, "IoMmuMap: %r\n", Status
));
266 // If this is a read operation from the Bus Master's point of view,
267 // then copy the contents of the real buffer into the mapped buffer
268 // so the Bus Master can read the contents of the real buffer.
270 if (Operation
== EdkiiIoMmuOperationBusMasterRead
||
271 Operation
== EdkiiIoMmuOperationBusMasterRead64
) {
273 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
274 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
275 MapInfo
->NumberOfBytes
279 MapInfo
->DeviceAddress
= MapInfo
->HostAddress
;
282 OriginalTpl
= gBS
->RaiseTPL (VTD_TPL_LEVEL
);
283 InsertTailList (&gMaps
, &MapInfo
->Link
);
284 gBS
->RestoreTPL (OriginalTpl
);
287 // The DeviceAddress is the address of the maped buffer below 4GB
289 *DeviceAddress
= MapInfo
->DeviceAddress
;
291 // Return a pointer to the MAP_INFO structure in Mapping
295 DEBUG ((DEBUG_VERBOSE
, "IoMmuMap: 0x%08x - 0x%08x <==\n", *DeviceAddress
, *Mapping
));
301 Completes the Map() operation and releases any corresponding resources.
303 @param This The protocol instance pointer.
304 @param Mapping The mapping value returned from Map().
306 @retval EFI_SUCCESS The range was unmapped.
307 @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
308 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
313 IN EDKII_IOMMU_PROTOCOL
*This
,
318 MAP_HANDLE_INFO
*MapHandleInfo
;
322 DEBUG ((DEBUG_VERBOSE
, "IoMmuUnmap: 0x%08x\n", Mapping
));
324 if (Mapping
== NULL
) {
325 DEBUG ((DEBUG_ERROR
, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER
));
326 return EFI_INVALID_PARAMETER
;
329 OriginalTpl
= gBS
->RaiseTPL (VTD_TPL_LEVEL
);
331 for (Link
= GetFirstNode (&gMaps
)
332 ; !IsNull (&gMaps
, Link
)
333 ; Link
= GetNextNode (&gMaps
, Link
)
335 MapInfo
= MAP_INFO_FROM_LINK (Link
);
336 if (MapInfo
== Mapping
) {
341 // Mapping is not a valid value returned by Map()
343 if (MapInfo
!= Mapping
) {
344 gBS
->RestoreTPL (OriginalTpl
);
345 DEBUG ((DEBUG_ERROR
, "IoMmuUnmap: %r\n", EFI_INVALID_PARAMETER
));
346 return EFI_INVALID_PARAMETER
;
348 RemoveEntryList (&MapInfo
->Link
);
349 gBS
->RestoreTPL (OriginalTpl
);
352 // remove all nodes in MapInfo->HandleList
354 while (!IsListEmpty (&MapInfo
->HandleList
)) {
355 MapHandleInfo
= MAP_HANDLE_INFO_FROM_LINK (MapInfo
->HandleList
.ForwardLink
);
356 RemoveEntryList (&MapHandleInfo
->Link
);
357 FreePool (MapHandleInfo
);
360 if (MapInfo
->DeviceAddress
!= MapInfo
->HostAddress
) {
362 // If this is a write operation from the Bus Master's point of view,
363 // then copy the contents of the mapped buffer into the real buffer
364 // so the processor can read the contents of the real buffer.
366 if (MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite
||
367 MapInfo
->Operation
== EdkiiIoMmuOperationBusMasterWrite64
) {
369 (VOID
*) (UINTN
) MapInfo
->HostAddress
,
370 (VOID
*) (UINTN
) MapInfo
->DeviceAddress
,
371 MapInfo
->NumberOfBytes
376 // Free the mapped buffer and the MAP_INFO structure.
378 gBS
->FreePages (MapInfo
->DeviceAddress
, MapInfo
->NumberOfPages
);
386 Allocates pages that are suitable for an OperationBusMasterCommonBuffer or
387 OperationBusMasterCommonBuffer64 mapping.
389 @param This The protocol instance pointer.
390 @param Type This parameter is not used and must be ignored.
391 @param MemoryType The type of memory to allocate, EfiBootServicesData or
392 EfiRuntimeServicesData.
393 @param Pages The number of pages to allocate.
394 @param HostAddress A pointer to store the base system memory address of the
396 @param Attributes The requested bit mask of attributes for the allocated range.
398 @retval EFI_SUCCESS The requested memory pages were allocated.
399 @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are
400 MEMORY_WRITE_COMBINE, MEMORY_CACHED and DUAL_ADDRESS_CYCLE.
401 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
402 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
407 IoMmuAllocateBuffer (
408 IN EDKII_IOMMU_PROTOCOL
*This
,
409 IN EFI_ALLOCATE_TYPE Type
,
410 IN EFI_MEMORY_TYPE MemoryType
,
412 IN OUT VOID
**HostAddress
,
417 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
419 DEBUG ((DEBUG_VERBOSE
, "IoMmuAllocateBuffer: ==> 0x%08x\n", Pages
));
422 // Validate Attributes
424 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER
) != 0) {
425 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_UNSUPPORTED
));
426 return EFI_UNSUPPORTED
;
430 // Check for invalid inputs
432 if (HostAddress
== NULL
) {
433 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER
));
434 return EFI_INVALID_PARAMETER
;
438 // The only valid memory types are EfiBootServicesData and
439 // EfiRuntimeServicesData
441 if (MemoryType
!= EfiBootServicesData
&&
442 MemoryType
!= EfiRuntimeServicesData
) {
443 DEBUG ((DEBUG_ERROR
, "IoMmuAllocateBuffer: %r\n", EFI_INVALID_PARAMETER
));
444 return EFI_INVALID_PARAMETER
;
447 PhysicalAddress
= DMA_MEMORY_TOP
;
448 if ((Attributes
& EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE
) == 0) {
450 // Limit allocations to memory below 4GB
452 PhysicalAddress
= MIN (PhysicalAddress
, SIZE_4GB
- 1);
454 Status
= gBS
->AllocatePages (
460 if (!EFI_ERROR (Status
)) {
461 *HostAddress
= (VOID
*) (UINTN
) PhysicalAddress
;
464 DEBUG ((DEBUG_VERBOSE
, "IoMmuAllocateBuffer: 0x%08x <==\n", *HostAddress
));
470 Frees memory that was allocated with AllocateBuffer().
472 @param This The protocol instance pointer.
473 @param Pages The number of pages to free.
474 @param HostAddress The base system memory address of the allocated range.
476 @retval EFI_SUCCESS The requested memory pages were freed.
477 @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and Pages
478 was not allocated with AllocateBuffer().
484 IN EDKII_IOMMU_PROTOCOL
*This
,
489 DEBUG ((DEBUG_VERBOSE
, "IoMmuFreeBuffer: 0x%\n", Pages
));
490 return gBS
->FreePages ((EFI_PHYSICAL_ADDRESS
) (UINTN
) HostAddress
, Pages
);
494 Get device information from mapping.
496 @param[in] Mapping The mapping.
497 @param[out] DeviceAddress The device address of the mapping.
498 @param[out] NumberOfPages The number of pages of the mapping.
500 @retval EFI_SUCCESS The device information is returned.
501 @retval EFI_INVALID_PARAMETER The mapping is invalid.
504 GetDeviceInfoFromMapping (
506 OUT EFI_PHYSICAL_ADDRESS
*DeviceAddress
,
507 OUT UINTN
*NumberOfPages
513 if (Mapping
== NULL
) {
514 return EFI_INVALID_PARAMETER
;
518 for (Link
= GetFirstNode (&gMaps
)
519 ; !IsNull (&gMaps
, Link
)
520 ; Link
= GetNextNode (&gMaps
, Link
)
522 MapInfo
= MAP_INFO_FROM_LINK (Link
);
523 if (MapInfo
== Mapping
) {
528 // Mapping is not a valid value returned by Map()
530 if (MapInfo
!= Mapping
) {
531 return EFI_INVALID_PARAMETER
;
534 *DeviceAddress
= MapInfo
->DeviceAddress
;
535 *NumberOfPages
= MapInfo
->NumberOfPages
;