#include <IndustryStandard/Pci22.h>\r
#include <IndustryStandard/Q35MchIch9.h>\r
#include <IndustryStandard/QemuCpuHotplug.h>\r
+#include <Library/MemoryAllocationLib.h>\r
#include <Library/QemuFwCfgLib.h>\r
#include <Library/QemuFwCfgS3Lib.h>\r
#include <Library/QemuFwCfgSimpleParserLib.h>\r
#include <Library/PciLib.h>\r
+#include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/VariableFormat.h>\r
#include <OvmfPlatforms.h>\r
\r
#include <Library/PlatformInitLib.h>\r
PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber = MaxCpuCount;\r
PlatformInfoHob->PcdCpuBootLogicalProcessorNumber = BootCpuCount;\r
}\r
+\r
+/**\r
+ Check padding data all bit should be 1.\r
+\r
+ @param[in] Buffer - A pointer to buffer header\r
+ @param[in] BufferSize - Buffer size\r
+\r
+ @retval TRUE - The padding data is valid.\r
+ @retval TRUE - The padding data is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+CheckPaddingData (\r
+ IN UINT8 *Buffer,\r
+ IN UINT32 BufferSize\r
+ )\r
+{\r
+ UINT32 index;\r
+\r
+ for (index = 0; index < BufferSize; index++) {\r
+ if (Buffer[index] != 0xFF) {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Check the integrity of NvVarStore.\r
+\r
+ @param[in] NvVarStoreBase - A pointer to NvVarStore header\r
+ @param[in] NvVarStoreSize - NvVarStore size\r
+\r
+ @retval TRUE - The NvVarStore is valid.\r
+ @retval FALSE - The NvVarStore is invalid.\r
+\r
+**/\r
+BOOLEAN\r
+EFIAPI\r
+PlatformValidateNvVarStore (\r
+ IN UINT8 *NvVarStoreBase,\r
+ IN UINT32 NvVarStoreSize\r
+ )\r
+{\r
+ UINT16 Checksum;\r
+ UINTN VariableBase;\r
+ UINT32 VariableOffset;\r
+ UINT32 VariableOffsetBeforeAlign;\r
+ EFI_FIRMWARE_VOLUME_HEADER *NvVarStoreFvHeader;\r
+ VARIABLE_STORE_HEADER *NvVarStoreHeader;\r
+ AUTHENTICATED_VARIABLE_HEADER *VariableHeader;\r
+\r
+ static EFI_GUID FvHdrGUID = EFI_SYSTEM_NV_DATA_FV_GUID;\r
+ static EFI_GUID VarStoreHdrGUID = EFI_AUTHENTICATED_VARIABLE_GUID;\r
+\r
+ VariableOffset = 0;\r
+\r
+ if (NvVarStoreBase == NULL) {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore pointer is NULL.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Verify the header zerovetor, filesystemguid,\r
+ // revision, signature, attributes, fvlength, checksum\r
+ // HeaderLength cannot be an odd number\r
+ //\r
+ NvVarStoreFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvVarStoreBase;\r
+\r
+ if ((!IsZeroBuffer (NvVarStoreFvHeader->ZeroVector, 16)) ||\r
+ (!CompareGuid (&FvHdrGUID, &NvVarStoreFvHeader->FileSystemGuid)) ||\r
+ (NvVarStoreFvHeader->Signature != EFI_FVH_SIGNATURE) ||\r
+ (NvVarStoreFvHeader->Attributes != 0x4feff) ||\r
+ (NvVarStoreFvHeader->Revision != EFI_FVH_REVISION) ||\r
+ (NvVarStoreFvHeader->FvLength != NvVarStoreSize)\r
+ )\r
+ {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore FV headers were invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Verify the header checksum\r
+ //\r
+ Checksum = CalculateSum16 ((VOID *)NvVarStoreFvHeader, NvVarStoreFvHeader->HeaderLength);\r
+\r
+ if (Checksum != 0) {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore FV checksum was invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Verify the header signature, size, format, state\r
+ //\r
+ NvVarStoreHeader = (VARIABLE_STORE_HEADER *)(NvVarStoreBase + NvVarStoreFvHeader->HeaderLength);\r
+ if ((!CompareGuid (&VarStoreHdrGUID, &NvVarStoreHeader->Signature)) ||\r
+ (NvVarStoreHeader->Format != VARIABLE_STORE_FORMATTED) ||\r
+ (NvVarStoreHeader->State != VARIABLE_STORE_HEALTHY) ||\r
+ (NvVarStoreHeader->Size > (NvVarStoreFvHeader->FvLength - NvVarStoreFvHeader->HeaderLength)) ||\r
+ (NvVarStoreHeader->Size < sizeof (VARIABLE_STORE_HEADER))\r
+ )\r
+ {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore header signature/size/format/state were invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Verify the header startId, state\r
+ // Verify data to the end\r
+ //\r
+ VariableBase = (UINTN)NvVarStoreBase + NvVarStoreFvHeader->HeaderLength + sizeof (VARIABLE_STORE_HEADER);\r
+ while (VariableOffset < (NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {\r
+ VariableHeader = (AUTHENTICATED_VARIABLE_HEADER *)(VariableBase + VariableOffset);\r
+ if (VariableHeader->StartId != VARIABLE_DATA) {\r
+ if (!CheckPaddingData ((UINT8 *)VariableHeader, NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - VariableOffset)) {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore variable header StartId was invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ VariableOffset = NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
+ } else {\r
+ if (!((VariableHeader->State == VAR_IN_DELETED_TRANSITION) ||\r
+ (VariableHeader->State == VAR_DELETED) ||\r
+ (VariableHeader->State == VAR_HEADER_VALID_ONLY) ||\r
+ (VariableHeader->State == VAR_ADDED)))\r
+ {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore Variable header State was invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ VariableOffset += sizeof (AUTHENTICATED_VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize;\r
+ // Verify VariableOffset should be less than or equal NvVarStoreHeader->Size - sizeof(VARIABLE_STORE_HEADER)\r
+ if (VariableOffset > (NvVarStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER))) {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore Variable header VariableOffset was invalid.\n"));\r
+ return FALSE;\r
+ }\r
+\r
+ VariableOffsetBeforeAlign = VariableOffset;\r
+ // 4 byte align\r
+ VariableOffset = (VariableOffset + 3) & (UINTN)(~3);\r
+\r
+ if (!CheckPaddingData ((UINT8 *)(VariableBase + VariableOffsetBeforeAlign), VariableOffset - VariableOffsetBeforeAlign)) {\r
+ DEBUG ((DEBUG_ERROR, "NvVarStore Variable header PaddingData was invalid.\n"));\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Allocate storage for NV variables early on so it will be\r
+ at a consistent address. Since VM memory is preserved\r
+ across reboots, this allows the NV variable storage to survive\r
+ a VM reboot.\r
+\r
+ *\r
+ * @retval VOID* The pointer to the storage for NV Variables\r
+ */\r
+VOID *\r
+EFIAPI\r
+PlatformReserveEmuVariableNvStore (\r
+ VOID\r
+ )\r
+{\r
+ VOID *VariableStore;\r
+ UINT32 VarStoreSize;\r
+\r
+ VarStoreSize = 2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
+ //\r
+ // Allocate storage for NV variables early on so it will be\r
+ // at a consistent address. Since VM memory is preserved\r
+ // across reboots, this allows the NV variable storage to survive\r
+ // a VM reboot.\r
+ //\r
+ VariableStore =\r
+ AllocateRuntimePages (\r
+ EFI_SIZE_TO_PAGES (VarStoreSize)\r
+ );\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Reserved variable store memory: 0x%p; size: %dkb\n",\r
+ VariableStore,\r
+ VarStoreSize / 1024\r
+ ));\r
+\r
+ return VariableStore;\r
+}\r
+\r
+/**\r
+ When OVMF is lauched with -bios parameter, UEFI variables will be\r
+ partially emulated, and non-volatile variables may lose their contents\r
+ after a reboot. This makes the secure boot feature not working.\r
+\r
+ This function is used to initialize the EmuVariableNvStore\r
+ with the conent in PcdOvmfFlashNvStorageVariableBase.\r
+\r
+ @param[in] EmuVariableNvStore - A pointer to EmuVariableNvStore\r
+\r
+ @retval EFI_SUCCESS - Successfully init the EmuVariableNvStore\r
+ @retval Others - As the error code indicates\r
+ */\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformInitEmuVariableNvStore (\r
+ IN VOID *EmuVariableNvStore\r
+ )\r
+{\r
+ UINT8 *Base;\r
+ UINT32 Size;\r
+ UINT32 EmuVariableNvStoreSize;\r
+\r
+ EmuVariableNvStoreSize = 2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
+ if ((EmuVariableNvStore == NULL) || (EmuVariableNvStoreSize == 0)) {\r
+ DEBUG ((DEBUG_ERROR, "Invalid EmuVariableNvStore parameter.\n"));\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Base = (UINT8 *)(UINTN)PcdGet32 (PcdOvmfFlashNvStorageVariableBase);\r
+ Size = (UINT32)PcdGet32 (PcdFlashNvStorageVariableSize);\r
+ ASSERT (Size < EmuVariableNvStoreSize);\r
+\r
+ if (!PlatformValidateNvVarStore (Base, PcdGet32 (PcdCfvRawDataSize))) {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ DEBUG ((DEBUG_INFO, "Init EmuVariableNvStore with the content in FlashNvStorage\n"));\r
+\r
+ CopyMem (EmuVariableNvStore, Base, Size);\r
+\r
+ return EFI_SUCCESS;\r
+}\r