+/**\r
+ Allocates aligned pages that are suitable for an OperationBusMasterCommonBuffer or\r
+ OperationBusMasterCommonBuffer64 mapping.\r
+\r
+ @param Pages The number of pages to allocate.\r
+ @param Alignment The requested alignment of the allocation. Must be a power of two.\r
+ @param HostAddress A pointer to store the base system memory address of the\r
+ allocated range.\r
+ @param DeviceAddress The resulting map address for the bus master PCI controller to use to\r
+ access the hosts HostAddress.\r
+ @param Mapping A resulting value to pass to Unmap().\r
+\r
+ @retval EFI_SUCCESS The requested memory pages were allocated.\r
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal attribute bits are\r
+ MEMORY_WRITE_COMBINE and MEMORY_CACHED.\r
+ @retval EFI_INVALID_PARAMETER One or more parameters are invalid.\r
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
+\r
+**/\r
+EFI_STATUS\r
+IoMmuAllocateAlignedBuffer (\r
+ IN UINTN Pages,\r
+ IN UINTN Alignment,\r
+ OUT VOID **HostAddress,\r
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
+ OUT VOID **Mapping\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VOID *Memory;\r
+ UINTN AlignedMemory;\r
+ UINTN AlignmentMask;\r
+ UINTN UnalignedPages;\r
+ UINTN RealPages;\r
+ UINTN NumberOfBytes;\r
+ EFI_PHYSICAL_ADDRESS HostPhyAddress;\r
+\r
+ *HostAddress = NULL;\r
+ *DeviceAddress = 0;\r
+ AlignmentMask = Alignment - 1;\r
+\r
+ //\r
+ // Calculate the total number of pages since alignment is larger than page size.\r
+ //\r
+ RealPages = Pages + EFI_SIZE_TO_PAGES (Alignment);\r
+\r
+ //\r
+ // Make sure that Pages plus EFI_SIZE_TO_PAGES (Alignment) does not overflow.\r
+ //\r
+ ASSERT (RealPages > Pages);\r
+\r
+ if (mIoMmu != NULL) {\r
+ Status = mIoMmu->AllocateBuffer (\r
+ mIoMmu,\r
+ EfiBootServicesData,\r
+ RealPages,\r
+ HostAddress,\r
+ 0\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Memory = *HostAddress;\r
+ AlignedMemory = ((UINTN) Memory + AlignmentMask) & ~AlignmentMask;\r
+ UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN) Memory);\r
+ if (UnalignedPages > 0) {\r
+ //\r
+ // Free first unaligned page(s).\r
+ //\r
+ Status = mIoMmu->FreeBuffer (\r
+ mIoMmu,\r
+ UnalignedPages,\r
+ Memory);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ Memory = (VOID *)(UINTN)(AlignedMemory + EFI_PAGES_TO_SIZE (Pages));\r
+ UnalignedPages = RealPages - Pages - UnalignedPages;\r
+ if (UnalignedPages > 0) {\r
+ //\r
+ // Free last unaligned page(s).\r
+ //\r
+ Status = mIoMmu->FreeBuffer (\r
+ mIoMmu,\r
+ UnalignedPages,\r
+ Memory);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ *HostAddress = (VOID *) AlignedMemory;\r
+ NumberOfBytes = EFI_PAGES_TO_SIZE(Pages);\r
+ Status = mIoMmu->Map (\r
+ mIoMmu,\r
+ EdkiiIoMmuOperationBusMasterCommonBuffer,\r
+ *HostAddress,\r
+ &NumberOfBytes,\r
+ DeviceAddress,\r
+ Mapping\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ Status = mIoMmu->SetAttribute (\r
+ mIoMmu,\r
+ *Mapping,\r
+ EDKII_IOMMU_ACCESS_READ | EDKII_IOMMU_ACCESS_WRITE\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesData,\r
+ RealPages,\r
+ &HostPhyAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ *HostAddress = (VOID *)(((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask);\r
+ *DeviceAddress = ((UINTN) HostPhyAddress + AlignmentMask) & ~AlignmentMask;\r
+ *Mapping = NULL;\r
+ }\r
+ return Status;\r
+}\r
+\r