public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Tuan Phan" <tphan@ventanamicro.com>
To: devel@edk2.groups.io
Cc: andyw@imsa.edu, maobibo@loongson.cn, lichao@loongson.cn,
	kraxel@redhat.com, jiewen.yao@intel.com,
	leif.lindholm@oss.qualcomm.com, sami.mujawar@arm.com,
	sunilvl@ventanamicro.com, ardb+tianocore@kernel.org,
	lixianglai@loongson.cn, Tuan Phan <tphan@ventanamicro.com>
Subject: [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library
Date: Mon, 21 Apr 2025 09:58:17 -0700	[thread overview]
Message-ID: <20250421165819.18451-2-tphan@ventanamicro.com> (raw)
In-Reply-To: <20250421165819.18451-1-tphan@ventanamicro.com>

This patch refactors low level NOR flash functions into a dedicated library
to enable reuse, particularly for supporting the firmware upgrade feature.

Signed-off-by: Tuan Phan <tphan@ventanamicro.com>
---
 .../Include/Library/VirtNorFlashDeviceLib.h   | 201 +++++++++
 .../VirtNorFlashDeviceLib.c}                  | 411 ++++++++++++------
 .../VirtNorFlashDeviceLib.inf                 |  30 ++
 OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc   |   5 +-
 OvmfPkg/OvmfPkg.dec                           |   4 +
 OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc           |   5 +-
 OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h        | 345 ---------------
 OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.c     | 180 ++------
 OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h     | 156 +++++++
 OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf   |   3 +-
 OvmfPkg/VirtNorFlashDxe/VirtNorFlashFvb.c     |  53 ++-
 11 files changed, 749 insertions(+), 644 deletions(-)
 create mode 100644 OvmfPkg/Include/Library/VirtNorFlashDeviceLib.h
 rename OvmfPkg/{VirtNorFlashDxe/VirtNorFlash.c => Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c} (63%)
 create mode 100644 OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
 delete mode 100644 OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h
 create mode 100644 OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h

diff --git a/OvmfPkg/Include/Library/VirtNorFlashDeviceLib.h b/OvmfPkg/Include/Library/VirtNorFlashDeviceLib.h
new file mode 100644
index 000000000000..45f4bf628097
--- /dev/null
+++ b/OvmfPkg/Include/Library/VirtNorFlashDeviceLib.h
@@ -0,0 +1,201 @@
+/** @file  VirtNorFlashDeviceLib.h
+
+  Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VIRT_NOR_FLASH_DEVICE_LIB__
+#define __VIRT_NOR_FLASH_DEVICE_LIB__
+
+#include <Base.h>
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiLib.h>
+
+#define NOR_FLASH_ERASE_RETRY  10
+
+// Device access macros
+// These are necessary because we use 2 x 16bit parts to make up 32bit data
+
+#define HIGH_16_BITS  0xFFFF0000
+#define LOW_16_BITS   0x0000FFFF
+#define LOW_8_BITS    0x000000FF
+
+#define FOLD_32BIT_INTO_16BIT(value)  ( ( value >> 16 ) | ( value & LOW_16_BITS ) )
+
+#define GET_LOW_BYTE(value)   ( value & LOW_8_BITS )
+#define GET_HIGH_BYTE(value)  ( GET_LOW_BYTE( value >> 16 ) )
+
+// Each command must be sent simultaneously to both chips,
+// i.e. at the lower 16 bits AND at the higher 16 bits
+#define CREATE_NOR_ADDRESS(BaseAddr, OffsetAddr)       ((BaseAddr) + ((OffsetAddr) << 2))
+#define CREATE_DUAL_CMD(Cmd)                           ( ( Cmd << 16) | ( Cmd & LOW_16_BITS) )
+#define SEND_NOR_COMMAND(BaseAddr, Offset, Cmd)        MmioWrite32 (CREATE_NOR_ADDRESS(BaseAddr,Offset), CREATE_DUAL_CMD(Cmd))
+#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize)  ( BaseAddr + (UINTN)((Lba) * LbaSize) )
+
+// Status Register Bits
+#define P30_SR_BIT_WRITE            (BIT7 << 16 | BIT7)
+#define P30_SR_BIT_ERASE_SUSPEND    (BIT6 << 16 | BIT6)
+#define P30_SR_BIT_ERASE            (BIT5 << 16 | BIT5)
+#define P30_SR_BIT_PROGRAM          (BIT4 << 16 | BIT4)
+#define P30_SR_BIT_VPP              (BIT3 << 16 | BIT3)
+#define P30_SR_BIT_PROGRAM_SUSPEND  (BIT2 << 16 | BIT2)
+#define P30_SR_BIT_BLOCK_LOCKED     (BIT1 << 16 | BIT1)
+#define P30_SR_BIT_BEFP             (BIT0 << 16 | BIT0)
+
+// Device Commands for Intel StrataFlash(R) Embedded Memory (P30) Family
+
+// On chip buffer size for buffered programming operations
+// There are 2 chips, each chip can buffer up to 32 (16-bit)words, and each word is 2 bytes.
+// Therefore the total size of the buffer is 2 x 32 x 2 = 128 bytes
+#define P30_MAX_BUFFER_SIZE_IN_BYTES  ((UINTN)128)
+#define P30_MAX_BUFFER_SIZE_IN_WORDS  (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINTN)4))
+#define MAX_BUFFERED_PROG_ITERATIONS  10000000
+#define BOUNDARY_OF_32_WORDS          ((UINTN)0x7F)
+
+// CFI Addresses
+#define P30_CFI_ADDR_QUERY_UNIQUE_QRY  0x10
+#define P30_CFI_ADDR_VENDOR_ID         0x13
+
+// CFI Data
+#define CFI_QRY  0x00595251
+
+// READ Commands
+#define P30_CMD_READ_DEVICE_ID         0x0090
+#define P30_CMD_READ_STATUS_REGISTER   0x0070
+#define P30_CMD_CLEAR_STATUS_REGISTER  0x0050
+#define P30_CMD_READ_ARRAY             0x00FF
+#define P30_CMD_READ_CFI_QUERY         0x0098
+
+// WRITE Commands
+#define P30_CMD_WORD_PROGRAM_SETUP            0x0040
+#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP  0x0010
+#define P30_CMD_BUFFERED_PROGRAM_SETUP        0x00E8
+#define P30_CMD_BUFFERED_PROGRAM_CONFIRM      0x00D0
+#define P30_CMD_BEFP_SETUP                    0x0080
+#define P30_CMD_BEFP_CONFIRM                  0x00D0
+
+// ERASE Commands
+#define P30_CMD_BLOCK_ERASE_SETUP    0x0020
+#define P30_CMD_BLOCK_ERASE_CONFIRM  0x00D0
+
+// SUSPEND Commands
+#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND  0x00B0
+#define P30_CMD_SUSPEND_RESUME            0x00D0
+
+// BLOCK LOCKING / UNLOCKING Commands
+#define P30_CMD_LOCK_BLOCK_SETUP  0x0060
+#define P30_CMD_LOCK_BLOCK        0x0001
+#define P30_CMD_UNLOCK_BLOCK      0x00D0
+#define P30_CMD_LOCK_DOWN_BLOCK   0x002F
+
+// PROTECTION Commands
+#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP  0x00C0
+
+// CONFIGURATION Commands
+#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP  0x0060
+#define P30_CMD_READ_CONFIGURATION_REGISTER        0x0003
+
+EFI_STATUS
+NorFlashWriteBuffer (
+  IN  UINTN   DeviceBaseAddress,
+  IN  UINTN   TargetAddress,
+  IN  UINTN   BufferSizeInBytes,
+  IN  UINT32  *Buffer
+  );
+
+EFI_STATUS
+NorFlashWriteSingleBlock (
+  IN  UINTN      DeviceBaseAddress,
+  IN  UINTN      RegionBaseAddress,
+  IN  EFI_LBA    Lba,
+  IN  UINT32     LastBlock,
+  IN  UINT32     BlockSize,
+  IN  UINTN      Size,
+  IN  UINTN      Offset,
+  IN OUT  UINTN  *NumBytes,
+  IN  UINT8      *Buffer,
+  IN  VOID       *ShadowBuffer
+  );
+
+EFI_STATUS
+NorFlashWriteBlocks (
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  EFI_LBA  LastBlock,
+  IN  UINT32   BlockSize,
+  IN  UINTN    BufferSizeInBytes,
+  IN  VOID     *Buffer
+  );
+
+EFI_STATUS
+NorFlashReadBlocks (
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  EFI_LBA  LastBlock,
+  IN  UINT32   BlockSize,
+  IN  UINTN    BufferSizeInBytes,
+  OUT  VOID    *Buffer
+  );
+
+EFI_STATUS
+NorFlashRead (
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  UINT32   BlockSize,
+  IN  UINTN    Size,
+  IN  UINTN    Offset,
+  IN  UINTN    BufferSizeInBytes,
+  OUT  VOID    *Buffer
+  );
+
+EFI_STATUS
+NorFlashEraseSingleBlock (
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
+  );
+
+EFI_STATUS
+NorFlashUnlockSingleBlockIfNecessary (
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
+  );
+
+EFI_STATUS
+NorFlashWriteSingleWord (
+  IN  UINTN   DeviceBaseAddress,
+  IN  UINTN   WordAddress,
+  IN  UINT32  WriteData
+  );
+
+EFI_STATUS
+NorFlashWriteFullBlock (
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  UINT32   *DataBuffer,
+  IN  UINT32   BlockSizeInWords
+  );
+
+EFI_STATUS
+NorFlashUnlockAndEraseSingleBlock (
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
+  );
+
+EFI_STATUS
+NorFlashReset (
+  IN  UINTN  DeviceBaseAddress
+  );
+
+#endif /* __VIRT_NOR_FLASH_DEVICE_LIB__ */
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlash.c b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c
similarity index 63%
rename from OvmfPkg/VirtNorFlashDxe/VirtNorFlash.c
rename to OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c
index e6aaed27ceba..604ac4df3f0b 100644
--- a/OvmfPkg/VirtNorFlashDxe/VirtNorFlash.c
+++ b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.c
@@ -8,31 +8,25 @@
 **/
 
 #include <Library/BaseMemoryLib.h>
-
-#include "VirtNorFlash.h"
-
-//
-// Global variable declarations
-//
-extern NOR_FLASH_INSTANCE  **mNorFlashInstances;
-extern UINT32              mNorFlashDeviceCount;
+#include <Library/IoLib.h>
+#include <Library/VirtNorFlashDeviceLib.h>
 
 UINT32
 NorFlashReadStatusRegister (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               SR_Address
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  SR_Address
   )
 {
   // Prepare to read the status register
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
-  return MmioRead32 (Instance->DeviceBaseAddress);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_STATUS_REGISTER);
+  return MmioRead32 (DeviceBaseAddress);
 }
 
 STATIC
 BOOLEAN
 NorFlashBlockIsLocked (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
   )
 {
   UINT32  LockStatus;
@@ -56,8 +50,8 @@ NorFlashBlockIsLocked (
 STATIC
 EFI_STATUS
 NorFlashUnlockSingleBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
   )
 {
   UINT32  LockStatus;
@@ -73,7 +67,7 @@ NorFlashUnlockSingleBlock (
 
   // Wait until the status register gives us the all clear
   do {
-    LockStatus = NorFlashReadStatusRegister (Instance, BlockAddress);
+    LockStatus = NorFlashReadStatusRegister (DeviceBaseAddress, BlockAddress);
   } while ((LockStatus & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
 
   // Put device back into Read Array mode
@@ -86,16 +80,16 @@ NorFlashUnlockSingleBlock (
 
 EFI_STATUS
 NorFlashUnlockSingleBlockIfNecessary (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
   )
 {
   EFI_STATUS  Status;
 
   Status = EFI_SUCCESS;
 
-  if (NorFlashBlockIsLocked (Instance, BlockAddress)) {
-    Status = NorFlashUnlockSingleBlock (Instance, BlockAddress);
+  if (NorFlashBlockIsLocked (DeviceBaseAddress, BlockAddress)) {
+    Status = NorFlashUnlockSingleBlock (DeviceBaseAddress, BlockAddress);
   }
 
   return Status;
@@ -106,8 +100,8 @@ NorFlashUnlockSingleBlockIfNecessary (
  **/
 EFI_STATUS
 NorFlashEraseSingleBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
   )
 {
   EFI_STATUS  Status;
@@ -121,7 +115,7 @@ NorFlashEraseSingleBlock (
 
   // Wait until the status register gives us the all clear
   do {
-    StatusRegister = NorFlashReadStatusRegister (Instance, BlockAddress);
+    StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, BlockAddress);
   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
 
   if (StatusRegister & P30_SR_BIT_VPP) {
@@ -147,20 +141,20 @@ NorFlashEraseSingleBlock (
 
   if (EFI_ERROR (Status)) {
     // Clear the Status Register
-    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+    SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
   }
 
   // Put device back into Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   return Status;
 }
 
 EFI_STATUS
 NorFlashWriteSingleWord (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               WordAddress,
-  IN UINT32              WriteData
+  IN  UINTN   DeviceBaseAddress,
+  IN  UINTN   WordAddress,
+  IN  UINT32  WriteData
   )
 {
   EFI_STATUS  Status;
@@ -177,7 +171,7 @@ NorFlashWriteSingleWord (
   // Wait for the write to complete and then check for any errors; i.e. check the Status Register
   do {
     // Prepare to read the status register
-    StatusRegister = NorFlashReadStatusRegister (Instance, WordAddress);
+    StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, WordAddress);
     // The chip is busy while the WRITE bit is not asserted
   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
 
@@ -202,7 +196,7 @@ NorFlashWriteSingleWord (
 
   if (!EFI_ERROR (Status)) {
     // Clear the Status Register
-    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+    SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
   }
 
   return Status;
@@ -225,10 +219,10 @@ NorFlashWriteSingleWord (
  */
 EFI_STATUS
 NorFlashWriteBuffer (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               TargetAddress,
-  IN UINTN               BufferSizeInBytes,
-  IN UINT32              *Buffer
+  IN  UINTN   DeviceBaseAddress,
+  IN  UINTN   TargetAddress,
+  IN  UINTN   BufferSizeInBytes,
+  IN  UINT32  *Buffer
   )
 {
   EFI_STATUS       Status;
@@ -299,11 +293,11 @@ NorFlashWriteBuffer (
   }
 
   // Issue the Buffered Program Confirm command, to start the programming operation
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_BUFFERED_PROGRAM_CONFIRM);
 
   // Wait for the write to complete and then check for any errors; i.e. check the Status Register
   do {
-    StatusRegister = NorFlashReadStatusRegister (Instance, TargetAddress);
+    StatusRegister = NorFlashReadStatusRegister (DeviceBaseAddress, TargetAddress);
     // The chip is busy while the WRITE bit is not asserted
   } while ((StatusRegister & P30_SR_BIT_WRITE) != P30_SR_BIT_WRITE);
 
@@ -330,7 +324,135 @@ NorFlashWriteBuffer (
 
   if (!EFI_ERROR (Status)) {
     // Clear the Status Register
-    SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+    SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_CLEAR_STATUS_REGISTER);
+  }
+
+  return Status;
+}
+
+/**
+ * This function unlock and erase an entire NOR Flash block.
+ **/
+EFI_STATUS
+NorFlashUnlockAndEraseSingleBlock (
+  IN  UINTN  DeviceBaseAddress,
+  IN  UINTN  BlockAddress
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Index;
+
+  Index = 0;
+  // The block erase might fail a first time (SW bug ?). Retry it ...
+  do {
+    // Unlock the block if we have to
+    Status = NorFlashUnlockSingleBlockIfNecessary (DeviceBaseAddress, BlockAddress);
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    Status = NorFlashEraseSingleBlock (DeviceBaseAddress, BlockAddress);
+    Index++;
+  } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
+
+  if (Index == NOR_FLASH_ERASE_RETRY) {
+    DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));
+  }
+
+  return Status;
+}
+
+EFI_STATUS
+NorFlashWriteFullBlock (
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  UINT32   *DataBuffer,
+  IN  UINT32   BlockSizeInWords
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       WordAddress;
+  UINT32      WordIndex;
+  UINTN       BufferIndex;
+  UINTN       BlockAddress;
+  UINTN       BuffersInBlock;
+  UINTN       RemainingWords;
+  UINTN       Cnt;
+
+  Status = EFI_SUCCESS;
+
+  // Get the physical address of the block
+  BlockAddress = GET_NOR_BLOCK_ADDRESS (RegionBaseAddress, Lba, BlockSizeInWords * 4);
+
+  // Start writing from the first address at the start of the block
+  WordAddress = BlockAddress;
+  Status      = NorFlashUnlockAndEraseSingleBlock (DeviceBaseAddress, BlockAddress);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
+    goto EXIT;
+  }
+
+  // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
+
+  // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
+  if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
+    // First, break the entire block into buffer-sized chunks.
+    BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
+
+    // Then feed each buffer chunk to the NOR Flash
+    // If a buffer does not contain any data, don't write it.
+    for (BufferIndex = 0;
+         BufferIndex < BuffersInBlock;
+         BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
+         )
+    {
+      // Check the buffer to see if it contains any data (not set all 1s).
+      for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
+        if (~DataBuffer[Cnt] != 0 ) {
+          // Some data found, write the buffer.
+          Status = NorFlashWriteBuffer (
+                     DeviceBaseAddress,
+                     WordAddress,
+                     P30_MAX_BUFFER_SIZE_IN_BYTES,
+                     DataBuffer
+                     );
+          if (EFI_ERROR (Status)) {
+            goto EXIT;
+          }
+
+          break;
+        }
+      }
+    }
+
+    // Finally, finish off any remaining words that are less than the maximum size of the buffer
+    RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
+
+    if (RemainingWords != 0) {
+      Status = NorFlashWriteBuffer (DeviceBaseAddress, WordAddress, (RemainingWords * 4), DataBuffer);
+      if (EFI_ERROR (Status)) {
+        goto EXIT;
+      }
+    }
+  } else {
+    // For now, use the single word programming algorithm
+    // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
+    // i.e. which ends in the range 0x......01 - 0x......7F.
+    for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
+      Status = NorFlashWriteSingleWord (DeviceBaseAddress, WordAddress, *DataBuffer);
+      if (EFI_ERROR (Status)) {
+        goto EXIT;
+      }
+    }
+  }
+
+EXIT:
+  // Put device back into Read Array mode
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
   }
 
   return Status;
@@ -338,10 +460,13 @@ NorFlashWriteBuffer (
 
 EFI_STATUS
 NorFlashWriteBlocks (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINTN               BufferSizeInBytes,
-  IN VOID                *Buffer
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  EFI_LBA  LastBlock,
+  IN  UINT32   BlockSize,
+  IN  UINTN    BufferSizeInBytes,
+  IN  VOID     *Buffer
   )
 {
   UINT32      *pWriteBuffer;
@@ -365,22 +490,22 @@ NorFlashWriteBlocks (
   }
 
   // The size of the buffer must be a multiple of the block size
-  DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", Instance->BlockSize));
-  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
+  DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: BlockSize in bytes =0x%x\n", BlockSize));
+  if ((BufferSizeInBytes % BlockSize) != 0) {
     return EFI_BAD_BUFFER_SIZE;
   }
 
   // All blocks must be within the device
-  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
+  NumBlocks = ((UINT32)BufferSizeInBytes) / BlockSize;
 
-  DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, Instance->LastBlock, Lba));
+  DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld.\n", NumBlocks, LastBlock, Lba));
 
-  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
+  if ((Lba + NumBlocks) > (LastBlock + 1)) {
     DEBUG ((DEBUG_ERROR, "NorFlashWriteBlocks: ERROR - Write will exceed last block.\n"));
     return EFI_INVALID_PARAMETER;
   }
 
-  BlockSizeInWords = Instance->BlockSize / 4;
+  BlockSizeInWords = BlockSize / 4;
 
   // Because the target *Buffer is a pointer to VOID, we must put all the data into a pointer
   // to a proper data type, so use *ReadBuffer
@@ -390,7 +515,13 @@ NorFlashWriteBlocks (
   for (BlockCount = 0; BlockCount < NumBlocks; BlockCount++, CurrentBlock++, pWriteBuffer = pWriteBuffer + BlockSizeInWords) {
     DEBUG ((DEBUG_BLKIO, "NorFlashWriteBlocks: Writing block #%d\n", (UINTN)CurrentBlock));
 
-    Status = NorFlashWriteFullBlock (Instance, CurrentBlock, pWriteBuffer, BlockSizeInWords);
+    Status = NorFlashWriteFullBlock (
+               DeviceBaseAddress,
+               RegionBaseAddress,
+               CurrentBlock,
+               pWriteBuffer,
+               BlockSizeInWords
+               );
 
     if (EFI_ERROR (Status)) {
       break;
@@ -403,10 +534,13 @@ NorFlashWriteBlocks (
 
 EFI_STATUS
 NorFlashReadBlocks (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINTN               BufferSizeInBytes,
-  OUT VOID               *Buffer
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  EFI_LBA  LastBlock,
+  IN  UINT32   BlockSize,
+  IN  UINTN    BufferSizeInBytes,
+  OUT  VOID    *Buffer
   )
 {
   UINT32  NumBlocks;
@@ -416,8 +550,8 @@ NorFlashReadBlocks (
     DEBUG_BLKIO,
     "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",
     BufferSizeInBytes,
-    Instance->BlockSize,
-    Instance->LastBlock,
+    BlockSize,
+    LastBlock,
     Lba
     ));
 
@@ -432,27 +566,27 @@ NorFlashReadBlocks (
   }
 
   // The size of the buffer must be a multiple of the block size
-  if ((BufferSizeInBytes % Instance->BlockSize) != 0) {
+  if ((BufferSizeInBytes % BlockSize) != 0) {
     return EFI_BAD_BUFFER_SIZE;
   }
 
   // All blocks must be within the device
-  NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->BlockSize;
+  NumBlocks = ((UINT32)BufferSizeInBytes) / BlockSize;
 
-  if ((Lba + NumBlocks) > (Instance->LastBlock + 1)) {
+  if ((Lba + NumBlocks) > (LastBlock + 1)) {
     DEBUG ((DEBUG_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));
     return EFI_INVALID_PARAMETER;
   }
 
   // Get the address to start reading from
   StartAddress = GET_NOR_BLOCK_ADDRESS (
-                   Instance->RegionBaseAddress,
+                   RegionBaseAddress,
                    Lba,
-                   Instance->BlockSize
+                   BlockSize
                    );
 
   // Put the device into Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   // Readout the data
   CopyMem (Buffer, (VOID *)StartAddress, BufferSizeInBytes);
@@ -462,11 +596,14 @@ NorFlashReadBlocks (
 
 EFI_STATUS
 NorFlashRead (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINTN               Offset,
-  IN UINTN               BufferSizeInBytes,
-  OUT VOID               *Buffer
+  IN  UINTN    DeviceBaseAddress,
+  IN  UINTN    RegionBaseAddress,
+  IN  EFI_LBA  Lba,
+  IN  UINT32   BlockSize,
+  IN  UINTN    Size,
+  IN  UINTN    Offset,
+  IN  UINTN    BufferSizeInBytes,
+  OUT  VOID    *Buffer
   )
 {
   UINTN  StartAddress;
@@ -481,20 +618,20 @@ NorFlashRead (
     return EFI_SUCCESS;
   }
 
-  if (((Lba * Instance->BlockSize) + Offset + BufferSizeInBytes) > Instance->Size) {
+  if (((Lba * BlockSize) + Offset + BufferSizeInBytes) > Size) {
     DEBUG ((DEBUG_ERROR, "NorFlashRead: ERROR - Read will exceed device size.\n"));
     return EFI_INVALID_PARAMETER;
   }
 
   // Get the address to start reading from
   StartAddress = GET_NOR_BLOCK_ADDRESS (
-                   Instance->RegionBaseAddress,
+                   RegionBaseAddress,
                    Lba,
-                   Instance->BlockSize
+                   BlockSize
                    );
 
   // Put the device into Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   // Readout the data
   CopyMem (Buffer, (VOID *)(StartAddress + Offset), BufferSizeInBytes);
@@ -505,27 +642,47 @@ NorFlashRead (
 STATIC
 EFI_STATUS
 NorFlashWriteSingleBlockWithErase (
-  IN        NOR_FLASH_INSTANCE  *Instance,
-  IN        EFI_LBA             Lba,
-  IN        UINTN               Offset,
-  IN OUT    UINTN               *NumBytes,
-  IN        UINT8               *Buffer
+  IN  UINTN      DeviceBaseAddress,
+  IN  UINTN      RegionBaseAddress,
+  IN  EFI_LBA    Lba,
+  IN  UINT32     LastBlock,
+  IN  UINT32     BlockSize,
+  IN  UINTN      Offset,
+  IN OUT  UINTN  *NumBytes,
+  IN  UINT8      *Buffer,
+  IN  VOID       *ShadowBuffer
   )
 {
   EFI_STATUS  Status;
 
   // Read NOR Flash data into shadow buffer
-  Status = NorFlashReadBlocks (Instance, Lba, Instance->BlockSize, Instance->ShadowBuffer);
+  Status = NorFlashReadBlocks (
+             DeviceBaseAddress,
+             RegionBaseAddress,
+             Lba,
+             LastBlock,
+             BlockSize,
+             BlockSize,
+             ShadowBuffer
+             );
   if (EFI_ERROR (Status)) {
     // Return one of the pre-approved error statuses
     return EFI_DEVICE_ERROR;
   }
 
   // Put the data at the appropriate location inside the buffer area
-  CopyMem ((VOID *)((UINTN)Instance->ShadowBuffer + Offset), Buffer, *NumBytes);
+  CopyMem ((VOID *)((UINTN)ShadowBuffer + Offset), Buffer, *NumBytes);
 
   // Write the modified buffer back to the NorFlash
-  Status = NorFlashWriteBlocks (Instance, Lba, Instance->BlockSize, Instance->ShadowBuffer);
+  Status = NorFlashWriteBlocks (
+             DeviceBaseAddress,
+             RegionBaseAddress,
+             Lba,
+             LastBlock,
+             BlockSize,
+             BlockSize,
+             ShadowBuffer
+             );
   if (EFI_ERROR (Status)) {
     // Return one of the pre-approved error statuses
     return EFI_DEVICE_ERROR;
@@ -540,16 +697,20 @@ NorFlashWriteSingleBlockWithErase (
 */
 EFI_STATUS
 NorFlashWriteSingleBlock (
-  IN        NOR_FLASH_INSTANCE  *Instance,
-  IN        EFI_LBA             Lba,
-  IN        UINTN               Offset,
-  IN OUT    UINTN               *NumBytes,
-  IN        UINT8               *Buffer
+  IN  UINTN      DeviceBaseAddress,
+  IN  UINTN      RegionBaseAddress,
+  IN  EFI_LBA    Lba,
+  IN  UINT32     LastBlock,
+  IN  UINT32     BlockSize,
+  IN  UINTN      Size,
+  IN  UINTN      Offset,
+  IN OUT  UINTN  *NumBytes,
+  IN  UINT8      *Buffer,
+  IN  VOID       *ShadowBuffer
   )
 {
   EFI_STATUS  Status;
   UINTN       CurOffset;
-  UINTN       BlockSize;
   UINTN       BlockAddress;
   UINT8       *OrigData;
   UINTN       Start, End;
@@ -558,14 +719,11 @@ NorFlashWriteSingleBlock (
   DEBUG ((DEBUG_BLKIO, "NorFlashWriteSingleBlock(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Lba, Offset, *NumBytes, Buffer));
 
   // Check we did get some memory. Buffer is BlockSize.
-  if (Instance->ShadowBuffer == NULL) {
+  if (ShadowBuffer == NULL) {
     DEBUG ((DEBUG_ERROR, "FvbWrite: ERROR - Buffer not ready\n"));
     return EFI_DEVICE_ERROR;
   }
 
-  // Cache the block size to avoid de-referencing pointers all the time
-  BlockSize = Instance->BlockSize;
-
   // The write must not span block boundaries.
   // We need to check each variable individually because adding two large values together overflows.
   if ((Offset               >= BlockSize) ||
@@ -620,11 +778,14 @@ NorFlashWriteSingleBlock (
 
     // Read the old version of the data into the shadow buffer
     Status = NorFlashRead (
-               Instance,
+               DeviceBaseAddress,
+               RegionBaseAddress,
                Lba,
+               BlockSize,
+               Size,
                Start,
                End - Start,
-               Instance->ShadowBuffer
+               ShadowBuffer
                );
     if (EFI_ERROR (Status)) {
       return EFI_DEVICE_ERROR;
@@ -632,7 +793,7 @@ NorFlashWriteSingleBlock (
 
     // Make OrigData point to the start of the old version of the data inside
     // the word aligned buffer
-    OrigData = Instance->ShadowBuffer + (Offset & BOUNDARY_OF_32_WORDS);
+    OrigData = ShadowBuffer + (Offset & BOUNDARY_OF_32_WORDS);
 
     // Update the buffer containing the old version of the data with the new
     // contents, while checking whether the old version had any bits cleared
@@ -640,11 +801,15 @@ NorFlashWriteSingleBlock (
     for (CurOffset = 0; CurOffset < *NumBytes; CurOffset++) {
       if (~(UINT32)OrigData[CurOffset] & (UINT32)Buffer[CurOffset]) {
         Status = NorFlashWriteSingleBlockWithErase (
-                   Instance,
+                   DeviceBaseAddress,
+                   RegionBaseAddress,
                    Lba,
+                   LastBlock,
+                   BlockSize,
                    Offset,
                    NumBytes,
-                   Buffer
+                   Buffer,
+                   ShadowBuffer
                    );
         return Status;
       }
@@ -655,10 +820,10 @@ NorFlashWriteSingleBlock (
     //
     // Write the updated buffer to NOR.
     //
-    BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSize);
+    BlockAddress = GET_NOR_BLOCK_ADDRESS (RegionBaseAddress, Lba, BlockSize);
 
     // Unlock the block if we have to
-    Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
+    Status = NorFlashUnlockSingleBlockIfNecessary (DeviceBaseAddress, BlockAddress);
     if (EFI_ERROR (Status)) {
       goto Exit;
     }
@@ -666,10 +831,10 @@ NorFlashWriteSingleBlock (
     Count = (End - Start) / P30_MAX_BUFFER_SIZE_IN_BYTES;
     for (Index = 0; Index < Count; Index++) {
       Status = NorFlashWriteBuffer (
-                 Instance,
+                 DeviceBaseAddress,
                  BlockAddress + Start + Index * P30_MAX_BUFFER_SIZE_IN_BYTES,
                  P30_MAX_BUFFER_SIZE_IN_BYTES,
-                 Instance->ShadowBuffer + Index * P30_MAX_BUFFER_SIZE_IN_BYTES
+                 ShadowBuffer + Index * P30_MAX_BUFFER_SIZE_IN_BYTES
                  );
       if (EFI_ERROR (Status)) {
         goto Exit;
@@ -677,66 +842,32 @@ NorFlashWriteSingleBlock (
     }
   } else {
     Status = NorFlashWriteSingleBlockWithErase (
-               Instance,
+               DeviceBaseAddress,
+               RegionBaseAddress,
                Lba,
+               LastBlock,
+               BlockSize,
                Offset,
                NumBytes,
-               Buffer
+               Buffer,
+               ShadowBuffer
                );
     return Status;
   }
 
 Exit:
   // Put device back into Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
 
   return Status;
 }
 
 EFI_STATUS
 NorFlashReset (
-  IN  NOR_FLASH_INSTANCE  *Instance
+  IN  UINTN  DeviceBaseAddress
   )
 {
   // As there is no specific RESET to perform, ensure that the devices is in the default Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
+  SEND_NOR_COMMAND (DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
   return EFI_SUCCESS;
 }
-
-/**
-  Fixup internal data so that EFI can be call in virtual mode.
-  Call the passed in Child Notify event and convert any pointers in
-  lib to virtual mode.
-
-  @param[in]    Event   The Event that is being processed
-  @param[in]    Context Event Context
-**/
-VOID
-EFIAPI
-NorFlashVirtualNotifyEvent (
-  IN EFI_EVENT  Event,
-  IN VOID       *Context
-  )
-{
-  UINTN  Index;
-
-  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);
-
-    // Convert Fvb
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
-    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);
-
-    if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
-      EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
-    }
-  }
-
-  return;
-}
diff --git a/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
new file mode 100644
index 000000000000..f99c8fb6b33a
--- /dev/null
+++ b/OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
@@ -0,0 +1,30 @@
+#/** @file
+#
+#  Component description file for NorFlashDxe module
+#
+#  Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 1.29
+  BASE_NAME                      = VirtNorFlashDeviceLib
+  FILE_GUID                      = 3f8c8c4b-5b92-4e71-ae73-9f7d2f1e33d4
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = VirtNorFlashDeviceLib
+
+[Sources.common]
+  VirtNorFlashDeviceLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseLib
+  BaseMemoryLib
+  DebugLib
+  IoLib
diff --git a/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
index 89abdf9f779e..27a2d1baf5df 100644
--- a/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
+++ b/OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc
@@ -507,7 +507,10 @@
   #
   # Variable
   #
-  OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
+  OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf {
+    <LibraryClasses>
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
+  }
   MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf {
     <LibraryClasses>
       NULL|EmbeddedPkg/Library/NvVarStoreFormattedLib/NvVarStoreFormattedLib.inf
diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
index 1703f5063711..529983af1923 100644
--- a/OvmfPkg/OvmfPkg.dec
+++ b/OvmfPkg/OvmfPkg.dec
@@ -120,6 +120,10 @@
   #                  transports.
   VirtioMmioDeviceLib|Include/Library/VirtioMmioDeviceLib.h
 
+  ##  @libraryclass  Provides a Device Nor flash interface.
+  #
+  VirtNorFlashDeviceLib|Include/Library/VirtNorFlashDeviceLib.h
+
   ##  @libraryclass  Provides a Nor flash interface.
   #
   VirtNorFlashPlatformLib|Include/Library/VirtNorFlashPlatformLib.h
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
index ca211b3db356..8e864e123f08 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
+++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
@@ -324,7 +324,10 @@
   MdeModulePkg/Universal/HiiDatabaseDxe/HiiDatabaseDxe.inf
 
   UefiCpuPkg/CpuTimerDxeRiscV64/CpuTimerDxeRiscV64.inf
-  OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
+  OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf {
+    <LibraryClasses>
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
+  }
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
 
   #
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h b/OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h
deleted file mode 100644
index 455eafacc2cf..000000000000
--- a/OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/** @file  NorFlash.h
-
-  Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
-
-  SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __VIRT_NOR_FLASH__
-#define __VIRT_NOR_FLASH__
-
-#include <Base.h>
-#include <PiDxe.h>
-
-#include <Guid/EventGroup.h>
-
-#include <Protocol/FirmwareVolumeBlock.h>
-
-#include <Library/DebugLib.h>
-#include <Library/IoLib.h>
-#include <Library/UefiLib.h>
-#include <Library/UefiRuntimeLib.h>
-#include <Library/VirtNorFlashPlatformLib.h>
-
-#define NOR_FLASH_ERASE_RETRY  10
-
-// Device access macros
-// These are necessary because we use 2 x 16bit parts to make up 32bit data
-
-#define HIGH_16_BITS  0xFFFF0000
-#define LOW_16_BITS   0x0000FFFF
-#define LOW_8_BITS    0x000000FF
-
-#define FOLD_32BIT_INTO_16BIT(value)  ( ( value >> 16 ) | ( value & LOW_16_BITS ) )
-
-#define GET_LOW_BYTE(value)   ( value & LOW_8_BITS )
-#define GET_HIGH_BYTE(value)  ( GET_LOW_BYTE( value >> 16 ) )
-
-// Each command must be sent simultaneously to both chips,
-// i.e. at the lower 16 bits AND at the higher 16 bits
-#define CREATE_NOR_ADDRESS(BaseAddr, OffsetAddr)       ((BaseAddr) + ((OffsetAddr) << 2))
-#define CREATE_DUAL_CMD(Cmd)                           ( ( Cmd << 16) | ( Cmd & LOW_16_BITS) )
-#define SEND_NOR_COMMAND(BaseAddr, Offset, Cmd)        MmioWrite32 (CREATE_NOR_ADDRESS(BaseAddr,Offset), CREATE_DUAL_CMD(Cmd))
-#define GET_NOR_BLOCK_ADDRESS(BaseAddr, Lba, LbaSize)  ( BaseAddr + (UINTN)((Lba) * LbaSize) )
-
-// Status Register Bits
-#define P30_SR_BIT_WRITE            (BIT7 << 16 | BIT7)
-#define P30_SR_BIT_ERASE_SUSPEND    (BIT6 << 16 | BIT6)
-#define P30_SR_BIT_ERASE            (BIT5 << 16 | BIT5)
-#define P30_SR_BIT_PROGRAM          (BIT4 << 16 | BIT4)
-#define P30_SR_BIT_VPP              (BIT3 << 16 | BIT3)
-#define P30_SR_BIT_PROGRAM_SUSPEND  (BIT2 << 16 | BIT2)
-#define P30_SR_BIT_BLOCK_LOCKED     (BIT1 << 16 | BIT1)
-#define P30_SR_BIT_BEFP             (BIT0 << 16 | BIT0)
-
-// Device Commands for Intel StrataFlash(R) Embedded Memory (P30) Family
-
-// On chip buffer size for buffered programming operations
-// There are 2 chips, each chip can buffer up to 32 (16-bit)words, and each word is 2 bytes.
-// Therefore the total size of the buffer is 2 x 32 x 2 = 128 bytes
-#define P30_MAX_BUFFER_SIZE_IN_BYTES  ((UINTN)128)
-#define P30_MAX_BUFFER_SIZE_IN_WORDS  (P30_MAX_BUFFER_SIZE_IN_BYTES/((UINTN)4))
-#define MAX_BUFFERED_PROG_ITERATIONS  10000000
-#define BOUNDARY_OF_32_WORDS          ((UINTN)0x7F)
-
-// CFI Addresses
-#define P30_CFI_ADDR_QUERY_UNIQUE_QRY  0x10
-#define P30_CFI_ADDR_VENDOR_ID         0x13
-
-// CFI Data
-#define CFI_QRY  0x00595251
-
-// READ Commands
-#define P30_CMD_READ_DEVICE_ID         0x0090
-#define P30_CMD_READ_STATUS_REGISTER   0x0070
-#define P30_CMD_CLEAR_STATUS_REGISTER  0x0050
-#define P30_CMD_READ_ARRAY             0x00FF
-#define P30_CMD_READ_CFI_QUERY         0x0098
-
-// WRITE Commands
-#define P30_CMD_WORD_PROGRAM_SETUP            0x0040
-#define P30_CMD_ALTERNATE_WORD_PROGRAM_SETUP  0x0010
-#define P30_CMD_BUFFERED_PROGRAM_SETUP        0x00E8
-#define P30_CMD_BUFFERED_PROGRAM_CONFIRM      0x00D0
-#define P30_CMD_BEFP_SETUP                    0x0080
-#define P30_CMD_BEFP_CONFIRM                  0x00D0
-
-// ERASE Commands
-#define P30_CMD_BLOCK_ERASE_SETUP    0x0020
-#define P30_CMD_BLOCK_ERASE_CONFIRM  0x00D0
-
-// SUSPEND Commands
-#define P30_CMD_PROGRAM_OR_ERASE_SUSPEND  0x00B0
-#define P30_CMD_SUSPEND_RESUME            0x00D0
-
-// BLOCK LOCKING / UNLOCKING Commands
-#define P30_CMD_LOCK_BLOCK_SETUP  0x0060
-#define P30_CMD_LOCK_BLOCK        0x0001
-#define P30_CMD_UNLOCK_BLOCK      0x00D0
-#define P30_CMD_LOCK_DOWN_BLOCK   0x002F
-
-// PROTECTION Commands
-#define P30_CMD_PROGRAM_PROTECTION_REGISTER_SETUP  0x00C0
-
-// CONFIGURATION Commands
-#define P30_CMD_READ_CONFIGURATION_REGISTER_SETUP  0x0060
-#define P30_CMD_READ_CONFIGURATION_REGISTER        0x0003
-
-#define NOR_FLASH_SIGNATURE  SIGNATURE_32('n', 'o', 'r', '0')
-#define INSTANCE_FROM_FVB_THIS(a)  CR(a, NOR_FLASH_INSTANCE, FvbProtocol, NOR_FLASH_SIGNATURE)
-
-typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
-
-#pragma pack (1)
-typedef struct {
-  VENDOR_DEVICE_PATH          Vendor;
-  UINT8                       Index;
-  EFI_DEVICE_PATH_PROTOCOL    End;
-} NOR_FLASH_DEVICE_PATH;
-#pragma pack ()
-
-struct _NOR_FLASH_INSTANCE {
-  UINT32                                 Signature;
-  EFI_HANDLE                             Handle;
-
-  UINTN                                  DeviceBaseAddress;
-  UINTN                                  RegionBaseAddress;
-  UINTN                                  Size;
-  EFI_LBA                                StartLba;
-  EFI_LBA                                LastBlock;
-  UINT32                                 BlockSize;
-
-  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;
-  VOID                                   *ShadowBuffer;
-
-  NOR_FLASH_DEVICE_PATH                  DevicePath;
-};
-
-EFI_STATUS
-NorFlashReadCfiData (
-  IN  UINTN   DeviceBaseAddress,
-  IN  UINTN   CFI_Offset,
-  IN  UINT32  NumberOfBytes,
-  OUT UINT32  *Data
-  );
-
-EFI_STATUS
-NorFlashWriteBuffer (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               TargetAddress,
-  IN UINTN               BufferSizeInBytes,
-  IN UINT32              *Buffer
-  );
-
-//
-// NorFlashFvbDxe.c
-//
-
-EFI_STATUS
-EFIAPI
-FvbGetAttributes (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
-  );
-
-EFI_STATUS
-EFIAPI
-FvbSetAttributes (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
-  );
-
-EFI_STATUS
-EFIAPI
-FvbGetPhysicalAddress (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  OUT       EFI_PHYSICAL_ADDRESS                 *Address
-  );
-
-EFI_STATUS
-EFIAPI
-FvbGetBlockSize (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  IN        EFI_LBA                              Lba,
-  OUT       UINTN                                *BlockSize,
-  OUT       UINTN                                *NumberOfBlocks
-  );
-
-EFI_STATUS
-EFIAPI
-FvbRead (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  IN        EFI_LBA                              Lba,
-  IN        UINTN                                Offset,
-  IN OUT    UINTN                                *NumBytes,
-  IN OUT    UINT8                                *Buffer
-  );
-
-EFI_STATUS
-EFIAPI
-FvbWrite (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  IN        EFI_LBA                              Lba,
-  IN        UINTN                                Offset,
-  IN OUT    UINTN                                *NumBytes,
-  IN        UINT8                                *Buffer
-  );
-
-EFI_STATUS
-EFIAPI
-FvbEraseBlocks (
-  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
-  ...
-  );
-
-EFI_STATUS
-ValidateFvHeader (
-  IN  NOR_FLASH_INSTANCE  *Instance
-  );
-
-EFI_STATUS
-InitializeFvAndVariableStoreHeaders (
-  IN NOR_FLASH_INSTANCE  *Instance
-  );
-
-VOID
-EFIAPI
-FvbVirtualNotifyEvent (
-  IN EFI_EVENT  Event,
-  IN VOID       *Context
-  );
-
-//
-// NorFlashDxe.c
-//
-
-EFI_STATUS
-NorFlashWriteFullBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINT32              *DataBuffer,
-  IN UINT32              BlockSizeInWords
-  );
-
-EFI_STATUS
-NorFlashUnlockAndEraseSingleBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
-  );
-
-EFI_STATUS
-NorFlashCreateInstance (
-  IN UINTN                NorFlashDeviceBase,
-  IN UINTN                NorFlashRegionBase,
-  IN UINTN                NorFlashSize,
-  IN UINT32               Index,
-  IN UINT32               BlockSize,
-  IN BOOLEAN              SupportFvb,
-  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
-  );
-
-EFI_STATUS
-EFIAPI
-NorFlashFvbInitialize (
-  IN NOR_FLASH_INSTANCE  *Instance
-  );
-
-//
-// NorFlash.c
-//
-EFI_STATUS
-NorFlashWriteSingleBlock (
-  IN        NOR_FLASH_INSTANCE  *Instance,
-  IN        EFI_LBA             Lba,
-  IN        UINTN               Offset,
-  IN OUT    UINTN               *NumBytes,
-  IN        UINT8               *Buffer
-  );
-
-EFI_STATUS
-NorFlashWriteBlocks (
-  IN  NOR_FLASH_INSTANCE  *Instance,
-  IN  EFI_LBA             Lba,
-  IN  UINTN               BufferSizeInBytes,
-  IN  VOID                *Buffer
-  );
-
-EFI_STATUS
-NorFlashReadBlocks (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINTN               BufferSizeInBytes,
-  OUT VOID               *Buffer
-  );
-
-EFI_STATUS
-NorFlashRead (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINTN               Offset,
-  IN UINTN               BufferSizeInBytes,
-  OUT VOID               *Buffer
-  );
-
-EFI_STATUS
-NorFlashWrite (
-  IN        NOR_FLASH_INSTANCE  *Instance,
-  IN        EFI_LBA             Lba,
-  IN        UINTN               Offset,
-  IN OUT    UINTN               *NumBytes,
-  IN        UINT8               *Buffer
-  );
-
-EFI_STATUS
-NorFlashReset (
-  IN  NOR_FLASH_INSTANCE  *Instance
-  );
-
-EFI_STATUS
-NorFlashEraseSingleBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
-  );
-
-EFI_STATUS
-NorFlashUnlockSingleBlockIfNecessary (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
-  );
-
-EFI_STATUS
-NorFlashWriteSingleWord (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               WordAddress,
-  IN UINT32              WriteData
-  );
-
-VOID
-EFIAPI
-NorFlashVirtualNotifyEvent (
-  IN EFI_EVENT  Event,
-  IN VOID       *Context
-  );
-
-#endif /* __VIRT_NOR_FLASH__ */
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.c b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.c
index 6b9ef261335e..1b46d2690108 100644
--- a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.c
+++ b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.c
@@ -1,4 +1,4 @@
-/** @file  NorFlashDxe.c
+/** @file  VirtNorFlashDxe.c
 
   Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
 
@@ -14,7 +14,7 @@
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiLib.h>
 
-#include "VirtNorFlash.h"
+#include "VirtNorFlashDxe.h"
 
 STATIC EFI_EVENT  mNorFlashVirtualAddrChangeEvent;
 
@@ -138,161 +138,41 @@ NorFlashCreateInstance (
 }
 
 /**
- * This function unlock and erase an entire NOR Flash block.
- **/
-EFI_STATUS
-NorFlashUnlockAndEraseSingleBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN UINTN               BlockAddress
-  )
-{
-  EFI_STATUS  Status;
-  UINTN       Index;
-  EFI_TPL     OriginalTPL;
-
-  if (!EfiAtRuntime ()) {
-    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
-    OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
-  } else {
-    // This initialization is only to prevent the compiler to complain about the
-    // use of uninitialized variables
-    OriginalTPL = TPL_HIGH_LEVEL;
-  }
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in
+  lib to virtual mode.
 
-  Index = 0;
-  // The block erase might fail a first time (SW bug ?). Retry it ...
-  do {
-    // Unlock the block if we have to
-    Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);
-    if (EFI_ERROR (Status)) {
-      break;
-    }
-
-    Status = NorFlashEraseSingleBlock (Instance, BlockAddress);
-    Index++;
-  } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
-
-  if (Index == NOR_FLASH_ERASE_RETRY) {
-    DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));
-  }
-
-  if (!EfiAtRuntime ()) {
-    // Interruptions can resume.
-    gBS->RestoreTPL (OriginalTPL);
-  }
-
-  return Status;
-}
-
-EFI_STATUS
-NorFlashWriteFullBlock (
-  IN NOR_FLASH_INSTANCE  *Instance,
-  IN EFI_LBA             Lba,
-  IN UINT32              *DataBuffer,
-  IN UINT32              BlockSizeInWords
+  @param[in]    Event   The Event that is being processed
+  @param[in]    Context Event Context
+**/
+VOID
+EFIAPI
+NorFlashVirtualNotifyEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
   )
 {
-  EFI_STATUS  Status;
-  UINTN       WordAddress;
-  UINT32      WordIndex;
-  UINTN       BufferIndex;
-  UINTN       BlockAddress;
-  UINTN       BuffersInBlock;
-  UINTN       RemainingWords;
-  EFI_TPL     OriginalTPL;
-  UINTN       Cnt;
-
-  Status = EFI_SUCCESS;
-
-  // Get the physical address of the block
-  BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);
-
-  // Start writing from the first address at the start of the block
-  WordAddress = BlockAddress;
-
-  if (!EfiAtRuntime ()) {
-    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
-    OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
-  } else {
-    // This initialization is only to prevent the compiler to complain about the
-    // use of uninitialized variables
-    OriginalTPL = TPL_HIGH_LEVEL;
-  }
-
-  Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
-  if (EFI_ERROR (Status)) {
-    DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));
-    goto EXIT;
-  }
-
-  // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.
-
-  // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero
-  if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {
-    // First, break the entire block into buffer-sized chunks.
-    BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;
-
-    // Then feed each buffer chunk to the NOR Flash
-    // If a buffer does not contain any data, don't write it.
-    for (BufferIndex = 0;
-         BufferIndex < BuffersInBlock;
-         BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS
-         )
-    {
-      // Check the buffer to see if it contains any data (not set all 1s).
-      for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {
-        if (~DataBuffer[Cnt] != 0 ) {
-          // Some data found, write the buffer.
-          Status = NorFlashWriteBuffer (
-                     Instance,
-                     WordAddress,
-                     P30_MAX_BUFFER_SIZE_IN_BYTES,
-                     DataBuffer
-                     );
-          if (EFI_ERROR (Status)) {
-            goto EXIT;
-          }
-
-          break;
-        }
-      }
-    }
-
-    // Finally, finish off any remaining words that are less than the maximum size of the buffer
-    RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;
+  UINTN  Index;
 
-    if (RemainingWords != 0) {
-      Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);
-      if (EFI_ERROR (Status)) {
-        goto EXIT;
-      }
-    }
-  } else {
-    // For now, use the single word programming algorithm
-    // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,
-    // i.e. which ends in the range 0x......01 - 0x......7F.
-    for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {
-      Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);
-      if (EFI_ERROR (Status)) {
-        goto EXIT;
-      }
+  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->DeviceBaseAddress);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->RegionBaseAddress);
+
+    // Convert Fvb
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Read);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);
+    EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->FvbProtocol.Write);
+
+    if (mNorFlashInstances[Index]->ShadowBuffer != NULL) {
+      EfiConvertPointer (0x0, (VOID **)&mNorFlashInstances[Index]->ShadowBuffer);
     }
   }
 
-EXIT:
-  // Put device back into Read Array mode
-  SEND_NOR_COMMAND (Instance->DeviceBaseAddress, 0, P30_CMD_READ_ARRAY);
-
-  if (!EfiAtRuntime ()) {
-    // Interruptions can resume.
-    gBS->RestoreTPL (OriginalTPL);
-  }
-
-  if (EFI_ERROR (Status)) {
-    DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));
-  }
-
-  return Status;
+  return;
 }
 
 EFI_STATUS
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h
new file mode 100644
index 000000000000..3c7f5094153f
--- /dev/null
+++ b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h
@@ -0,0 +1,156 @@
+/** @file  VirtNorFlashDxe.h
+
+  Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>
+  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __VIRT_NOR_FLASH_DXE__
+#define __VIRT_NOR_FLASH_DXE__
+
+#include <Base.h>
+#include <PiDxe.h>
+
+#include <Guid/EventGroup.h>
+
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/VirtNorFlashDeviceLib.h>
+#include <Library/VirtNorFlashPlatformLib.h>
+
+#define NOR_FLASH_SIGNATURE  SIGNATURE_32('n', 'o', 'r', '0')
+#define INSTANCE_FROM_FVB_THIS(a)  CR(a, NOR_FLASH_INSTANCE, FvbProtocol, NOR_FLASH_SIGNATURE)
+
+typedef struct _NOR_FLASH_INSTANCE NOR_FLASH_INSTANCE;
+
+#pragma pack (1)
+typedef struct {
+  VENDOR_DEVICE_PATH          Vendor;
+  UINT8                       Index;
+  EFI_DEVICE_PATH_PROTOCOL    End;
+} NOR_FLASH_DEVICE_PATH;
+#pragma pack ()
+
+struct _NOR_FLASH_INSTANCE {
+  UINT32                                 Signature;
+  EFI_HANDLE                             Handle;
+
+  UINTN                                  DeviceBaseAddress;
+  UINTN                                  RegionBaseAddress;
+  UINTN                                  Size;
+  EFI_LBA                                StartLba;
+  EFI_LBA                                LastBlock;
+  UINT32                                 BlockSize;
+
+  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    FvbProtocol;
+  VOID                                   *ShadowBuffer;
+
+  NOR_FLASH_DEVICE_PATH                  DevicePath;
+};
+
+//
+// NorFlashFvbDxe.c
+//
+
+EFI_STATUS
+EFIAPI
+FvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+FvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+FvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  );
+
+EFI_STATUS
+EFIAPI
+FvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  );
+
+EFI_STATUS
+EFIAPI
+FvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN OUT    UINT8                                *Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+FvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  IN        UINTN                                Offset,
+  IN OUT    UINTN                                *NumBytes,
+  IN        UINT8                                *Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+FvbEraseBlocks (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  ...
+  );
+
+EFI_STATUS
+ValidateFvHeader (
+  IN  NOR_FLASH_INSTANCE  *Instance
+  );
+
+EFI_STATUS
+InitializeFvAndVariableStoreHeaders (
+  IN NOR_FLASH_INSTANCE  *Instance
+  );
+
+VOID
+EFIAPI
+FvbVirtualNotifyEvent (
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  );
+
+//
+// NorFlashDxe.c
+//
+EFI_STATUS
+NorFlashCreateInstance (
+  IN UINTN                NorFlashDeviceBase,
+  IN UINTN                NorFlashRegionBase,
+  IN UINTN                NorFlashSize,
+  IN UINT32               Index,
+  IN UINT32               BlockSize,
+  IN BOOLEAN              SupportFvb,
+  OUT NOR_FLASH_INSTANCE  **NorFlashInstance
+  );
+
+EFI_STATUS
+EFIAPI
+NorFlashFvbInitialize (
+  IN NOR_FLASH_INSTANCE  *Instance
+  );
+
+#endif /* __VIRT_NOT_FLASH_DXE__ */
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
index f549400280a1..6d6d615a6219 100644
--- a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
+++ b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.inf
@@ -17,8 +17,6 @@
   ENTRY_POINT                    = NorFlashInitialise
 
 [Sources.common]
-  VirtNorFlash.c
-  VirtNorFlash.h
   VirtNorFlashDxe.c
   VirtNorFlashFvb.c
 
@@ -39,6 +37,7 @@
   UefiDriverEntryPoint
   UefiLib
   UefiRuntimeLib
+  VirtNorFlashDeviceLib
   VirtNorFlashPlatformLib
 
 [Guids]
diff --git a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashFvb.c b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashFvb.c
index c8b5e0be1379..0d6c9ef01631 100644
--- a/OvmfPkg/VirtNorFlashDxe/VirtNorFlashFvb.c
+++ b/OvmfPkg/VirtNorFlashDxe/VirtNorFlashFvb.c
@@ -19,7 +19,7 @@
 #include <Guid/SystemNvDataGuid.h>
 #include <Guid/VariableFormat.h>
 
-#include "VirtNorFlash.h"
+#include "VirtNorFlashDxe.h"
 
 extern UINTN  mFlashNvStorageVariableBase;
 ///
@@ -653,13 +653,30 @@ FvbRead (
 
   // Decide if we are doing full block reads or not.
   if (*NumBytes % BlockSize != 0) {
-    TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, *NumBytes, Buffer);
+    TempStatus = NorFlashRead (
+                   Instance->DeviceBaseAddress,
+                   Instance->RegionBaseAddress,
+                   Instance->StartLba + Lba,
+                   Instance->BlockSize,
+                   Instance->Size,
+                   Offset,
+                   *NumBytes,
+                   Buffer
+                   );
     if (EFI_ERROR (TempStatus)) {
       return EFI_DEVICE_ERROR;
     }
   } else {
     // Read NOR Flash data into shadow buffer
-    TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, Buffer);
+    TempStatus = NorFlashReadBlocks (
+                   Instance->DeviceBaseAddress,
+                   Instance->RegionBaseAddress,
+                   Instance->StartLba + Lba,
+                   Instance->LastBlock,
+                   Instance->BlockSize,
+                   BlockSize,
+                   Buffer
+                   );
     if (EFI_ERROR (TempStatus)) {
       // Return one of the pre-approved error statuses
       return EFI_DEVICE_ERROR;
@@ -737,7 +754,18 @@ FvbWrite (
 
   Instance = INSTANCE_FROM_FVB_THIS (This);
 
-  return NorFlashWriteSingleBlock (Instance, Instance->StartLba + Lba, Offset, NumBytes, Buffer);
+  return NorFlashWriteSingleBlock (
+           Instance->DeviceBaseAddress,
+           Instance->RegionBaseAddress,
+           Instance->StartLba + Lba,
+           Instance->LastBlock,
+           Instance->BlockSize,
+           Instance->Size,
+           Offset,
+           NumBytes,
+           Buffer,
+           Instance->ShadowBuffer
+           );
 }
 
 /**
@@ -795,6 +823,7 @@ FvbEraseBlocks (
   UINTN               BlockAddress; // Physical address of Lba to erase
   EFI_LBA             StartingLba;  // Lba from which we start erasing
   UINTN               NumOfLba;     // Number of Lba blocks to erase
+  EFI_TPL             OriginalTPL;
   NOR_FLASH_INSTANCE  *Instance;
 
   Instance = INSTANCE_FROM_FVB_THIS (This);
@@ -865,7 +894,21 @@ FvbEraseBlocks (
 
       // Erase it
       DEBUG ((DEBUG_BLKIO, "FvbEraseBlocks: Erasing Lba=%ld @ 0x%08x.\n", Instance->StartLba + StartingLba, BlockAddress));
-      Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);
+      if (!EfiAtRuntime ()) {
+        // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
+        OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+      } else {
+        // This initialization is only to prevent the compiler to complain about the
+        // use of uninitialized variables
+        OriginalTPL = TPL_HIGH_LEVEL;
+      }
+
+      Status = NorFlashUnlockAndEraseSingleBlock (Instance->DeviceBaseAddress, BlockAddress);
+      if (!EfiAtRuntime ()) {
+        // Interruptions can resume.
+        gBS->RestoreTPL (OriginalTPL);
+      }
+
       if (EFI_ERROR (Status)) {
         VA_END (Args);
         Status = EFI_DEVICE_ERROR;
-- 
2.34.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#121276): https://edk2.groups.io/g/devel/message/121276
Mute This Topic: https://groups.io/mt/112379038/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  reply	other threads:[~2025-04-21 16:58 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-21 16:58 [edk2-devel] [PATCH 0/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade Tuan Phan
2025-04-21 16:58 ` Tuan Phan [this message]
2025-04-21 16:58 ` [edk2-devel] [PATCH 2/3] ArmVirtPkg: Link all targets to the new VirtNorFlashDeviceLib Tuan Phan
2025-04-21 16:58 ` [edk2-devel] [PATCH 3/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade Tuan Phan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250421165819.18451-2-tphan@ventanamicro.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox