* [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