EFI_PHYSICAL_ADDRESS PlainTextAddress;\r
} MAP_INFO;\r
\r
-#define NO_MAPPING (VOID *) (UINTN) -1\r
+#define COMMON_BUFFER_SIG SIGNATURE_64 ('C', 'M', 'N', 'B', 'U', 'F', 'F', 'R')\r
+\r
+//\r
+// The following structure enables Map() and Unmap() to perform in-place\r
+// decryption and encryption, respectively, for BusMasterCommonBuffer[64]\r
+// operations, without dynamic memory allocation or release.\r
+//\r
+// Both COMMON_BUFFER_HEADER and COMMON_BUFFER_HEADER.StashBuffer are allocated\r
+// by AllocateBuffer() and released by FreeBuffer().\r
+//\r
+#pragma pack (1)\r
+typedef struct {\r
+ UINT64 Signature;\r
+\r
+ //\r
+ // Always allocated from EfiBootServicesData type memory, and always\r
+ // encrypted.\r
+ //\r
+ VOID *StashBuffer;\r
+\r
+ //\r
+ // Followed by the actual common buffer, starting at the next page.\r
+ //\r
+} COMMON_BUFFER_HEADER;\r
+#pragma pack ()\r
\r
/**\r
Provides the controller-specific addresses required to access system memory\r
EFI_STATUS Status;\r
MAP_INFO *MapInfo;\r
EFI_ALLOCATE_TYPE AllocateType;\r
+ COMMON_BUFFER_HEADER *CommonBufferHeader;\r
+ VOID *DecryptionSource;\r
\r
if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||\r
Mapping == NULL) {\r
\r
//\r
// In the switch statement below, we point "MapInfo->PlainTextAddress" to the\r
- // plaintext buffer, according to Operation.\r
+ // plaintext buffer, according to Operation. We also set "DecryptionSource".\r
//\r
MapInfo->PlainTextAddress = MAX_ADDRESS;\r
AllocateType = AllocateAnyPages;\r
+ DecryptionSource = (VOID *)(UINTN)MapInfo->CryptedAddress;\r
switch (Operation) {\r
//\r
// For BusMasterRead[64] and BusMasterWrite[64] operations, a bounce buffer\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
+ // For BusMasterCommonBuffer[64] operations, a to-be-plaintext buffer and a\r
+ // stash buffer (for in-place decryption) have been allocated already, with\r
+ // AllocateBuffer(). We only check whether the address of the to-be-plaintext\r
+ // buffer is low enough for the requested operation.\r
//\r
case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
if ((MapInfo->CryptedAddress > BASE_4GB) ||\r
//\r
case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
//\r
- // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer(),\r
- // and it is already decrypted.\r
+ // The buffer at MapInfo->CryptedAddress comes from AllocateBuffer().\r
//\r
MapInfo->PlainTextAddress = MapInfo->CryptedAddress;\r
-\r
//\r
- // Therefore no mapping is necessary.\r
+ // Stash the crypted data.\r
//\r
- *DeviceAddress = MapInfo->PlainTextAddress;\r
- *Mapping = NO_MAPPING;\r
- FreePool (MapInfo);\r
- return EFI_SUCCESS;\r
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
+ (UINTN)MapInfo->CryptedAddress - EFI_PAGE_SIZE\r
+ );\r
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
+ CopyMem (\r
+ CommonBufferHeader->StashBuffer,\r
+ (VOID *)(UINTN)MapInfo->CryptedAddress,\r
+ MapInfo->NumberOfBytes\r
+ );\r
+ //\r
+ // Point "DecryptionSource" to the stash buffer so that we decrypt\r
+ // it to the original location, after the switch statement.\r
+ //\r
+ DecryptionSource = CommonBufferHeader->StashBuffer;\r
+ break;\r
\r
default:\r
//\r
// then copy the contents of the real buffer into the mapped buffer\r
// so the Bus Master can read the contents of the real buffer.\r
//\r
+ // For BusMasterCommonBuffer[64] operations, the CopyMem() below will decrypt\r
+ // the original data (from the stash buffer) back to the original location.\r
+ //\r
if (Operation == EdkiiIoMmuOperationBusMasterRead ||\r
- Operation == EdkiiIoMmuOperationBusMasterRead64) {\r
+ Operation == EdkiiIoMmuOperationBusMasterRead64 ||\r
+ Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
+ Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
CopyMem (\r
(VOID *) (UINTN) MapInfo->PlainTextAddress,\r
- (VOID *) (UINTN) MapInfo->CryptedAddress,\r
+ DecryptionSource,\r
MapInfo->NumberOfBytes\r
);\r
}\r
{\r
MAP_INFO *MapInfo;\r
EFI_STATUS Status;\r
+ COMMON_BUFFER_HEADER *CommonBufferHeader;\r
+ VOID *EncryptionTarget;\r
\r
if (Mapping == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ MapInfo = (MAP_INFO *)Mapping;\r
+\r
//\r
- // See if the Map() operation associated with this Unmap() required a mapping\r
- // buffer. If a mapping buffer was not required, then this function simply\r
- // buffer. If a mapping buffer was not required, then this function simply\r
+ // set CommonBufferHeader to suppress incorrect compiler/analyzer warnings\r
//\r
- if (Mapping == NO_MAPPING) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- MapInfo = (MAP_INFO *)Mapping;\r
+ CommonBufferHeader = NULL;\r
\r
//\r
- // If this is a write operation from the Bus Master's point of view,\r
- // then copy the contents of the mapped buffer into the real buffer\r
- // so the processor can read the contents of the real buffer.\r
+ // For BusMasterWrite[64] operations and BusMasterCommonBuffer[64] operations\r
+ // we have to encrypt the results, ultimately to the original place (i.e.,\r
+ // "MapInfo->CryptedAddress").\r
+ //\r
+ // For BusMasterCommonBuffer[64] operations however, this encryption has to\r
+ // land in-place, so divert the encryption to the stash buffer first.\r
//\r
- if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite ||\r
- MapInfo->Operation == EdkiiIoMmuOperationBusMasterWrite64) {\r
+ EncryptionTarget = (VOID *)(UINTN)MapInfo->CryptedAddress;\r
+\r
+ switch (MapInfo->Operation) {\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer:\r
+ case EdkiiIoMmuOperationBusMasterCommonBuffer64:\r
+ ASSERT (MapInfo->PlainTextAddress == MapInfo->CryptedAddress);\r
+\r
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
+ (UINTN)MapInfo->PlainTextAddress - EFI_PAGE_SIZE\r
+ );\r
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
+ EncryptionTarget = CommonBufferHeader->StashBuffer;\r
+ //\r
+ // fall through\r
+ //\r
+\r
+ case EdkiiIoMmuOperationBusMasterWrite:\r
+ case EdkiiIoMmuOperationBusMasterWrite64:\r
CopyMem (\r
- (VOID *) (UINTN) MapInfo->CryptedAddress,\r
+ EncryptionTarget,\r
(VOID *) (UINTN) MapInfo->PlainTextAddress,\r
MapInfo->NumberOfBytes\r
);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // nothing to encrypt after BusMasterRead[64] operations\r
+ //\r
+ break;\r
}\r
\r
DEBUG ((\r
(UINT64)MapInfo->NumberOfPages,\r
(UINT64)MapInfo->NumberOfBytes\r
));\r
+\r
//\r
- // Restore the memory encryption mask\r
+ // Restore the memory encryption mask on the area we used to hold the\r
+ // plaintext.\r
//\r
Status = MemEncryptSevSetPageEncMask (\r
0,\r
TRUE\r
);\r
ASSERT_EFI_ERROR(Status);\r
- ZeroMem (\r
- (VOID*)(UINTN)MapInfo->PlainTextAddress,\r
- EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)\r
- );\r
\r
//\r
- // Free the mapped buffer and the MAP_INFO structure.\r
+ // For BusMasterCommonBuffer[64] operations, copy the stashed data to the\r
+ // original (now encrypted) location.\r
+ //\r
+ // For all other operations, fill the late bounce buffer (which existed as\r
+ // plaintext at some point) with zeros, and then release it.\r
+ //\r
+ if (MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer ||\r
+ MapInfo->Operation == EdkiiIoMmuOperationBusMasterCommonBuffer64) {\r
+ CopyMem (\r
+ (VOID *)(UINTN)MapInfo->CryptedAddress,\r
+ CommonBufferHeader->StashBuffer,\r
+ MapInfo->NumberOfBytes\r
+ );\r
+ } else {\r
+ ZeroMem (\r
+ (VOID *)(UINTN)MapInfo->PlainTextAddress,\r
+ EFI_PAGES_TO_SIZE (MapInfo->NumberOfPages)\r
+ );\r
+ gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);\r
+ }\r
+\r
+ //\r
+ // Free the MAP_INFO structure.\r
//\r
- gBS->FreePages (MapInfo->PlainTextAddress, MapInfo->NumberOfPages);\r
FreePool (Mapping);\r
return EFI_SUCCESS;\r
}\r
{\r
EFI_STATUS Status;\r
EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
+ VOID *StashBuffer;\r
+ UINTN CommonBufferPages;\r
+ COMMON_BUFFER_HEADER *CommonBufferHeader;\r
\r
//\r
// Validate Attributes\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ //\r
+ // We'll need a header page for the COMMON_BUFFER_HEADER structure.\r
+ //\r
+ if (Pages > MAX_UINTN - 1) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ CommonBufferPages = Pages + 1;\r
+\r
+ //\r
+ // Allocate the stash in EfiBootServicesData type memory.\r
+ //\r
+ // Map() will temporarily save encrypted data in the stash for\r
+ // BusMasterCommonBuffer[64] operations, so the data can be decrypted to the\r
+ // original location.\r
+ //\r
+ // Unmap() will temporarily save plaintext data in the stash for\r
+ // BusMasterCommonBuffer[64] operations, so the data can be encrypted to the\r
+ // original location.\r
+ //\r
+ // StashBuffer always resides in encrypted memory.\r
+ //\r
+ StashBuffer = AllocatePages (Pages);\r
+ if (StashBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
PhysicalAddress = (UINTN)-1;\r
if ((Attributes & EDKII_IOMMU_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {\r
//\r
Status = gBS->AllocatePages (\r
AllocateMaxAddress,\r
MemoryType,\r
- Pages,\r
+ CommonBufferPages,\r
&PhysicalAddress\r
);\r
- if (!EFI_ERROR (Status)) {\r
- *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
-\r
- //\r
- // Clear memory encryption mask\r
- //\r
- Status = MemEncryptSevClearPageEncMask (0, PhysicalAddress, Pages, TRUE);\r
- ASSERT_EFI_ERROR(Status);\r
+ if (EFI_ERROR (Status)) {\r
+ goto FreeStashBuffer;\r
}\r
\r
+ CommonBufferHeader = (VOID *)(UINTN)PhysicalAddress;\r
+ PhysicalAddress += EFI_PAGE_SIZE;\r
+\r
+ CommonBufferHeader->Signature = COMMON_BUFFER_SIG;\r
+ CommonBufferHeader->StashBuffer = StashBuffer;\r
+\r
+ *HostAddress = (VOID *)(UINTN)PhysicalAddress;\r
+\r
DEBUG ((\r
DEBUG_VERBOSE,\r
"%a Address 0x%Lx Pages 0x%Lx\n",\r
PhysicalAddress,\r
(UINT64)Pages\r
));\r
+ return EFI_SUCCESS;\r
+\r
+FreeStashBuffer:\r
+ FreePages (StashBuffer, Pages);\r
return Status;\r
}\r
\r
IN VOID *HostAddress\r
)\r
{\r
- EFI_STATUS Status;\r
+ UINTN CommonBufferPages;\r
+ COMMON_BUFFER_HEADER *CommonBufferHeader;\r
+\r
+ CommonBufferPages = Pages + 1;\r
+ CommonBufferHeader = (COMMON_BUFFER_HEADER *)(\r
+ (UINTN)HostAddress - EFI_PAGE_SIZE\r
+ );\r
\r
//\r
- // Set memory encryption mask\r
+ // Check the signature.\r
//\r
- Status = MemEncryptSevSetPageEncMask (\r
- 0,\r
- (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress,\r
- Pages,\r
- TRUE\r
- );\r
- ASSERT_EFI_ERROR(Status);\r
- ZeroMem (HostAddress, EFI_PAGES_TO_SIZE (Pages));\r
+ ASSERT (CommonBufferHeader->Signature == COMMON_BUFFER_SIG);\r
+ if (CommonBufferHeader->Signature != COMMON_BUFFER_SIG) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Free the stash buffer. This buffer was always encrypted, so no need to\r
+ // zero it.\r
+ //\r
+ FreePages (CommonBufferHeader->StashBuffer, Pages);\r
\r
DEBUG ((\r
DEBUG_VERBOSE,\r
(UINT64)(UINTN)HostAddress,\r
(UINT64)Pages\r
));\r
- return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);\r
+\r
+ //\r
+ // Release the common buffer itself. Unmap() has re-encrypted it in-place, so\r
+ // no need to zero it.\r
+ //\r
+ return gBS->FreePages ((UINTN)CommonBufferHeader, CommonBufferPages);\r
}\r
\r
\r