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
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ 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] 6+ 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
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ 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] 6+ 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
  2025-04-22  9:01 ` [edk2-devel] [PATCH 0/3] " Sami Mujawar via groups.io
  3 siblings, 0 replies; 6+ 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] 6+ 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
  2025-04-22  9:01 ` [edk2-devel] [PATCH 0/3] " Sami Mujawar via groups.io
  3 siblings, 0 replies; 6+ 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] 6+ messages in thread

* Re: [edk2-devel] [PATCH 0/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
                   ` (2 preceding siblings ...)
  2025-04-21 16:58 ` [edk2-devel] [PATCH 3/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade Tuan Phan
@ 2025-04-22  9:01 ` Sami Mujawar via groups.io
  2025-04-22 13:55   ` Tuan Phan
  3 siblings, 1 reply; 6+ messages in thread
From: Sami Mujawar via groups.io @ 2025-04-22  9:01 UTC (permalink / raw)
  To: Tuan Phan, devel@edk2.groups.io
  Cc: andyw@imsa.edu, maobibo@loongson.cn, lichao@loongson.cn,
	kraxel@redhat.com, jiewen.yao@intel.com,
	leif.lindholm@oss.qualcomm.com, sunilvl@ventanamicro.com,
	ardb+tianocore@kernel.org, lixianglai@loongson.cn, Tuan Phan

[-- Attachment #1: Type: text/plain, Size: 5026 bytes --]

Hi Tuan,

EDK2 has moved to a Github Pull Request model for code reviews and merge.
Is there a PR for this patch series? If not, can you create a PR, please?

Regards,

Sami Mujawar

From: Tuan Phan <tphan@ventanamicro.com>
Date: Monday, 21 April 2025 at 17:58
To: devel@edk2.groups.io <devel@edk2.groups.io>
Cc: andyw@imsa.edu <andyw@imsa.edu>, maobibo@loongson.cn <maobibo@loongson.cn>, lichao@loongson.cn <lichao@loongson.cn>, kraxel@redhat.com <kraxel@redhat.com>, jiewen.yao@intel.com <jiewen.yao@intel.com>, leif.lindholm@oss.qualcomm.com <leif.lindholm@oss.qualcomm.com>, Sami Mujawar <Sami.Mujawar@arm.com>, sunilvl@ventanamicro.com <sunilvl@ventanamicro.com>, ardb+tianocore@kernel.org <ardb+tianocore@kernel.org>, lixianglai@loongson.cn <lixianglai@loongson.cn>, Tuan Phan <tphan@ventanamicro.com>
Subject: [PATCH 0/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade
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
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#121280): https://edk2.groups.io/g/devel/message/121280
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]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 10100 bytes --]

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

* Re: [edk2-devel] [PATCH 0/3] OvmfPkg/RiscVVirt: Add support for Capsule Firmware Upgrade
  2025-04-22  9:01 ` [edk2-devel] [PATCH 0/3] " Sami Mujawar via groups.io
@ 2025-04-22 13:55   ` Tuan Phan
  0 siblings, 0 replies; 6+ messages in thread
From: Tuan Phan @ 2025-04-22 13:55 UTC (permalink / raw)
  To: Sami Mujawar
  Cc: devel@edk2.groups.io, andyw@imsa.edu, maobibo@loongson.cn,
	lichao@loongson.cn, kraxel@redhat.com, jiewen.yao@intel.com,
	leif.lindholm@oss.qualcomm.com, sunilvl@ventanamicro.com,
	ardb+tianocore@kernel.org, lixianglai@loongson.cn

[-- Attachment #1: Type: text/plain, Size: 5492 bytes --]

Hi Sami,

Yes, it's already on Github. You can find it here:
https://github.com/tianocore/edk2/pull/10975


Thanks,
Tuan

On Tue, Apr 22, 2025 at 2:02 AM Sami Mujawar <Sami.Mujawar@arm.com> wrote:

> Hi Tuan,
>
>
>
> EDK2 has moved to a Github Pull Request model for code reviews and merge.
>
> Is there a PR for this patch series? If not, can you create a PR, please?
>
>
>
> Regards,
>
>
>
> Sami Mujawar
>
>
>
> *From: *Tuan Phan <tphan@ventanamicro.com>
> *Date: *Monday, 21 April 2025 at 17:58
> *To: *devel@edk2.groups.io <devel@edk2.groups.io>
> *Cc: *andyw@imsa.edu <andyw@imsa.edu>, maobibo@loongson.cn <
> maobibo@loongson.cn>, lichao@loongson.cn <lichao@loongson.cn>,
> kraxel@redhat.com <kraxel@redhat.com>, jiewen.yao@intel.com <
> jiewen.yao@intel.com>, leif.lindholm@oss.qualcomm.com <
> leif.lindholm@oss.qualcomm.com>, Sami Mujawar <Sami.Mujawar@arm.com>,
> sunilvl@ventanamicro.com <sunilvl@ventanamicro.com>,
> ardb+tianocore@kernel.org <ardb+tianocore@kernel.org>,
> lixianglai@loongson.cn <lixianglai@loongson.cn>, Tuan Phan <
> tphan@ventanamicro.com>
> *Subject: *[PATCH 0/3] OvmfPkg/RiscVVirt: Add support for Capsule
> Firmware Upgrade
>
> 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
> IMPORTANT NOTICE: The contents of this email and any attachments are
> confidential and may also be privileged. If you are not the intended
> recipient, please notify the sender immediately and do not disclose the
> contents to any other person, use it for any purpose, or store or copy the
> information in any medium. Thank you.
>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#121282): https://edk2.groups.io/g/devel/message/121282
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]
-=-=-=-=-=-=-=-=-=-=-=-



[-- Attachment #2: Type: text/html, Size: 9702 bytes --]

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

end of thread, other threads:[~2025-04-22 13:56 UTC | newest]

Thread overview: 6+ 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
2025-04-22  9:01 ` [edk2-devel] [PATCH 0/3] " Sami Mujawar via groups.io
2025-04-22 13:55   ` Tuan Phan

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