+/** @file\r
+\r
+ Library implementing the LockBox interface for OVMF\r
+\r
+ Copyright (C) 2013, Red Hat, Inc.\r
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials are licensed and made available\r
+ under the terms and conditions of the BSD License which accompanies this\r
+ distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT\r
+ WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/LockBoxLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <LockBoxLib.h>\r
+\r
+#pragma pack(1)\r
+typedef struct {\r
+ EFI_GUID Guid;\r
+ EFI_PHYSICAL_ADDRESS OrigAddress;\r
+ EFI_PHYSICAL_ADDRESS CopyAddress;\r
+ UINT32 Size;\r
+ UINT64 Attributes;\r
+} LOCK_BOX_ENTRY;\r
+#pragma pack()\r
+\r
+LOCK_BOX_GLOBAL *mLockBoxGlobal = NULL;\r
+STATIC LOCK_BOX_ENTRY *StartOfEntries = NULL;\r
+STATIC LOCK_BOX_ENTRY *EndOfEntries = NULL;\r
+\r
+RETURN_STATUS\r
+EFIAPI\r
+LockBoxLibInitialize (\r
+ VOID\r
+ )\r
+{\r
+ UINTN NumEntries;\r
+\r
+ if (PcdGet32 (PcdOvmfLockBoxStorageSize) < sizeof (LOCK_BOX_GLOBAL)) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+\r
+ mLockBoxGlobal = (LOCK_BOX_GLOBAL *)(UINTN) PcdGet32 (PcdOvmfLockBoxStorageBase);\r
+ StartOfEntries = ((LOCK_BOX_ENTRY *) (mLockBoxGlobal + 1));\r
+ NumEntries = ((PcdGet32 (PcdOvmfLockBoxStorageSize) - sizeof (LOCK_BOX_GLOBAL)) /\r
+ sizeof (LOCK_BOX_ENTRY));\r
+ EndOfEntries = StartOfEntries + NumEntries; \r
+ if (mLockBoxGlobal->Signature != LOCK_BOX_GLOBAL_SIGNATURE) {\r
+ //\r
+ // Note: This code depends on the lock box being cleared in early\r
+ // PEI before usage, so the SubPageBuffer and SubPageRemaining\r
+ // fields don't need to be set to 0.\r
+ //\r
+ mLockBoxGlobal->Signature = LOCK_BOX_GLOBAL_SIGNATURE;\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Find LockBox entry based on GUID.\r
+\r
+ @param[in] Guid The GUID to search for.\r
+\r
+ @return Address of the LOCK_BOX_ENTRY found.\r
+\r
+ If NULL, then the item was not found, and there is no space\r
+ left to store a new item.\r
+\r
+ If non-NULL and LOCK_BOX_ENTRY.Size == 0, then the item was not\r
+ found, but a new item can be inserted at the returned location.\r
+\r
+ If non-NULL and LOCK_BOX_ENTRY.Size > 0, then the item was found.\r
+**/\r
+STATIC\r
+LOCK_BOX_ENTRY *\r
+EFIAPI\r
+FindHeaderByGuid (\r
+ IN CONST EFI_GUID *Guid\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+\r
+ for (Header = StartOfEntries; Header < EndOfEntries; Header++) {\r
+ if (Header->Size == 0 || CompareGuid (Guid, &Header->Guid)) {\r
+ return Header;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+\r
+/**\r
+ This function will save confidential information to lockbox.\r
+\r
+ @param Guid the guid to identify the confidential information\r
+ @param Buffer the address of the confidential information\r
+ @param Length the length of the confidential information\r
+\r
+ @retval RETURN_SUCCESS the information is saved successfully.\r
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or\r
+ Length is 0\r
+ @retval RETURN_ALREADY_STARTED the requested GUID already exist.\r
+ @retval RETURN_OUT_OF_RESOURCES no enough resource to save the information.\r
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface\r
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface\r
+ @retval RETURN_UNSUPPORTED the service is not supported by\r
+ implementaion.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SaveLockBox (\r
+ IN GUID *Guid,\r
+ IN VOID *Buffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+ VOID *CopyBuffer;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p Length=0x%x\n", __FUNCTION__,\r
+ Guid, Buffer, (UINT32) Length));\r
+\r
+ if (Guid == NULL || Buffer == NULL || Length == 0) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Length > 0xFFFFFFFF) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Header = FindHeaderByGuid (Guid);\r
+ if (Header == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Header->Size > 0) {\r
+ return RETURN_ALREADY_STARTED;\r
+ }\r
+\r
+ CopyBuffer = AllocateAcpiNvsPool (Length);\r
+ if (CopyBuffer == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // overwrite the current terminator header with new metadata\r
+ //\r
+ CopyGuid (&Header->Guid, Guid);\r
+ Header->OrigAddress = (UINTN) Buffer;\r
+ Header->CopyAddress = (UINTN) CopyBuffer;\r
+ Header->Size = (UINT32) Length;\r
+ Header->Attributes = 0;\r
+\r
+ //\r
+ // copy contents\r
+ //\r
+ CopyMem (CopyBuffer, Buffer, Length);\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function will set lockbox attributes.\r
+\r
+ @param Guid the guid to identify the confidential information\r
+ @param Attributes the attributes of the lockbox\r
+\r
+ @retval RETURN_SUCCESS the information is saved successfully.\r
+ @retval RETURN_INVALID_PARAMETER attributes is invalid.\r
+ @retval RETURN_NOT_FOUND the requested GUID not found.\r
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface\r
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface\r
+ @retval RETURN_UNSUPPORTED the service is not supported by\r
+ implementaion.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+SetLockBoxAttributes (\r
+ IN GUID *Guid,\r
+ IN UINT64 Attributes\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Attributes=0x%Lx\n", __FUNCTION__, Guid,\r
+ Attributes));\r
+\r
+ if (Guid == NULL) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ Header = FindHeaderByGuid (Guid);\r
+ if (!Header || Header->Size == 0) {\r
+ return RETURN_NOT_FOUND;\r
+ }\r
+ Header->Attributes = Attributes;\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function will update confidential information to lockbox.\r
+\r
+ @param Guid the guid to identify the original confidential information\r
+ @param Offset the offset of the original confidential information\r
+ @param Buffer the address of the updated confidential information\r
+ @param Length the length of the updated confidential information\r
+\r
+ @retval RETURN_SUCCESS the information is saved successfully.\r
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or Buffer is NULL, or\r
+ Length is 0.\r
+ @retval RETURN_NOT_FOUND the requested GUID not found.\r
+ @retval RETURN_BUFFER_TOO_SMALL the original buffer to too small to hold\r
+ new information.\r
+ @retval RETURN_ACCESS_DENIED it is too late to invoke this interface\r
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface\r
+ @retval RETURN_UNSUPPORTED the service is not supported by\r
+ implementaion.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+UpdateLockBox (\r
+ IN GUID *Guid,\r
+ IN UINTN Offset,\r
+ IN VOID *Buffer,\r
+ IN UINTN Length\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Offset=0x%x Length=0x%x\n", __FUNCTION__,\r
+ Guid, (UINT32) Offset, (UINT32) Length));\r
+\r
+ if (Guid == NULL || Buffer == NULL || Length == 0) {\r
+ return RETURN_INVALID_PARAMETER;\r
+ }\r
+\r
+ Header = FindHeaderByGuid (Guid);\r
+ if (!Header || Header->Size == 0) {\r
+ return RETURN_NOT_FOUND;\r
+ }\r
+\r
+ if (Header->Size < Offset ||\r
+ Length > Header->Size - Offset) {\r
+ return RETURN_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ CopyMem ((UINT8 *)(UINTN) (Header->CopyAddress) + Offset, Buffer, Length);\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function will restore confidential information from lockbox.\r
+\r
+ @param Guid the guid to identify the confidential information\r
+ @param Buffer the address of the restored confidential information\r
+ NULL means restored to original address, Length MUST be NULL at\r
+ same time.\r
+ @param Length the length of the restored confidential information\r
+\r
+ @retval RETURN_SUCCESS the information is restored successfully.\r
+ @retval RETURN_INVALID_PARAMETER the Guid is NULL, or one of Buffer and\r
+ Length is NULL.\r
+ @retval RETURN_WRITE_PROTECTED Buffer and Length are NULL, but the LockBox\r
+ has no LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE\r
+ attribute.\r
+ @retval RETURN_BUFFER_TOO_SMALL the Length is too small to hold the\r
+ confidential information.\r
+ @retval RETURN_NOT_FOUND the requested GUID not found.\r
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface\r
+ @retval RETURN_ACCESS_DENIED not allow to restore to the address\r
+ @retval RETURN_UNSUPPORTED the service is not supported by\r
+ implementaion.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+RestoreLockBox (\r
+ IN GUID *Guid,\r
+ IN VOID *Buffer, OPTIONAL\r
+ IN OUT UINTN *Length OPTIONAL\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__, Guid,\r
+ Buffer));\r
+\r
+ if ((Guid == NULL) ||\r
+ ((Buffer == NULL) && (Length != NULL)) ||\r
+ ((Buffer != NULL) && (Length == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Header = FindHeaderByGuid (Guid);\r
+ if (!Header || Header->Size == 0) {\r
+ return RETURN_NOT_FOUND;\r
+ }\r
+\r
+ if (Buffer == NULL) {\r
+ if (!(Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE)) {\r
+ return RETURN_WRITE_PROTECTED;\r
+ }\r
+ if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ Buffer = (VOID *)(UINTN) Header->OrigAddress;\r
+ }\r
+\r
+ //\r
+ // Set RestoreLength\r
+ //\r
+ if (Length != NULL) {\r
+ if (Header->Size > *Length) {\r
+ //\r
+ // Input buffer is too small to hold all data.\r
+ //\r
+ *Length = Header->Size;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ *Length = Header->Size;\r
+ }\r
+\r
+ CopyMem (Buffer, (VOID*)(UINTN) Header->CopyAddress, Header->Size);\r
+\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ This function will restore confidential information from all lockbox which\r
+ have RestoreInPlace attribute.\r
+\r
+ @retval RETURN_SUCCESS the information is restored successfully.\r
+ @retval RETURN_NOT_STARTED it is too early to invoke this interface\r
+ @retval RETURN_UNSUPPORTED the service is not supported by\r
+ implementaion.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+RestoreAllLockBoxInPlace (\r
+ VOID\r
+ )\r
+{\r
+ LOCK_BOX_ENTRY *Header;\r
+\r
+ for (Header = StartOfEntries;\r
+ Header < EndOfEntries && Header->Size > 0;\r
+ Header++) {\r
+ if (Header->Attributes & LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE) {\r
+ VOID *Buffer;\r
+\r
+ if (Header->OrigAddress + (Header->Size - 1) > MAX_ADDRESS) {\r
+ return RETURN_UNSUPPORTED;\r
+ }\r
+ Buffer = (VOID *)(UINTN) Header->OrigAddress;\r
+ CopyMem (Buffer, (VOID*)(UINTN)Header->CopyAddress, Header->Size);\r
+ DEBUG ((DEBUG_VERBOSE, "%a: Guid=%g Buffer=%p\n", __FUNCTION__,\r
+ Header->Guid, Buffer));\r
+ }\r
+ }\r
+ return RETURN_SUCCESS;\r
+}\r