public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* [edk2-devel] [PATCH 0/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade
@ 2025-04-21 16:58 Tuan Phan
  2025-04-21 16:58 ` [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library Tuan Phan
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Tuan Phan @ 2025-04-21 16:58 UTC (permalink / raw)
  To: devel
  Cc: andyw, maobibo, lichao, kraxel, jiewen.yao, leif.lindholm,
	sami.mujawar, sunilvl, ardb+tianocore, lixianglai, Tuan Phan

This patch series introduces capsule-based firmware upgrade support
for the RISC-V Virt platform.

Changes:
- Moved low level NOR flash functions to a seperate library.
- Implemented capsule firmware upgrade support.

Tuan Phan (3):
  OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library
  ArmVirtPkg: Link all targets to the new VirtNorFlashDeviceLib
  OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade

 ArmVirtPkg/ArmVirtKvmTool.dsc                 |   1 +
 ArmVirtPkg/ArmVirtQemu.dsc                    |   1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc              |   1 +
 .../Include/Library/VirtNorFlashDeviceLib.h   | 201 +++++
 .../VirtNorFlashDeviceLib.c}                  | 411 ++++++----
 .../VirtNorFlashDeviceLib.inf                 |  30 +
 OvmfPkg/LoongArchVirt/LoongArchVirtQemu.dsc   |   5 +-
 OvmfPkg/OvmfPkg.ci.yaml                       |   3 +-
 OvmfPkg/OvmfPkg.dec                           |   4 +
 .../Capsule/GenerateCapsule/GenCapsule.py     | 332 ++++++++
 .../CapsuleUpdatePolicyLib.c                  | 121 +++
 .../CapsuleUpdatePolicyLib.inf                |  29 +
 .../CapsuleUpdatePolicyLib.uni                |  12 +
 .../Library/FmpDeviceLib/FmpDeviceLib.c       | 774 ++++++++++++++++++
 .../Library/FmpDeviceLib/FmpDeviceLib.inf     |  46 ++
 .../PlatformFlashAccessLib.c                  | 236 ++++++
 .../PlatformFlashAccessLib.h                  |  95 +++
 .../PlatformFlashAccessLib.inf                |  34 +
 OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc           |  44 +-
 OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf           |   5 +
 OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc   |  61 ++
 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 +-
 26 files changed, 2538 insertions(+), 645 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
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.uni
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.h
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc
 delete mode 100644 OvmfPkg/VirtNorFlashDxe/VirtNorFlash.h
 create mode 100644 OvmfPkg/VirtNorFlashDxe/VirtNorFlashDxe.h

-- 
2.34.1



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



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library
  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
  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
  2 siblings, 0 replies; 4+ messages in thread
From: Tuan Phan @ 2025-04-21 16:58 UTC (permalink / raw)
  To: devel
  Cc: andyw, maobibo, lichao, kraxel, jiewen.yao, leif.lindholm,
	sami.mujawar, sunilvl, ardb+tianocore, lixianglai, Tuan Phan

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]
-=-=-=-=-=-=-=-=-=-=-=-



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH 2/3] ArmVirtPkg: Link all targets to the new VirtNorFlashDeviceLib
  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 ` [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library Tuan Phan
@ 2025-04-21 16:58 ` Tuan Phan
  2025-04-21 16:58 ` [edk2-devel] [PATCH 3/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade Tuan Phan
  2 siblings, 0 replies; 4+ messages in thread
From: Tuan Phan @ 2025-04-21 16:58 UTC (permalink / raw)
  To: devel
  Cc: andyw, maobibo, lichao, kraxel, jiewen.yao, leif.lindholm,
	sami.mujawar, sunilvl, ardb+tianocore, lixianglai, Tuan Phan

Since VirtNorFlashDxe now depends on the new VirtNorFlashDeviceLib,
all related targets should be linked against this library.

Signed-off-by: Tuan Phan <tphan@ventanamicro.com>
---
 ArmVirtPkg/ArmVirtKvmTool.dsc    | 1 +
 ArmVirtPkg/ArmVirtQemu.dsc       | 1 +
 ArmVirtPkg/ArmVirtQemuKernel.dsc | 1 +
 3 files changed, 3 insertions(+)

diff --git a/ArmVirtPkg/ArmVirtKvmTool.dsc b/ArmVirtPkg/ArmVirtKvmTool.dsc
index 271459327176..7e1dbb44dea4 100644
--- a/ArmVirtPkg/ArmVirtKvmTool.dsc
+++ b/ArmVirtPkg/ArmVirtKvmTool.dsc
@@ -314,6 +314,7 @@
     <LibraryClasses>
       # don't use unaligned CopyMem () on the UEFI varstore NOR flash region
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
   }
 
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
diff --git a/ArmVirtPkg/ArmVirtQemu.dsc b/ArmVirtPkg/ArmVirtQemu.dsc
index 29aa2dcba8fd..026ab2f47794 100644
--- a/ArmVirtPkg/ArmVirtQemu.dsc
+++ b/ArmVirtPkg/ArmVirtQemu.dsc
@@ -435,6 +435,7 @@
     <LibraryClasses>
       # don't use unaligned CopyMem () on the UEFI varstore NOR flash region
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
   }
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf
diff --git a/ArmVirtPkg/ArmVirtQemuKernel.dsc b/ArmVirtPkg/ArmVirtQemuKernel.dsc
index 0dee41cf9f74..47f52826d209 100644
--- a/ArmVirtPkg/ArmVirtQemuKernel.dsc
+++ b/ArmVirtPkg/ArmVirtQemuKernel.dsc
@@ -355,6 +355,7 @@
     <LibraryClasses>
       # don't use unaligned CopyMem () on the UEFI varstore NOR flash region
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
   }
   MdeModulePkg/Universal/WatchdogTimerDxe/WatchdogTimer.inf
   SecurityPkg/RandomNumberGenerator/RngDxe/RngDxe.inf
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [edk2-devel] [PATCH 3/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade
  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 ` [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library Tuan Phan
  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 ` Tuan Phan
  2 siblings, 0 replies; 4+ messages in thread
From: Tuan Phan @ 2025-04-21 16:58 UTC (permalink / raw)
  To: devel
  Cc: andyw, maobibo, lichao, kraxel, jiewen.yao, leif.lindholm,
	sami.mujawar, sunilvl, ardb+tianocore, lixianglai, Tuan Phan

This patch introduces support for firmware upgrades using the
FMP capsule update mechanism.

Signed-off-by: Tuan Phan <tphan@ventanamicro.com>
---
 OvmfPkg/OvmfPkg.ci.yaml                       |   3 +-
 .../Capsule/GenerateCapsule/GenCapsule.py     | 332 ++++++++
 .../CapsuleUpdatePolicyLib.c                  | 121 +++
 .../CapsuleUpdatePolicyLib.inf                |  29 +
 .../CapsuleUpdatePolicyLib.uni                |  12 +
 .../Library/FmpDeviceLib/FmpDeviceLib.c       | 774 ++++++++++++++++++
 .../Library/FmpDeviceLib/FmpDeviceLib.inf     |  46 ++
 .../PlatformFlashAccessLib.c                  | 236 ++++++
 .../PlatformFlashAccessLib.h                  |  95 +++
 .../PlatformFlashAccessLib.inf                |  34 +
 OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc           |  39 +
 OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf           |   5 +
 OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc   |  61 ++
 13 files changed, 1786 insertions(+), 1 deletion(-)
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.uni
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.h
 create mode 100644 OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
 create mode 100644 OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc

diff --git a/OvmfPkg/OvmfPkg.ci.yaml b/OvmfPkg/OvmfPkg.ci.yaml
index e4b729b4a80e..056e681b3dd2 100644
--- a/OvmfPkg/OvmfPkg.ci.yaml
+++ b/OvmfPkg/OvmfPkg.ci.yaml
@@ -53,7 +53,8 @@
             "UefiCpuPkg/UefiCpuPkg.dec",
             "ShellPkg/ShellPkg.dec",
             "EmbeddedPkg/EmbeddedPkg.dec",
-            "SourceLevelDebugPkg/SourceLevelDebugPkg.dec"
+            "SourceLevelDebugPkg/SourceLevelDebugPkg.dec",
+            "FmpDevicePkg/FmpDevicePkg.dec"
         ],
         # For host based unit tests
         "AcceptableDependencies-HOST_APPLICATION":[
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py b/OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py
new file mode 100644
index 000000000000..1889328fb9ba
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py
@@ -0,0 +1,332 @@
+## @file
+# Generate capsules for RiscVVirt platform
+#   openssl, gcab must be install and in path
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+
+'''
+GenCapsuleAll
+'''
+
+import os
+import sys
+import argparse
+import subprocess
+import glob
+import shutil
+import struct
+import datetime
+
+#
+# Globals for help information
+#
+__prog__        = 'GenCapsuleAll'
+__copyright__   = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
+__description__ = 'Generate RiscVVirt capsules.\n'
+
+#
+# Globals
+#
+gWorkspace = ''
+gBaseToolsPath = ''
+gArgs      = None
+
+def LogAlways(Message):
+    sys.stdout.write (__prog__ + ': ' + Message + '\n')
+    sys.stdout.flush()
+
+def Log(Message):
+    global gArgs
+    if not gArgs.Verbose:
+        return
+    sys.stdout.write (__prog__ + ': ' + Message + '\n')
+    sys.stdout.flush()
+
+def Error(Message, ExitValue=1):
+    sys.stderr.write (__prog__ + ': ERROR: ' + Message + '\n')
+    sys.exit (ExitValue)
+
+def RelativePath(target):
+    global gWorkspace
+    Log('RelativePath' + target)
+    return os.path.relpath (target, gWorkspace)
+
+def NormalizePath(target):
+    if isinstance(target, tuple):
+        return os.path.normpath (os.path.join (*target))
+    else:
+        return os.path.normpath (target)
+
+def RemoveFile(target):
+    target = NormalizePath(target)
+    if not target or target == os.pathsep:
+        Error ('RemoveFile() invalid target')
+    if os.path.exists(target):
+        os.remove (target)
+        Log ('remove %s' % (RelativePath (target)))
+
+def RemoveDirectory(target):
+    target = NormalizePath(target)
+    if not target or target == os.pathsep:
+        Error ('RemoveDirectory() invalid target')
+    if os.path.exists(target):
+        Log ('rmdir %s' % (RelativePath (target)))
+        shutil.rmtree(target)
+
+def CreateDirectory(target):
+    target = NormalizePath(target)
+    if not os.path.exists(target):
+        Log ('mkdir %s' % (RelativePath (target)))
+        os.makedirs (target)
+
+def Copy(src, dst):
+    src = NormalizePath(src)
+    dst = NormalizePath(dst)
+    for File in glob.glob(src):
+        Log ('copy %s -> %s' % (RelativePath (File), RelativePath (dst)))
+        shutil.copy (File, dst)
+
+GenerateCapsuleCommand = '''
+GenerateCapsule
+--encode
+--guid {FMP_CAPSULE_GUID}
+--fw-version {FMP_CAPSULE_VERSION}
+--lsv {FMP_CAPSULE_LSV}
+--signer-private-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestCert.pem
+--other-public-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestSub.pub.pem
+--trusted-public-cert={BASE_TOOLS_PATH}/Source/Python/Pkcs7Sign/TestRoot.pub.pem
+-o {FMP_CAPSULE_FILE}
+{FMP_CAPSULE_PAYLOAD}
+'''
+MetaInfoXmlTemplate = '''
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="firmware">
+  <id>com.intel.FMP_CAPSULE_BASE_NAME.firmware</id>
+  <name>FMP_CAPSULE_BASE_NAME</name>
+  <summary>System firmware for the FMP_CAPSULE_BASE_NAME</summary>
+  <description>
+    Description of System firmware for the FMP_CAPSULE_BASE_NAME
+  </description>
+  <provides>
+    <firmware type="flashed">FMP_CAPSULE_GUID</firmware>
+  </provides>
+  <url type="homepage">http://www.tianocore.org</url>
+  <metadata_license>CC0-1.0</metadata_license>
+  <project_license>BSD</project_license>
+  <developer_name>Tianocore</developer_name>
+  <releases>
+    <release version="FMP_CAPSULE_VERSION_DECIMAL" date="FMP_CAPSULE_DATE">
+      <description>
+        Build FMP_CAPSULE_STRING
+      </description>
+    </release>
+  </releases>
+  <!-- most OEMs do not need to do this... -->
+  <custom>
+    <value key="LVFS::InhibitDownload"/>
+  </custom>
+</component>
+'''
+
+def GenCapsuleDevice (BaseName, PayloadFileName, Guid, Version, Lsv, CapsulesPath, CapsulesSubDir):
+    global gBaseToolsPath
+    LogAlways ('Generate Capsule: {0} {1:08x} {2:08x} {3}'.format (Guid, Version, Lsv, PayloadFileName))
+
+    VersionString = '.'.join([str(ord(x)) for x in struct.pack('>I', Version).decode()])
+
+    FmpCapsuleFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cap'))
+    Command = GenerateCapsuleCommand.format (
+                FMP_CAPSULE_GUID    = Guid,
+                FMP_CAPSULE_VERSION = Version,
+                FMP_CAPSULE_LSV     = Lsv,
+                BASE_TOOLS_PATH     = gBaseToolsPath,
+                FMP_CAPSULE_FILE    = FmpCapsuleFile,
+                FMP_CAPSULE_PAYLOAD = PayloadFileName
+                )
+    Command = ' '.join(Command.splitlines()).strip()
+    if gArgs.Verbose:
+        Command = Command + ' -v'
+
+    Log (Command)
+
+    Process = subprocess.Popen(Command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+    ProcessOutput = Process.communicate()
+
+    if Process.returncode == 0:
+        Log (ProcessOutput[0].decode())
+    else:
+        LogAlways (Command)
+        LogAlways (ProcessOutput[0].decode())
+        Error ('GenerateCapsule returned an error')
+
+    Copy (PayloadFileName, (CapsulesPath, 'firmware.bin'))
+    MetaInfoXml = MetaInfoXmlTemplate
+    MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_GUID', Guid)
+    MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_BASE_NAME', BaseName)
+    MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_VERSION_DECIMAL', str(Version))
+    MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_STRING', VersionString)
+    MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_DATE', str(datetime.date.today()))
+    f = open (NormalizePath ((CapsulesPath, 'firmware.metainfo.xml')), 'w')
+    f.write(MetaInfoXml)
+    f.close()
+
+    Command = 'gcab --create firmware.cab firmware.bin firmware.metainfo.xml'
+    Log (Command)
+
+    Process = subprocess.Popen(Command, cwd=CapsulesPath, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
+    ProcessOutput = Process.communicate()
+
+    if Process.returncode == 0:
+        Log (ProcessOutput[0].decode())
+    else:
+        LogAlways (Command)
+        LogAlways (ProcessOutput[0].decode())
+        Error ('GenerateCapsule returned an error')
+
+    FmpCabinetFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cab'))
+
+    Copy ((CapsulesPath, 'firmware.cab'), FmpCabinetFile)
+
+    RemoveFile ((CapsulesPath, 'firmware.cab'))
+    RemoveFile ((CapsulesPath, 'firmware.metainfo.xml'))
+    RemoveFile ((CapsulesPath, 'firmware.bin'))
+
+if __name__ == '__main__':
+    #
+    # Create command line argument parser object
+    #
+    parser = argparse.ArgumentParser (
+                        prog = __prog__,
+                        description = __description__ + __copyright__,
+                        conflict_handler = 'resolve'
+                        )
+    parser.add_argument (
+             '-a', '--arch', dest = 'Arch', nargs = '+', action = 'append',
+             required = True,
+             help = '''ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64, RISCV64
+                       or EBC, which overrides target.txt's TARGET_ARCH definition.
+                       To specify more archs, please repeat this option.'''
+             )
+    parser.add_argument (
+             '-t', '--tagname', dest = 'ToolChain', required = True,
+             help = '''Using the Tool Chain Tagname to build the platform,
+                       overriding target.txt's TOOL_CHAIN_TAG definition.'''
+             )
+    parser.add_argument (
+             '-p', '--platform', dest = 'PlatformFile', required = True,
+             help = '''Build the platform specified by the DSC file name argument,
+                       overriding target.txt's ACTIVE_PLATFORM definition.'''
+             )
+    parser.add_argument (
+             '-b', '--buildtarget', dest = 'BuildTarget', required = True,
+             help = '''Using the TARGET to build the platform, overriding
+                       target.txt's TARGET definition.'''
+             )
+    parser.add_argument (
+             '--conf=', dest = 'ConfDirectory', required = True,
+             help = '''Specify the customized Conf directory.'''
+             )
+    parser.add_argument (
+             '-D', '--define', dest = 'Define', nargs='*', action = 'append',
+             help = '''Macro: "Name [= Value]".'''
+             )
+    parser.add_argument (
+             '-v', '--verbose', dest = 'Verbose', action = 'store_true',
+             help = '''Turn on verbose output with informational messages printed'''
+             )
+    parser.add_argument (
+             '--package', dest = 'Package', nargs = '*', action = 'append',
+             help = '''The directory name of a package of tests to copy'''
+             )
+
+    #
+    # Parse command line arguments
+    #
+    gArgs, remaining = parser.parse_known_args()
+    gArgs.BuildType = 'all'
+    for BuildType in ['all', 'fds', 'genc', 'genmake', 'clean', 'cleanall', 'modules', 'libraries', 'run']:
+        if BuildType in remaining:
+            gArgs.BuildType = BuildType
+            remaining.remove(BuildType)
+            break
+    gArgs.Remaining = ' '.join(remaining)
+
+    #
+    # Get WORKSPACE environment variable
+    #
+    try:
+        gWorkspace = os.environ['WORKSPACE']
+    except:
+        Error ('WORKSPACE environment variable not set')
+
+    #
+    # Get PACKAGES_PATH and generate prioritized list of paths
+    #
+    PathList = [gWorkspace]
+    try:
+        PathList += os.environ['PACKAGES_PATH'].split(os.pathsep)
+    except:
+        pass
+
+    #
+    # Determine full path to BaseTools
+    #
+    for Path in PathList:
+        if os.path.exists (os.path.join (Path, 'BaseTools')):
+            gBaseToolsPath = os.path.join (Path, 'BaseTools')
+            break
+
+    #
+    # Parse PLATFORM_NAME from DSC file
+    #
+    for Path in PathList:
+        if os.path.exists (os.path.join (Path, gArgs.PlatformFile)):
+            Dsc = open (os.path.join (Path, gArgs.PlatformFile), 'r').readlines()
+            break
+    for Line in Dsc:
+        if Line.strip().startswith('PLATFORM_NAME'):
+            OutputDirectory = os.path.join ('Build', Line.strip().split('=')[1].strip())
+            break
+
+    #
+    # Determine full paths to EDK II build directory, EDK II build output
+    # directory and the CPU arch of the UEFI phase.
+    #
+    CommandDir = os.path.dirname(sys.argv[0])
+    EdkiiBuildDir = os.path.join (gWorkspace, OutputDirectory)
+    EdkiiBuildOutput = os.path.join (EdkiiBuildDir, gArgs.BuildTarget + '_' + gArgs.ToolChain)
+    UefiArch = gArgs.Arch[0][0]
+    if len (gArgs.Arch) > 1:
+        if ['RISCV64'] in gArgs.Arch:
+            UefiArch = 'RISCV64'
+
+    CapsulesPath = NormalizePath((EdkiiBuildDir, 'Capsules'))
+
+    CapsulesSubDir = 'TestCert' + '_' + UefiArch + '_' + gArgs.BuildTarget + '_' + gArgs.ToolChain
+
+    #
+    # Create output directories
+    #
+    try:
+        CreateDirectory ((CapsulesPath))
+    except:
+        pass
+    try:
+        CreateDirectory ((CapsulesPath, CapsulesSubDir))
+    except:
+        pass
+
+    #
+    #  Copy CapsuleApp
+    #
+    Copy ((EdkiiBuildOutput, UefiArch, 'CapsuleApp.efi'), (CapsulesPath, CapsulesSubDir))
+
+    #
+    # Generate capsules for RiscVVirt Firmware Updates
+    #
+    CodeFW = os.path.join (EdkiiBuildOutput, 'FV', 'RISCV_VIRT_CODE.fd')
+    GenCapsuleDevice('RISCVVIRT', CodeFW,'bcbacac2-1d1d-4c14-89a3-5e27496b702d',0x00010000,0x00000000, CapsulesPath, CapsulesSubDir)
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.c b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.c
new file mode 100644
index 000000000000..3d1adfac1849
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.c
@@ -0,0 +1,121 @@
+/** @file
+  Provides platform policy services used during a capsule update.
+
+  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/CapsuleUpdatePolicyLib.h>
+
+/**
+  Determine if the system power state supports a capsule update.
+
+  @param[out] Good  Returns TRUE if system power state supports a capsule
+                    update.  Returns FALSE if system power state does not
+                    support a capsule update.  Return value is only valid if
+                    return status is EFI_SUCCESS.
+
+  @retval EFI_SUCCESS            Good parameter has been updated with result.
+  @retval EFI_INVALID_PARAMETER  Good is NULL.
+  @retval EFI_DEVICE_ERROR       System power state can not be determined.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckSystemPower (
+  OUT BOOLEAN  *Good
+  )
+{
+  *Good = TRUE;
+  return EFI_SUCCESS;
+}
+
+/**
+  Determines if the system thermal state supports a capsule update.
+
+  @param[out] Good  Returns TRUE if system thermal state supports a capsule
+                    update.  Returns FALSE if system thermal state does not
+                    support a capsule update.  Return value is only valid if
+                    return status is EFI_SUCCESS.
+
+  @retval EFI_SUCCESS            Good parameter has been updated with result.
+  @retval EFI_INVALID_PARAMETER  Good is NULL.
+  @retval EFI_DEVICE_ERROR       System thermal state can not be determined.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckSystemThermal (
+  OUT BOOLEAN  *Good
+  )
+{
+  *Good = TRUE;
+  return EFI_SUCCESS;
+}
+
+/**
+  Determines if the system environment state supports a capsule update.
+
+  @param[out] Good  Returns TRUE if system environment state supports a capsule
+                    update.  Returns FALSE if system environment state does not
+                    support a capsule update.  Return value is only valid if
+                    return status is EFI_SUCCESS.
+
+  @retval EFI_SUCCESS            Good parameter has been updated with result.
+  @retval EFI_INVALID_PARAMETER  Good is NULL.
+  @retval EFI_DEVICE_ERROR       System environment state can not be determined.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckSystemEnvironment (
+  OUT BOOLEAN  *Good
+  )
+{
+  *Good = TRUE;
+  return EFI_SUCCESS;
+}
+
+/**
+  Determines if the Lowest Supported Version checks should be performed.  The
+  expected result from this function is TRUE.  A platform can choose to return
+  FALSE (e.g. during manufacturing or servicing) to allow a capsule update to a
+  version below the current Lowest Supported Version.
+
+  @retval TRUE   The lowest supported version check is required.
+  @retval FALSE  Do not perform lowest support version check.
+
+**/
+BOOLEAN
+EFIAPI
+IsLowestSupportedVersionCheckRequired (
+  VOID
+  )
+{
+  return TRUE;
+}
+
+/**
+  Determines if the FMP device should be locked when the event specified by
+  PcdFmpDeviceLockEventGuid is signaled. The expected result from this function
+  is TRUE so the FMP device is always locked.  A platform can choose to return
+  FALSE (e.g. during manufacturing) to allow FMP devices to remain unlocked.
+
+  @retval TRUE   The FMP device lock action is required at lock event guid.
+  @retval FALSE  Do not perform FMP device lock at lock event guid.
+
+**/
+BOOLEAN
+EFIAPI
+IsLockFmpDeviceAtLockEventGuidRequired (
+  VOID
+  )
+{
+  // Not lock FMP device for this platform
+  return FALSE;
+}
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf
new file mode 100644
index 000000000000..fcefadd0551d
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf
@@ -0,0 +1,29 @@
+## @file
+#  Provides platform policy services used during a capsule update.
+#
+#  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 1.30
+  BASE_NAME       = CapsuleUpdatePolicyLib
+  MODULE_UNI_FILE = CapsuleUpdatePolicyLib.uni
+  FILE_GUID       = 3ed188f7-7aba-47ff-bdeb-2ac23287a5ea
+  MODULE_TYPE     = BASE
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = CapsuleUpdatePolicyLib
+
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
+#
+
+[Sources]
+  CapsuleUpdatePolicyLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.uni b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.uni
new file mode 100644
index 000000000000..d26e716b11ad
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.uni
@@ -0,0 +1,12 @@
+// /** @file
+// Provides platform policy services used during a capsule update.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT     #language en-US  "Provides platform policy services used during a capsule update."
+
+#string STR_MODULE_DESCRIPTION  #language en-US  "Provides platform policy services used during a capsule update."
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
new file mode 100644
index 000000000000..4fe21b763d5b
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.c
@@ -0,0 +1,774 @@
+/** @file
+  Provides firmware device specific services to support updates of a firmware
+  image stored in a firmware device.
+
+  Copyright (c) Microsoft Corporation.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Guid/SystemResourceTable.h>
+#include <Library/DebugLib.h>
+#include <Library/FmpDeviceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Include/LastAttemptStatus.h>
+#include "../PlatformFlashAccessLib/PlatformFlashAccessLib.h"
+
+#define __BUILD_STRING(x)  L ## #x
+#define BUILD_STRING(x)    L"build #" __BUILD_STRING(x)
+#define CURRENT_FIRMWARE_VERSION         FixedPcdGet32 (PcdFirmwareRevision)
+#define CURRENT_FIRMWARE_VERSION_STRING  BUILD_STRING (CURRENT_FIRMWARE_VERSION)
+
+typedef struct {
+  PLATFORM_FIRMWARE_TYPE    FirmwareType;
+  FLASH_ADDRESS_TYPE        AddressType;
+  EFI_PHYSICAL_ADDRESS      BaseAddress;
+  UINTN                     Length;
+  UINTN                     ImageOffset;
+} UPDATE_CONFIG_DATA;
+
+UPDATE_CONFIG_DATA  mUpdateConfigData[] = {
+  { PlatformFirmwareTypeSystemFirmware, FlashAddressTypeAbsoluteAddress, 0x20000000, 0x00800000, 0x00000000 },
+};
+
+/**
+  Provide a function to install the Firmware Management Protocol instance onto a
+  device handle when the device is managed by a driver that follows the UEFI
+  Driver Model.  If the device is not managed by a driver that follows the UEFI
+  Driver Model, then EFI_UNSUPPORTED is returned.
+
+  @param[in] FmpInstaller  Function that installs the Firmware Management
+                           Protocol.
+
+  @retval EFI_SUCCESS      The device is managed by a driver that follows the
+                           UEFI Driver Model.  FmpInstaller must be called on
+                           each Driver Binding Start().
+  @retval EFI_UNSUPPORTED  The device is not managed by a driver that follows
+                           the UEFI Driver Model.
+  @retval other            The Firmware Management Protocol for this firmware
+                           device is not installed.  The firmware device is
+                           still locked using FmpDeviceLock().
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterFmpInstaller (
+  IN FMP_DEVICE_LIB_REGISTER_FMP_INSTALLER  Function
+  )
+{
+  //
+  // This is a system firmware update that does not use Driver Binding Protocol
+  //
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Provide a function to uninstall the Firmware Management Protocol instance from a
+  device handle when the device is managed by a driver that follows the UEFI
+  Driver Model.  If the device is not managed by a driver that follows the UEFI
+  Driver Model, then EFI_UNSUPPORTED is returned.
+
+  @param[in] FmpUninstaller  Function that installs the Firmware Management
+                             Protocol.
+
+  @retval EFI_SUCCESS      The device is managed by a driver that follows the
+                           UEFI Driver Model.  FmpUninstaller must be called on
+                           each Driver Binding Stop().
+  @retval EFI_UNSUPPORTED  The device is not managed by a driver that follows
+                           the UEFI Driver Model.
+  @retval other            The Firmware Management Protocol for this firmware
+                           device is not installed.  The firmware device is
+                           still locked using FmpDeviceLock().
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterFmpUninstaller (
+  IN FMP_DEVICE_LIB_REGISTER_FMP_UNINSTALLER  Function
+  )
+{
+  //
+  // This is a system firmware update that does not use Driver Binding Protocol
+  //
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Set the device context for the FmpDeviceLib services when the device is
+  managed by a driver that follows the UEFI Driver Model.  If the device is not
+  managed by a driver that follows the UEFI Driver Model, then EFI_UNSUPPORTED
+  is returned.  Once a device context is set, the FmpDeviceLib services
+  operate on the currently set device context.
+
+  @param[in]      Handle   Device handle for the FmpDeviceLib services.
+                           If Handle is NULL, then Context is freed.
+  @param[in, out] Context  Device context for the FmpDeviceLib services.
+                           If Context is NULL, then a new context is allocated
+                           for Handle and the current device context is set and
+                           returned in Context.  If Context is not NULL, then
+                           the current device context is set.
+
+  @retval EFI_SUCCESS      The device is managed by a driver that follows the
+                           UEFI Driver Model.
+  @retval EFI_UNSUPPORTED  The device is not managed by a driver that follows
+                           the UEFI Driver Model.
+  @retval other            The Firmware Management Protocol for this firmware
+                           device is not installed.  The firmware device is
+                           still locked using FmpDeviceLock().
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceSetContext (
+  IN EFI_HANDLE  Handle,
+  IN OUT VOID    **Context
+  )
+{
+  //
+  // This is a system firmware update that does not use Driver Binding Protocol
+  //
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Returns the size, in bytes, of the firmware image currently stored in the
+  firmware device.  This function is used to by the GetImage() and
+  GetImageInfo() services of the Firmware Management Protocol.  If the image
+  size can not be determined from the firmware device, then 0 must be returned.
+
+  @param[out] Size  Pointer to the size, in bytes, of the firmware image
+                    currently stored in the firmware device.
+
+  @retval EFI_SUCCESS            The size of the firmware image currently
+                                 stored in the firmware device was returned.
+  @retval EFI_INVALID_PARAMETER  Size is NULL.
+  @retval EFI_UNSUPPORTED        The firmware device does not support reporting
+                                 the size of the currently stored firmware image.
+  @retval EFI_DEVICE_ERROR       An error occurred attempting to determine the
+                                 size of the firmware image currently stored in
+                                 in the firmware device.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetSize (
+  OUT UINTN  *Size
+  )
+{
+  if (Size == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Returns the GUID value used to fill in the ImageTypeId field of the
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+  service of the Firmware Management Protocol.  If EFI_UNSUPPORTED is returned,
+  then the ImageTypeId field is set to gEfiCallerIdGuid.  If EFI_SUCCESS is
+  returned, then ImageTypeId is set to the Guid returned from this function.
+
+  @param[out] Guid  Double pointer to a GUID value that is updated to point to
+                    to a GUID value.  The GUID value is not allocated and must
+                    not be modified or freed by the caller.
+
+  @retval EFI_SUCCESS      EFI_FIRMWARE_IMAGE_DESCRIPTOR ImageTypeId GUID is set
+                           to the returned Guid value.
+  @retval EFI_UNSUPPORTED  EFI_FIRMWARE_IMAGE_DESCRIPTOR ImageTypeId GUID is set
+                           to gEfiCallerIdGuid.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetImageTypeIdGuidPtr (
+  OUT EFI_GUID  **Guid
+  )
+{
+  *Guid = &gEfiCallerIdGuid;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns values used to fill in the AttributesSupported and AttributesSettings
+  fields of the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the
+  GetImageInfo() service of the Firmware Management Protocol.  The following
+  bit values from the Firmware Management Protocol may be combined:
+    IMAGE_ATTRIBUTE_IMAGE_UPDATABLE
+    IMAGE_ATTRIBUTE_RESET_REQUIRED
+    IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED
+    IMAGE_ATTRIBUTE_IN_USE
+    IMAGE_ATTRIBUTE_UEFI_IMAGE
+
+  @param[out] Supported  Attributes supported by this firmware device.
+  @param[out] Setting    Attributes settings for this firmware device.
+
+  @retval EFI_SUCCESS            The attributes supported by the firmware
+                                 device were returned.
+  @retval EFI_INVALID_PARAMETER  Supported is NULL.
+  @retval EFI_INVALID_PARAMETER  Setting is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetAttributes (
+  OUT UINT64  *Supported,
+  OUT UINT64  *Setting
+  )
+{
+  if ((Supported == NULL) || (Setting == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *Supported = (IMAGE_ATTRIBUTE_IMAGE_UPDATABLE         |
+                IMAGE_ATTRIBUTE_RESET_REQUIRED          |
+                IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED |
+                IMAGE_ATTRIBUTE_IN_USE
+                );
+  *Setting = (IMAGE_ATTRIBUTE_IMAGE_UPDATABLE         |
+              IMAGE_ATTRIBUTE_RESET_REQUIRED          |
+              IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED |
+              IMAGE_ATTRIBUTE_IN_USE
+              );
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns the value used to fill in the LowestSupportedVersion field of the
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+  service of the Firmware Management Protocol.  If EFI_SUCCESS is returned, then
+  the firmware device supports a method to report the LowestSupportedVersion
+  value from the currently stored firmware image.  If the value can not be
+  reported for the firmware image currently stored in the firmware device, then
+  EFI_UNSUPPORTED must be returned.  EFI_DEVICE_ERROR is returned if an error
+  occurs attempting to retrieve the LowestSupportedVersion value for the
+  currently stored firmware image.
+
+  @note It is recommended that all firmware devices support a method to report
+        the LowestSupportedVersion value from the currently stored firmware
+        image.
+
+  @param[out] LowestSupportedVersion  LowestSupportedVersion value retrieved
+                                      from the currently stored firmware image.
+
+  @retval EFI_SUCCESS       The lowest supported version of currently stored
+                            firmware image was returned in LowestSupportedVersion.
+  @retval EFI_UNSUPPORTED   The firmware device does not support a method to
+                            report the lowest supported version of the currently
+                            stored firmware image.
+  @retval EFI_DEVICE_ERROR  An error occurred attempting to retrieve the lowest
+                            supported version of the currently stored firmware
+                            image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetLowestSupportedVersion (
+  OUT UINT32  *LowestSupportedVersion
+  )
+{
+  *LowestSupportedVersion = PcdGet32 (PcdFmpDeviceBuildTimeLowestSupportedVersion);
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns the Null-terminated Unicode string that is used to fill in the
+  VersionName field of the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is
+  returned by the GetImageInfo() service of the Firmware Management Protocol.
+  The returned string must be allocated using EFI_BOOT_SERVICES.AllocatePool().
+
+  @note It is recommended that all firmware devices support a method to report
+        the VersionName string from the currently stored firmware image.
+
+  @param[out] VersionString  The version string retrieved from the currently
+                             stored firmware image.
+
+  @retval EFI_SUCCESS            The version string of currently stored
+                                 firmware image was returned in Version.
+  @retval EFI_INVALID_PARAMETER  VersionString is NULL.
+  @retval EFI_UNSUPPORTED        The firmware device does not support a method
+                                 to report the version string of the currently
+                                 stored firmware image.
+  @retval EFI_DEVICE_ERROR       An error occurred attempting to retrieve the
+                                 version string of the currently stored
+                                 firmware image.
+  @retval EFI_OUT_OF_RESOURCES   There are not enough resources to allocate the
+                                 buffer for the version string of the currently
+                                 stored firmware image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetVersionString (
+  OUT CHAR16  **VersionString
+  )
+{
+  if (VersionString == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *VersionString = (CHAR16 *)AllocateCopyPool (
+                               sizeof (CURRENT_FIRMWARE_VERSION_STRING),
+                               CURRENT_FIRMWARE_VERSION_STRING
+                               );
+  if (*VersionString == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns the value used to fill in the Version field of the
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+  service of the Firmware Management Protocol.  If EFI_SUCCESS is returned, then
+  the firmware device supports a method to report the Version value from the
+  currently stored firmware image.  If the value can not be reported for the
+  firmware image currently stored in the firmware device, then EFI_UNSUPPORTED
+  must be returned.  EFI_DEVICE_ERROR is returned if an error occurs attempting
+  to retrieve the LowestSupportedVersion value for the currently stored firmware
+  image.
+
+  @note It is recommended that all firmware devices support a method to report
+        the Version value from the currently stored firmware image.
+
+  @param[out] Version  The version value retrieved from the currently stored
+                       firmware image.
+
+  @retval EFI_SUCCESS       The version of currently stored firmware image was
+                            returned in Version.
+  @retval EFI_UNSUPPORTED   The firmware device does not support a method to
+                            report the version of the currently stored firmware
+                            image.
+  @retval EFI_DEVICE_ERROR  An error occurred attempting to retrieve the version
+                            of the currently stored firmware image.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetVersion (
+  OUT UINT32  *Version
+  )
+{
+  *Version = PcdGet32 (PcdFirmwareRevision);
+  return EFI_SUCCESS;
+}
+
+/**
+  Returns the value used to fill in the HardwareInstance field of the
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+  service of the Firmware Management Protocol.  If EFI_SUCCESS is returned, then
+  the firmware device supports a method to report the HardwareInstance value.
+  If the value can not be reported for the firmware device, then EFI_UNSUPPORTED
+  must be returned.  EFI_DEVICE_ERROR is returned if an error occurs attempting
+  to retrieve the HardwareInstance value for the firmware device.
+
+  @param[out] HardwareInstance  The hardware instance value for the firmware
+                                device.
+
+  @retval EFI_SUCCESS       The hardware instance for the current firmware
+                            device is returned in HardwareInstance.
+  @retval EFI_UNSUPPORTED   The firmware device does not support a method to
+                            report the hardware instance value.
+  @retval EFI_DEVICE_ERROR  An error occurred attempting to retrieve the hardware
+                            instance value.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetHardwareInstance (
+  OUT UINT64  *HardwareInstance
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Returns a copy of the firmware image currently stored in the firmware device.
+
+  @note It is recommended that all firmware devices support a method to retrieve
+        a copy currently stored firmware image.  This can be used to support
+        features such as recovery and rollback.
+
+  @param[out]     Image     Pointer to a caller allocated buffer where the
+                            currently stored firmware image is copied to.
+  @param[in, out] ImageSize Pointer the size, in bytes, of the Image buffer.
+                            On return, points to the size, in bytes, of firmware
+                            image currently stored in the firmware device.
+
+  @retval EFI_SUCCESS            Image contains a copy of the firmware image
+                                 currently stored in the firmware device, and
+                                 ImageSize contains the size, in bytes, of the
+                                 firmware image currently stored in the
+                                 firmware device.
+  @retval EFI_BUFFER_TOO_SMALL   The buffer specified by ImageSize is too small
+                                 to hold the firmware image currently stored in
+                                 the firmware device. The buffer size required
+                                 is returned in ImageSize.
+  @retval EFI_INVALID_PARAMETER  The Image is NULL.
+  @retval EFI_INVALID_PARAMETER  The ImageSize is NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_DEVICE_ERROR       An error occurred attempting to retrieve the
+                                 firmware image currently stored in the firmware
+                                 device.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceGetImage (
+  OUT    VOID   *Image,
+  IN OUT UINTN  *ImageSize
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Checks if a new firmware image is valid for the firmware device.  This
+  function allows firmware update operation to validate the firmware image
+  before FmpDeviceSetImage() is called.
+
+  @param[in]  Image           Points to a new firmware image.
+  @param[in]  ImageSize       Size, in bytes, of a new firmware image.
+  @param[out] ImageUpdatable  Indicates if a new firmware image is valid for
+                              a firmware update to the firmware device.  The
+                              following values from the Firmware Management
+                              Protocol are supported:
+                                IMAGE_UPDATABLE_VALID
+                                IMAGE_UPDATABLE_INVALID
+                                IMAGE_UPDATABLE_INVALID_TYPE
+                                IMAGE_UPDATABLE_INVALID_OLD
+                                IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
+
+  @retval EFI_SUCCESS            The image was successfully checked.  Additional
+                                 status information is returned in
+                                 ImageUpdatable.
+  @retval EFI_INVALID_PARAMETER  Image is NULL.
+  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceCheckImage (
+  IN  CONST VOID  *Image,
+  IN  UINTN       ImageSize,
+  OUT UINT32      *ImageUpdatable
+  )
+{
+  UINT32  LastAttemptStatus;
+
+  return FmpDeviceCheckImageWithStatus (Image, ImageSize, ImageUpdatable, &LastAttemptStatus);
+}
+
+/**
+  Checks if a new firmware image is valid for the firmware device.  This
+  function allows firmware update operation to validate the firmware image
+  before FmpDeviceSetImage() is called.
+
+  @param[in]  Image               Points to a new firmware image.
+  @param[in]  ImageSize           Size, in bytes, of a new firmware image.
+  @param[out] ImageUpdatable      Indicates if a new firmware image is valid for
+                                  a firmware update to the firmware device.  The
+                                  following values from the Firmware Management
+                                  Protocol are supported:
+                                    IMAGE_UPDATABLE_VALID
+                                    IMAGE_UPDATABLE_INVALID
+                                    IMAGE_UPDATABLE_INVALID_TYPE
+                                    IMAGE_UPDATABLE_INVALID_OLD
+                                    IMAGE_UPDATABLE_VALID_WITH_VENDOR_CODE
+  @param[out] LastAttemptStatus   A pointer to a UINT32 that holds the last attempt
+                                  status to report back to the ESRT table in case
+                                  of error.
+
+                                  The return status code must fall in the range of
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                  LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                  If the value falls outside this range, it will be converted
+                                  to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The image was successfully checked.  Additional
+                                 status information is returned in
+                                 ImageUpdatable.
+  @retval EFI_INVALID_PARAMETER  Image is NULL.
+  @retval EFI_INVALID_PARAMETER  ImageUpdatable is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceCheckImageWithStatus (
+  IN  CONST VOID  *Image,
+  IN  UINTN       ImageSize,
+  OUT UINT32      *ImageUpdatable,
+  OUT UINT32      *LastAttemptStatus
+  )
+{
+  if (LastAttemptStatus == NULL) {
+    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - LastAttemptStatus Pointer Parameter is NULL.\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+
+  if (ImageUpdatable == NULL) {
+    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - ImageUpdatable Pointer Parameter is NULL.\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Set to valid and then if any tests fail it will update this flag.
+  //
+  *ImageUpdatable = IMAGE_UPDATABLE_VALID;
+
+  if (Image == NULL) {
+    DEBUG ((DEBUG_ERROR, "CheckImageWithStatus - Image Pointer Parameter is NULL.\n"));
+    //
+    // Not sure if this is needed
+    //
+    *ImageUpdatable    = IMAGE_UPDATABLE_INVALID;
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Updates a firmware device with a new firmware image.  This function returns
+  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
+  is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+    - Validate that the image is a supported image for this firmware device.
+      Return EFI_ABORTED if the image is not supported.  Additional details
+      on why the image is not a supported image may be returned in AbortReason.
+    - Validate the data from VendorCode if is not NULL.  Firmware image
+      validation must be performed before VendorCode data validation.
+      VendorCode data is ignored or considered invalid if image validation
+      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update
+  policy.  Null if the caller did not specify the policy or use the default
+  policy.  As an example, vendor can implement a policy to allow an option to
+  force a firmware image update when the abort reason is due to the new firmware
+  image version is older than the current firmware image version or bad image
+  checksum.  Sensitive operations such as those wiping the entire firmware image
+  and render the device to be non-functional should be encoded in the image
+  itself rather than passed with the VendorCode.  AbortReason enables vendor to
+  have the option to provide a more detailed description of the abort reason to
+  the caller.
+
+  @param[in]  Image             Points to the new firmware image.
+  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
+  @param[in]  VendorCode        This enables vendor to implement vendor-specific
+                                firmware image update policy.  NULL indicates
+                                the caller did not specify the policy or use the
+                                default policy.
+  @param[in]  Progress          A function used to report the progress of
+                                updating the firmware device with the new
+                                firmware image.
+  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
+                                update capsule that provided the new firmware
+                                image.
+  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
+                                Unicode string providing more details on an
+                                aborted operation. The buffer is allocated by
+                                this function with
+                                EFI_BOOT_SERVICES.AllocatePool().  It is the
+                                caller's responsibility to free this buffer with
+                                EFI_BOOT_SERVICES.FreePool().
+
+  @retval EFI_SUCCESS            The firmware device was successfully updated
+                                 with the new firmware image.
+  @retval EFI_ABORTED            The operation is aborted.  Additional details
+                                 are provided in AbortReason.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceSetImage (
+  IN  CONST VOID                                     *Image,
+  IN  UINTN                                          ImageSize,
+  IN  CONST VOID                                     *VendorCode        OPTIONAL,
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress           OPTIONAL,
+  IN  UINT32                                         CapsuleFwVersion,
+  OUT CHAR16                                         **AbortReason
+  )
+{
+  UINT32  LastAttemptStatus;
+
+  return FmpDeviceSetImageWithStatus (
+           Image,
+           ImageSize,
+           VendorCode,
+           Progress,
+           CapsuleFwVersion,
+           AbortReason,
+           &LastAttemptStatus
+           );
+}
+
+/**
+  Updates a firmware device with a new firmware image.  This function returns
+  EFI_UNSUPPORTED if the firmware image is not updatable.  If the firmware image
+  is updatable, the function should perform the following minimal validations
+  before proceeding to do the firmware image update.
+    - Validate that the image is a supported image for this firmware device.
+      Return EFI_ABORTED if the image is not supported.  Additional details
+      on why the image is not a supported image may be returned in AbortReason.
+    - Validate the data from VendorCode if is not NULL.  Firmware image
+      validation must be performed before VendorCode data validation.
+      VendorCode data is ignored or considered invalid if image validation
+      fails.  Return EFI_ABORTED if the VendorCode data is invalid.
+
+  VendorCode enables vendor to implement vendor-specific firmware image update
+  policy.  Null if the caller did not specify the policy or use the default
+  policy.  As an example, vendor can implement a policy to allow an option to
+  force a firmware image update when the abort reason is due to the new firmware
+  image version is older than the current firmware image version or bad image
+  checksum.  Sensitive operations such as those wiping the entire firmware image
+  and render the device to be non-functional should be encoded in the image
+  itself rather than passed with the VendorCode.  AbortReason enables vendor to
+  have the option to provide a more detailed description of the abort reason to
+  the caller.
+
+  @param[in]  Image             Points to the new firmware image.
+  @param[in]  ImageSize         Size, in bytes, of the new firmware image.
+  @param[in]  VendorCode        This enables vendor to implement vendor-specific
+                                firmware image update policy.  NULL indicates
+                                the caller did not specify the policy or use the
+                                default policy.
+  @param[in]  Progress          A function used to report the progress of
+                                updating the firmware device with the new
+                                firmware image.
+  @param[in]  CapsuleFwVersion  The version of the new firmware image from the
+                                update capsule that provided the new firmware
+                                image.
+  @param[out] AbortReason       A pointer to a pointer to a Null-terminated
+                                Unicode string providing more details on an
+                                aborted operation. The buffer is allocated by
+                                this function with
+                                EFI_BOOT_SERVICES.AllocatePool().  It is the
+                                caller's responsibility to free this buffer with
+                                EFI_BOOT_SERVICES.FreePool().
+  @param[out] LastAttemptStatus A pointer to a UINT32 that holds the last attempt
+                                status to report back to the ESRT table in case
+                                of error. This value will only be checked when this
+                                function returns an error.
+
+                                The return status code must fall in the range of
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE to
+                                LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MAX_ERROR_CODE_VALUE.
+
+                                If the value falls outside this range, it will be converted
+                                to LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL.
+
+  @retval EFI_SUCCESS            The firmware device was successfully updated
+                                 with the new firmware image.
+  @retval EFI_ABORTED            The operation is aborted.  Additional details
+                                 are provided in AbortReason.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceSetImageWithStatus (
+  IN  CONST VOID                                     *Image,
+  IN  UINTN                                          ImageSize,
+  IN  CONST VOID                                     *VendorCode        OPTIONAL,
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress           OPTIONAL,
+  IN  UINT32                                         CapsuleFwVersion,
+  OUT CHAR16                                         **AbortReason,
+  OUT UINT32                                         *LastAttemptStatus
+  )
+{
+  EFI_STATUS          Status;
+  UINTN               Index;
+  UPDATE_CONFIG_DATA  *ConfigData;
+  UINTN               TotalSize;
+  UINTN               BytesWritten;
+
+  if (Progress == NULL) {
+    DEBUG ((DEBUG_ERROR, "FmpDeviceSetImageWithStatus - Invalid progress callback\n"));
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSATISFIED_DEPENDENCIES;
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %d Images ...\n", ARRAY_SIZE (mUpdateConfigData)));
+
+  //
+  // Compute total size of update
+  //
+  for (Index = 0, TotalSize = 0; Index < ARRAY_SIZE (mUpdateConfigData); Index++) {
+    TotalSize += mUpdateConfigData[Index].Length;
+  }
+
+  BytesWritten = 0;
+  for (Index = 0, ConfigData = mUpdateConfigData; Index < ARRAY_SIZE (mUpdateConfigData); Index++, ConfigData++) {
+    DEBUG ((
+      DEBUG_INFO,
+      "PlatformUpdate(%d): BaseAddress - 0x%lx ImageOffset - 0x%x Length - 0x%x\n",
+      Index,
+      ConfigData->BaseAddress,
+      ConfigData->ImageOffset,
+      ConfigData->Length
+      ));
+    Status = PerformFlashWriteWithProgress (
+               ConfigData->FirmwareType,                                     // FirmwareType
+               ConfigData->BaseAddress,                                      // FlashAddress
+               ConfigData->AddressType,                                      // FlashAddressType
+               (VOID *)((UINTN)Image + (UINTN)ConfigData->ImageOffset),      // Buffer
+               ConfigData->Length,                                           // BufferLength
+               Progress,                                                     // Progress
+               BytesWritten  / TotalSize,                                    // StartPercentage
+               (BytesWritten + ConfigData->Length) * 80 / TotalSize          // EndPercentage
+               );
+    if (EFI_ERROR (Status)) {
+      break;
+    }
+
+    BytesWritten += ConfigData->Length;
+  }
+
+  DEBUG ((DEBUG_INFO, "FmpDeviceSetImageWithStatus - %r\n", Status));
+
+  if (EFI_ERROR (Status)) {
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_DEVICE_LIBRARY_MIN_ERROR_CODE_VALUE;
+  }
+
+  return Status;
+}
+
+/**
+  Lock the firmware device that contains a firmware image.  Once a firmware
+  device is locked, any attempts to modify the firmware image contents in the
+  firmware device must fail.
+
+  @note It is recommended that all firmware devices support a lock method to
+        prevent modifications to a stored firmware image.
+
+  @note A firmware device lock mechanism is typically only cleared by a full
+        system reset (not just sleep state/low power mode).
+
+  @retval  EFI_SUCCESS      The firmware device was locked.
+  @retval  EFI_UNSUPPORTED  The firmware device does not support locking
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDeviceLock (
+  VOID
+  )
+{
+  return EFI_UNSUPPORTED;
+}
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf
new file mode 100644
index 000000000000..abdf5d5d6ddc
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf
@@ -0,0 +1,46 @@
+## @file
+#  Provides firmware device specific services to support updates of a firmware
+#  image stored in a firmware device.
+#
+#  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2025, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+  INF_VERSION     = 1.30
+  BASE_NAME       = FmpDeviceLib
+  FILE_GUID       = BCBACAC2-1D1D-4C14-89A3-5E27496B702D
+  MODULE_TYPE     = DXE_DRIVER
+  VERSION_STRING  = 1.0
+  LIBRARY_CLASS   = FmpDeviceLib|DXE_DRIVER UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+#  VALID_ARCHITECTURES           = IA32 X64 ARM AARCH64 RISCV64
+#
+
+[Sources]
+  FmpDeviceLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+  DebugLib
+  BaseLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  PlatformFlashAccessLib
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareRevision
+  gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceBuildTimeLowestSupportedVersion
+
+
+
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
new file mode 100644
index 000000000000..491757d51903
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.c
@@ -0,0 +1,236 @@
+/** @file
+  Platform Flash Access library.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/VirtNorFlashDeviceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include "PlatformFlashAccessLib.h"
+
+#define ALIGN(v, a)  (UINTN)((((v) - 1) | ((a) - 1)) + 1)
+
+#define FLASH_CODE_BASE  0x20000000
+#define FLASH_DATA_BASE  0x22000000
+#define FLASH_SIZE       SIZE_32MB
+#define BLOCK_SIZE       SIZE_256KB
+
+/**
+  Perform flash write operation with progress indicator.  The start and end
+  completion percentage values are passed into this function.  If the requested
+  flash write operation is broken up, then completion percentage between the
+  start and end values may be passed to the provided Progress function.  The
+  caller of this function is required to call the Progress function for the
+  start and end completion percentage values.  This allows the Progress,
+  StartPercentage, and EndPercentage parameters to be ignored if the requested
+  flash write operation can not be broken up
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+  @param[in] Progress          A function used report the progress of the
+                               firmware update.  This is an optional parameter
+                               that may be NULL.
+  @param[in] StartPercentage   The start completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+  @param[in] EndPercentage     The end completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWriteWithProgress (
+  IN PLATFORM_FIRMWARE_TYPE FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS FlashAddress,
+  IN FLASH_ADDRESS_TYPE FlashAddressType,
+  IN VOID *Buffer,
+  IN UINTN Length,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress, OPTIONAL
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  )
+{
+  EFI_STATUS  Status = EFI_SUCCESS;
+  UINTN       LbaNum;
+  UINTN       Lba;
+  UINTN       Index;
+  VOID        *ShadowBuffer;
+  UINTN       LastBlock;
+  UINTN       NumByte;
+  UINTN       FlashBase;
+
+  DEBUG ((DEBUG_INFO, "PerformFlashWrite - 0x%x(%x) - 0x%x\n", (UINTN)FlashAddress, (UINTN)FlashAddressType, Length));
+
+  if (FlashAddressType != FlashAddressTypeAbsoluteAddress) {
+    // Only support absolute address for this platform
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (FirmwareType == PlatformFirmwareTypeSystemFirmware) {
+    if ((FlashAddress < FLASH_CODE_BASE) || ((FlashAddress + Length) > (FLASH_CODE_BASE + FLASH_SIZE))) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    FlashBase = FLASH_CODE_BASE;
+  } else {
+    if ((FlashAddress < FLASH_DATA_BASE) || ((FlashAddress + Length) > (FLASH_DATA_BASE + FLASH_SIZE))) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    FlashBase = FLASH_DATA_BASE;
+  }
+
+  ShadowBuffer = AllocateZeroPool (BLOCK_SIZE);
+  LastBlock    = FLASH_SIZE / BLOCK_SIZE - 1;
+  if (  (ALIGN (FlashAddress, BLOCK_SIZE) != FlashAddress)
+     || (Length % BLOCK_SIZE))
+  {
+    // Not expect un-aligned flash address
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Erase & Write
+  //
+  LbaNum = Length / BLOCK_SIZE;
+  Lba    = (FlashAddress - FlashBase) / BLOCK_SIZE;
+  for (Index = 0; Index < LbaNum; Index++) {
+    if (Progress != NULL) {
+      Progress (StartPercentage + ((Index * (EndPercentage - StartPercentage)) / LbaNum));
+    }
+
+    if (CompareMem (
+          (UINT8 *)(UINTN)(GET_NOR_BLOCK_ADDRESS (FlashBase, Lba + Index, BLOCK_SIZE)),
+          (UINT8 *)Buffer + Index * BLOCK_SIZE,
+          BLOCK_SIZE
+          ) == 0)
+    {
+      DEBUG ((DEBUG_INFO, "Sector - 0x%x - skip\n", Index));
+      continue;
+    }
+
+    DEBUG ((DEBUG_INFO, "Sector - 0x%x - update...\n", Index));
+    NumByte = BLOCK_SIZE;
+    Status  = NorFlashWriteSingleBlock (
+                FlashBase,
+                FlashBase,
+                Lba + Index,
+                LastBlock,
+                BLOCK_SIZE,
+                FLASH_SIZE,
+                0,
+                &NumByte,
+                (UINT8 *)Buffer + Index * BLOCK_SIZE,
+                ShadowBuffer
+                );
+    if ((Status != EFI_SUCCESS) || (NumByte != BLOCK_SIZE)) {
+      DEBUG ((
+        DEBUG_INFO,
+        "Sector - 0x%x - update failed (bytes written)...\n",
+        Index,
+        NumByte
+        ));
+      break;
+    }
+  }
+
+  if (Progress != NULL) {
+    Progress (EndPercentage);
+  }
+
+  FreePool (ShadowBuffer);
+  return Status;
+}
+
+/**
+  Perform flash write operation.
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWrite (
+  IN PLATFORM_FIRMWARE_TYPE  FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS    FlashAddress,
+  IN FLASH_ADDRESS_TYPE      FlashAddressType,
+  IN VOID                    *Buffer,
+  IN UINTN                   Length
+  )
+{
+  return PerformFlashWriteWithProgress (
+           FirmwareType,
+           FlashAddress,
+           FlashAddressType,
+           Buffer,
+           Length,
+           NULL,
+           0,
+           0
+           );
+}
+
+/**
+  Platform Flash Access Lib Constructor.
+
+  @param[in]  ImageHandle       The firmware allocated handle for the EFI image.
+  @param[in]  SystemTable       A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS  Constructor returns successfully.
+**/
+EFI_STATUS
+EFIAPI
+PlatformFlashAccessLibConstructor (
+  VOID
+  )
+{
+  EFI_STATUS  Status;
+
+  //
+  // map the code flash region, the data flash region
+  // already mapped via variable driver
+  //
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  FLASH_CODE_BASE,
+                  SIZE_32MB,
+                  EFI_MEMORY_UC
+                  );
+  if (!EFI_ERROR (Status)) {
+    Status = gDS->SetMemorySpaceAttributes (
+                    FLASH_CODE_BASE,
+                    SIZE_32MB,
+                    EFI_MEMORY_UC
+                    );
+    ASSERT_EFI_ERROR (Status);
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.h b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.h
new file mode 100644
index 000000000000..fe3cf0a17b3c
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.h
@@ -0,0 +1,95 @@
+/** @file
+  Platform flash device access library.
+
+  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PLATFORM_FLASH_ACCESS_LIB_H__
+#define __PLATFORM_FLASH_ACCESS_LIB_H__
+
+#include <Protocol/FirmwareManagement.h>
+
+typedef enum {
+  FlashAddressTypeRelativeAddress,
+  FlashAddressTypeAbsoluteAddress,
+} FLASH_ADDRESS_TYPE;
+
+//
+// Type 0 ~ 0x7FFFFFFF is defined in this library.
+// Type 0x80000000 ~ 0xFFFFFFFF is reserved for OEM.
+//
+typedef enum {
+  PlatformFirmwareTypeSystemFirmware,
+  PlatformFirmwareTypeNvRam,
+} PLATFORM_FIRMWARE_TYPE;
+
+/**
+  Perform flash write operation.
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWrite (
+  IN PLATFORM_FIRMWARE_TYPE  FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS    FlashAddress,
+  IN FLASH_ADDRESS_TYPE      FlashAddressType,
+  IN VOID                    *Buffer,
+  IN UINTN                   Length
+  );
+
+/**
+  Perform flash write operation with progress indicator.  The start and end
+  completion percentage values are passed into this function.  If the requested
+  flash write operation is broken up, then completion percentage between the
+  start and end values may be passed to the provided Progress function.  The
+  caller of this function is required to call the Progress function for the
+  start and end completion percentage values.  This allows the Progress,
+  StartPercentage, and EndPercentage parameters to be ignored if the requested
+  flash write operation can not be broken up
+
+  @param[in] FirmwareType      The type of firmware.
+  @param[in] FlashAddress      The address of flash device to be accessed.
+  @param[in] FlashAddressType  The type of flash device address.
+  @param[in] Buffer            The pointer to the data buffer.
+  @param[in] Length            The length of data buffer in bytes.
+  @param[in] Progress          A function used report the progress of the
+                               firmware update.  This is an optional parameter
+                               that may be NULL.
+  @param[in] StartPercentage   The start completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+  @param[in] EndPercentage     The end completion percentage value that may
+                               be used to report progress during the flash
+                               write operation.
+
+  @retval EFI_SUCCESS           The operation returns successfully.
+  @retval EFI_WRITE_PROTECTED   The flash device is read only.
+  @retval EFI_UNSUPPORTED       The flash device access is unsupported.
+  @retval EFI_INVALID_PARAMETER The input parameter is not valid.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlashWriteWithProgress (
+  IN PLATFORM_FIRMWARE_TYPE                         FirmwareType,
+  IN EFI_PHYSICAL_ADDRESS                           FlashAddress,
+  IN FLASH_ADDRESS_TYPE                             FlashAddressType,
+  IN VOID                                           *Buffer,
+  IN UINTN                                          Length,
+  IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  Progress         OPTIONAL,
+  IN UINTN                                          StartPercentage,
+  IN UINTN                                          EndPercentage
+  );
+
+#endif
diff --git a/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
new file mode 100644
index 000000000000..1c632f2fde52
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
@@ -0,0 +1,34 @@
+## @file
+#  Platform Flash Access library.
+#
+#  Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2025, Ventana Micro Systems Inc. All Rights Reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 1.30
+  BASE_NAME                      = PlatformFlashAccessLibDxe
+  FILE_GUID                      = 2FDAFAFE-0179-4047-90A4-40BC56CFBBAE
+  MODULE_TYPE                    = BASE
+  VERSION_STRING                 = 1.0
+  LIBRARY_CLASS                  = PlatformFlashAccessLib
+  CONSTRUCTOR                    = PlatformFlashAccessLibConstructor
+
+[Sources]
+  PlatformFlashAccessLib.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  OvmfPkg/OvmfPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  PcdLib
+  DebugLib
+  VirtNorFlashDeviceLib
+  UefiBootServicesTableLib
+  DxeServicesTableLib
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
index 8e864e123f08..47e388ced4a2 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
+++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.dsc
@@ -56,10 +56,20 @@
   !error "NETWORK_SNP_ENABLE is IA32/X64/EBC only"
 !endif
 
+  #
+  # UPDATE/RECOVERY definition
+  #
+  DEFINE CAPSULE_ENABLE          = FALSE
+  DEFINE FMP_SYSTEM_DEVICE       = BCBACAC2-1D1D-4C14-89A3-5E27496B702D
 
 !include MdePkg/MdeLibs.dsc.inc
 !include NetworkPkg/Network.dsc.inc
 
+!if $(CAPSULE_ENABLE) == TRUE
+  POSTBUILD                      = python OvmfPkg/RiscVVirt/Feature/Capsule/GenerateCapsule/GenCapsule.py
+!include OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc
+!endif
+
 [BuildOptions]
   GCC:RELEASE_*_*_CC_FLAGS       = -DMDEPKG_NDEBUG
 !ifdef $(SOURCE_DEBUG_ENABLE)
@@ -118,6 +128,18 @@
   TpmPlatformHierarchyLib|SecurityPkg/Library/PeiDxeTpmPlatformHierarchyLibNull/PeiDxeTpmPlatformHierarchyLib.inf
 !endif
 
+!if $(CAPSULE_ENABLE) == TRUE
+  CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.inf
+  BmpSupportLib|MdeModulePkg/Library/BaseBmpSupportLib/BaseBmpSupportLib.inf
+  SafeIntLib|MdePkg/Library/BaseSafeIntLib/BaseSafeIntLib.inf
+  OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf
+  IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf
+  BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf
+  FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
+  DisplayUpdateProgressLib|MdeModulePkg/Library/DisplayUpdateProgressLibText/DisplayUpdateProgressLibText.inf
+  RngLib|MdeModulePkg/Library/BaseRngLibTimerLib/BaseRngLibTimerLib.inf
+!endif
+
 [LibraryClasses.common.DXE_DRIVER]
   AcpiPlatformLib|OvmfPkg/Library/AcpiPlatformLib/DxeAcpiPlatformLib.inf
   ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeReportStatusCodeLib.inf
@@ -131,6 +153,11 @@
   UefiScsiLib|MdePkg/Library/UefiScsiLib/UefiScsiLib.inf
   PciExpressLib|OvmfPkg/Library/BaseCachingPciExpressLib/BaseCachingPciExpressLib.inf
 
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+!if $(CAPSULE_ENABLE) == TRUE
+  CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibFmp/DxeRuntimeCapsuleLib.inf
+!endif
+
 ################################################################################
 #
 # Pcd Section - list of all EDK II PCD Entries defined by this Platform.
@@ -230,6 +257,10 @@
   gEfiSecurityPkgTokenSpaceGuid.PcdTpmBaseAddress|0x0
 !endif
 
+!if $(CAPSULE_ENABLE) == TRUE
+  gEfiMdeModulePkgTokenSpaceGuid.PcdSystemFmpCapsuleImageTypeIdGuid|{GUID("$(FMP_SYSTEM_DEVICE)")}|VOID*|0x10
+!endif
+
 [PcdsDynamicHii]
   gUefiOvmfPkgTokenSpaceGuid.PcdForceNoAcpi|L"ForceNoAcpi"|gOvmfVariableGuid|0x0|FALSE|NV,BS
 
@@ -493,3 +524,11 @@
     <LibraryClasses>
       NULL|OvmfPkg/Fdt/FdtPciPcdProducerLib/FdtPciPcdProducerLib.inf
   }
+
+!if $(CAPSULE_ENABLE) == TRUE
+  MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf
+  MdeModulePkg/Application/CapsuleApp/CapsuleApp.inf {
+    <LibraryClasses>
+      PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+  }
+!endif
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
index 4528a44d3b82..8cbd5711aa64 100644
--- a/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
+++ b/OvmfPkg/RiscVVirt/RiscVVirtQemu.fdf
@@ -216,6 +216,11 @@ INF  MdeModulePkg/Logo/LogoDxe.inf
 #
 INF  MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf
 
+!if $(CAPSULE_ENABLE) == TRUE
+INF  MdeModulePkg/Universal/EsrtFmpDxe/EsrtFmpDxe.inf
+INF  FILE_GUID = $(FMP_SYSTEM_DEVICE) FmpDevicePkg/FmpDxe/FmpDxe.inf
+!endif
+
 ################################################################################
 
 [FV.FVMAIN_COMPACT]
diff --git a/OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc b/OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc
new file mode 100644
index 000000000000..644e894e03fc
--- /dev/null
+++ b/OvmfPkg/RiscVVirt/RiscVVirtSystemFW.dsc.inc
@@ -0,0 +1,61 @@
+## @file
+#  FmpDxe driver for system firmware update.
+#
+#  Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+FmpDevicePkg/FmpDxe/FmpDxe.inf {
+    <Defines>
+      #
+      # ESRT and FMP GUID for system device capsule update
+      #
+      FILE_GUID = $(FMP_SYSTEM_DEVICE)
+
+    <PcdsFixedAtBuild>
+      #
+      # Unicode name string that is used to populate FMP Image Descriptor for this capsule update module
+      #
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageIdName|L"RISC-V VIRT System Firmware Device"
+
+      #
+      # ESRT and FMP Lowest Support Version for this capsule update module
+      # 000.000.000.000
+      #
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceBuildTimeLowestSupportedVersion|0x00000001
+
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressWatchdogTimeInSeconds|2
+
+      #
+      # Capsule Update Progress Bar Color.  Set to Green (RGB) (0, 255, 0)
+      #
+      gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressColor|0x0000FF00
+
+      #
+      # Certificates used to authenticate capsule update image
+      # EDKII Test certificate
+      #
+      !include BaseTools/Source/Python/Pkcs7Sign/TestRoot.cer.gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr.inc
+
+    <LibraryClasses>
+      #
+      # Generic libraries that are used "as is" by all FMP modules
+      #
+      FmpPayloadHeaderLib|FmpDevicePkg/Library/FmpPayloadHeaderLibV1/FmpPayloadHeaderLibV1.inf
+      FmpAuthenticationLib|SecurityPkg/Library/FmpAuthenticationLibPkcs7/FmpAuthenticationLibPkcs7.inf
+      FmpDependencyLib|FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf
+      FmpDependencyCheckLib|FmpDevicePkg/Library/FmpDependencyCheckLibNull/FmpDependencyCheckLibNull.inf
+      FmpDependencyDeviceLib|FmpDevicePkg/Library/FmpDependencyDeviceLibNull/FmpDependencyDeviceLibNull.inf
+      #
+      # Platform specific capsule policy library
+      #
+      CapsuleUpdatePolicyLib|OvmfPkg/RiscVVirt/Feature/Capsule/Library/CapsuleUpdatePolicyLib/CapsuleUpdatePolicyLib.inf
+      #
+      # Device specific library that processes a capsule and updates the FW storage device
+      #
+      FmpDeviceLib|OvmfPkg/RiscVVirt/Feature/Capsule/Library/FmpDeviceLib/FmpDeviceLib.inf
+      VirtNorFlashDeviceLib|OvmfPkg/Library/VirtNorFlashDeviceLib/VirtNorFlashDeviceLib.inf
+      PlatformFlashAccessLib|OvmfPkg/RiscVVirt/Feature/Capsule/Library/PlatformFlashAccessLib/PlatformFlashAccessLib.inf
+  }
-- 
2.34.1



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



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-04-21 16:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
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 ` [edk2-devel] [PATCH 1/3] OvmfPkg/VirtNorFlash: Move low level NOR flash functions into library Tuan Phan
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox