)\r
{\r
EFI_STATUS Status;\r
- EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
MAP_INFO *MapInfo;\r
- EFI_PHYSICAL_ADDRESS DmaMemoryTop;\r
EFI_ALLOCATE_TYPE AllocateType;\r
\r
if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- //\r
- // Make sure that Operation is valid\r
- //\r
- if ((UINT32) Operation >= EdkiiIoMmuOperationMaximum) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
-\r
- DmaMemoryTop = (UINTN)-1;\r
- AllocateType = AllocateAnyPages;\r
-\r
- if (((Operation != EdkiiIoMmuOperationBusMasterRead64 &&\r
- Operation != EdkiiIoMmuOperationBusMasterWrite64 &&\r
- Operation != EdkiiIoMmuOperationBusMasterCommonBuffer64)) &&\r
- ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {\r
- //\r
- // If the root bridge or the device cannot handle performing DMA above\r
- // 4GB but any part of the DMA transfer being mapped is above 4GB, then\r
- // map the DMA transfer to a buffer below 4GB.\r
- //\r
- DmaMemoryTop = SIZE_4GB - 1;\r
- AllocateType = AllocateMaxAddress;\r
-\r
- if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
- Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
- //\r
- // Common Buffer operations can not be remapped. If the common buffer\r
- // if above 4GB, then it is not possible to generate a mapping, so\r
- // return an error.\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- //\r
- // CommandBuffer was allocated by us (AllocateBuffer) and is already in\r
- // unencryted buffer so no need to create bounce buffer\r
- //\r
- if (Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
- Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
- *Mapping = NO_MAPPING;\r
- *DeviceAddress = PhysicalAddress;\r
-\r
- return EFI_SUCCESS;\r
- }\r
-\r
//\r
// Allocate a MAP_INFO structure to remember the mapping when Unmap() is\r
// called later.\r
//\r
MapInfo = AllocatePool (sizeof (MAP_INFO));\r
if (MapInfo == NULL) {\r
- *NumberOfBytes = 0;\r
- return EFI_OUT_OF_RESOURCES;\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Failed;\r
}\r
\r
//\r
- // Initialize the MAP_INFO structure\r
+ // Initialize the MAP_INFO structure, except the PlainTextAddress field\r
//\r
MapInfo->Operation = Operation;\r
MapInfo->NumberOfBytes = *NumberOfBytes;\r
MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);\r
- MapInfo->CryptedAddress = PhysicalAddress;\r
- MapInfo->PlainTextAddress = DmaMemoryTop;\r
+ MapInfo->CryptedAddress = (UINTN)HostAddress;\r
\r
//\r
- // Allocate a buffer to map the transfer to.\r
+ // In the switch statement below, we point "MapInfo->PlainTextAddress" to the\r
+ // plaintext buffer, according to Operation.\r
//\r
- Status = gBS->AllocatePages (\r
- AllocateType,\r
- EfiBootServicesData,\r
- MapInfo->NumberOfPages,\r
- &MapInfo->PlainTextAddress\r
- );\r
- if (EFI_ERROR (Status)) {\r
+ MapInfo->PlainTextAddress = MAX_ADDRESS;\r
+ AllocateType = AllocateAnyPages;\r
+ switch (Operation) {\r
+ //\r
+ // For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer\r
+ // is necessary regardless of whether the original (crypted) buffer crosses\r
+ // the 4GB limit or not -- we have to allocate a separate plaintext buffer.\r
+ // The only variable is whether the plaintext buffer should be under 4GB.\r
+ //\r
+ case EdkiiIoMmuOperationBusMasterRead:\r
+ case EdkiiIoMmuOperationBusMasterWrite:\r
+ MapInfo->PlainTextAddress = BASE_4GB - 1;\r
+ AllocateType = AllocateMaxAddress;\r
+ //\r
+ // fall through\r
+ //\r
+ case EdkiiIoMmuOperationBusMasterRead64:\r
+ case EdkiiIoMmuOperationBusMasterWrite64:\r
+ //\r
+ // Allocate the implicit plaintext bounce buffer.\r
+ //\r
+ Status = gBS->AllocatePages (\r
+ AllocateType,\r
+ EfiBootServicesData,\r
+ MapInfo->NumberOfPages,\r
+ &MapInfo->PlainTextAddress\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeMapInfo;\r
+ }\r
+ break;\r
+\r
+ //\r
+ // For BusMasterCommonBuffer[64] operations, a plaintext buffer has been\r
+ // allocated already, with AllocateBuffer(). We only check whether the\r
+ // address is low enough for the requested operation.\r
+ //\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+ if ((MapInfo->CryptedAddress > BASE_4GB) ||\r
+ (EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages) >\r
+ BASE_4GB - MapInfo->CryptedAddress)) {\r
+ //\r
+ // CommonBuffer operations cannot be remapped. If the common buffer is\r
+ // above 4GB, then it is not possible to generate a mapping, so return an\r
+ // error.\r
+ //\r
+ Status = EFI_UNSUPPORTED;\r
+ goto FreeMapInfo;\r
+ }\r
+ //\r
+ // fall through\r
+ //\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+ //\r
+ // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(),\r
+ // and it is already decrypted.\r
+ //\r
+ MapInfo->PlainTextAddress = MapInfo->CryptedAddress;\r
+\r
+ //\r
+ // Therefore no mapping is necessary.\r
+ //\r
+ *DeviceAddress = MapInfo->PlainTextAddress;\r
+ *Mapping = NO_MAPPING;\r
FreePool (MapInfo);\r
- *NumberOfBytes = 0;\r
- return Status;\r
+ return EFI_SUCCESS;\r
+\r
+ default:\r
+ //\r
+ // Operation is invalid\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ goto FreeMapInfo;\r
}\r
\r
//\r
- // Clear the memory encryption mask from the device buffer\r
+ // Clear the memory encryption mask on the plaintext buffer.\r
//\r
Status = MemEncryptSevClearPageEncMask (\r
0,\r
}\r
\r
//\r
- // The DeviceAddress is the address of the maped buffer below 4GB\r
+ // Populate output parameters.\r
//\r
*DeviceAddress = MapInfo->PlainTextAddress;\r
-\r
- //\r
- // Return a pointer to the MAP_INFO structure in Mapping\r
- //\r
*Mapping = MapInfo;\r
\r
DEBUG ((\r
));\r
\r
return EFI_SUCCESS;\r
+\r
+FreeMapInfo:\r
+ FreePool (MapInfo);\r
+\r
+Failed:\r
+ *NumberOfBytes = 0;\r
+ return Status;\r
}\r
\r
/**\r