From dba6159a710e79db3bd8692b44d8c1c1f9d5e53f Mon Sep 17 00:00:00 2001 From: Laszlo Ersek Date: Thu, 19 Jun 2014 17:15:04 +0200 Subject: OvmfPkg: QemuFlash: preformat an all-zero, flash-based varstore If we find that the variable store area is all-zeroes and backed by flash, preformat it with the expected headers and the padding byte that matches the erase polarity. This is supposed to mask user configuration errors. Suggested-by: Paolo Bonzini --- OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c | 126 +++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c index a96e0e5..cb4d27a 100644 --- a/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c +++ b/OvmfPkg/QemuFlashFvbServicesRuntimeDxe/QemuFlash.c @@ -15,6 +15,7 @@ #include "PiDxe.h" #include #include +#include #include #include #include @@ -37,6 +38,22 @@ STATIC UINT8 *mFlashBase = NULL; STATIC UINTN mFdBlockSize = 0; STATIC UINTN mFdBlockCount = 0; +STATIC CONST UINT8 VarstoreHeader[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8d, 0x2b, 0xf1, 0xff, 0x96, 0x76, 0x8b, 0x4c, 0xa9, 0x85, + 0x27, 0x47, 0x07, 0x5b, 0x4f, 0x50, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00, 0x48, 0x00, 0x19, 0xf9, + 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, + 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92, 0xb8, 0xdf, 0x00, + 0x00, 0x5a, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +STATIC CONST UINT8 WorkingBlockHeader[] = { + 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49, 0xa0, 0xce, 0x65, 0x00, 0xfd, + 0x9f, 0x1b, 0x95, 0x2c, 0xaf, 0x2c, 0x64, 0xfe, 0xff, 0xff, 0xff, 0xe0, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; VOID QemuFlashConvertPointers ( @@ -59,6 +76,111 @@ QemuFlashPtr ( /** + If the leading 128 KB of the flash memory range is all-zeroes, and it behaves + as flash (based on the first byte), then preformat the area. + + @retval EFI_SUCCESS First 128 KB preformatted. + @retval EFI_NOT_FOUND Area has nonzero contents or doesn't behave as + flash. + @retval EFI_OUT_OF_RESOURCES Formatting attempted but abandoned due to lack + of free memory. +**/ +STATIC +EFI_STATUS +PreformatFlash ( + VOID + ) +{ + UINTN VsBlockCount; + volatile UINT8 *Ptr; + UINTN Idx; + UINT8 *Scratch, *ScratchPtr; + + VsBlockCount = 32; + + ASSERT (mFdBlockSize == 4096); + ASSERT (mFdBlockCount >= VsBlockCount); + + Ptr = QemuFlashPtr (0, 0); + for (Idx = 0; Idx < VsBlockCount * mFdBlockSize; ++Idx) { + if (*Ptr++ != 0) { + DEBUG ((EFI_D_INFO, "%a: found nonzero contents\n", __FUNCTION__)); + return EFI_NOT_FOUND; + } + } + + // + // Issue a write command, write a byte with value 1, then flip back the + // flash device to romd mode. + // + Ptr = QemuFlashPtr (0, 0); + *Ptr = WRITE_BYTE_CMD; + *Ptr = 1; + *Ptr = READ_ARRAY_CMD; // value 0xFF + + // + // Read back the value and decide about RAM / ROM / Flash. + // + switch (*Ptr) { + case 0: + // + // found original zero value + // + DEBUG ((EFI_D_INFO, "%a: found ROM\n", __FUNCTION__)); + break; + + case 1: + // + // found the programmed value; format the first 128 KB as authenticated + // variable store + // + Scratch = AllocatePool (VsBlockCount * mFdBlockSize); + if (Scratch == NULL) { + // + // This error will decay to "flash unavailable": the area is all-zeroes, + // hence the caller won't find a probe location. + // + DEBUG ((EFI_D_ERROR, "%a: AllocatePool() failed\n", __FUNCTION__)); + return EFI_OUT_OF_RESOURCES; + } + SetMem (Scratch, VsBlockCount * mFdBlockSize, 0xFF); + CopyMem (Scratch, VarstoreHeader, sizeof VarstoreHeader); + CopyMem (Scratch + 15 * mFdBlockSize, + WorkingBlockHeader, sizeof WorkingBlockHeader); + + ScratchPtr = Scratch; + for (Idx = 0; Idx < VsBlockCount; ++Idx) { + UINTN NumBytes; + EFI_STATUS Status; + + NumBytes = mFdBlockSize; + Status = QemuFlashWrite (Idx, 0, &NumBytes, ScratchPtr); + ASSERT_EFI_ERROR (Status); + ASSERT (NumBytes == mFdBlockSize); + + ScratchPtr += mFdBlockSize; + } + FreePool (Scratch); + DEBUG ((EFI_D_INFO, "%a: formatted FLASH\n", __FUNCTION__)); + return EFI_SUCCESS; + + case READ_ARRAY_CMD: + // + // found the last written, READ_ARRAY_CMD value; restore original + // + *Ptr = 0; + DEBUG ((EFI_D_INFO, "%a: found RAM\n", __FUNCTION__)); + break; + + default: + ASSERT (FALSE); + } + + return EFI_NOT_FOUND; +} + + +/** Determines if the QEMU flash memory device is present. @retval FALSE The QEMU flash device is not present. @@ -78,6 +200,10 @@ QemuFlashDetected ( UINT8 OriginalUint8; UINT8 ProbeUint8; + if (!EFI_ERROR (PreformatFlash ())) { + return TRUE; + } + FlashDetected = FALSE; Ptr = QemuFlashPtr (0, 0); -- 1.8.3.1