DmaMem.c 7.8 KB

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