From dba6159a710e79db3bd8692b44d8c1c1f9d5e53f Mon Sep 17 00:00:00 2001
From: Laszlo Ersek <lersek@redhat.com>
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 <pbonzini@redhat.com>
---
 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 <Library/DebugLib.h>
 #include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
 #include <Library/PcdLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiRuntimeLib.h>
@@ -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

