* [edk2-devel][edk2-platforms][PATCH v1] EarlySpiFlashRescueFeaturePkg: Initial commit of new feature
@ 2022-09-06 17:54 Benjamin Doron
0 siblings, 0 replies; only message in thread
From: Benjamin Doron @ 2022-09-06 17:54 UTC (permalink / raw)
To: devel
Cc: Sai Chaganty, Isaac Oram, Nate DeSimone, Ankit Sinha, Liming Gao,
Eric Dong
Implement a new debug feature to assist in recovering the SPI flash from
broken firmware. This feature is intended to be used with the userspace
tool presently in my repo here:
https://github.com/benjamindoron/early_flash_rescue.
After my planned second project for GSoC 2022 finished early, I chose to
implement this feature too with the remaining time.
The UEFI shell app implemented for testing and located in that repo
works quite well, though quite slow due to the serial port layer. The
PEIM seems to be quite broken at present. CPU throws undefined opcode
exception for a PciLibRead8() in the PchAcpiBaseSet()... constructor?
Specifically, EIP points at `test ebx, 0xf0000f00`. Note that this means
that re-entry actually succeeds. Maybe.
Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Ankit Sinha <ankit.sinha@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Signed-off-by: Benjamin Doron <benjamin.doron00@gmail.com>
---
.../AdvancedFeaturePkg/AdvancedFeaturePkg.dsc | 1 +
.../Include/AdvancedFeatures.dsc | 4 +
.../Include/AdvancedFeaturesPcd.dsc | 2 +
.../AdvancedFeaturePkg/Include/PostMemory.fdf | 4 +
.../AdvancedFeaturePkg/Include/PreMemory.fdf | 4 +
.../EarlySpiFlashRescueFeaturePkg.dec | 44 ++++
.../EarlySpiFlashRescueFeaturePkg.dsc | 47 ++++
.../FlashRescueBoardPei/FlashRescueBoard.h | 85 +++++++
.../FlashRescueBoardCommon.c | 236 ++++++++++++++++++
.../FlashRescueBoardPei/FlashRescueBoardPei.c | 211 ++++++++++++++++
.../FlashRescueBoardPei.inf | 53 ++++
.../Include/EarlySpiFlashRescueFeature.dsc | 34 +++
.../Include/PostMemory.fdf | 8 +
.../Include/Ppi/FeatureInMemory.h | 23 ++
.../Include/PreMemory.fdf | 8 +
.../EarlySpiFlashRescueFeaturePkg/Readme.md | 119 +++++++++
16 files changed, 883 insertions(+)
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dsc
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoard.h
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardCommon.c
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.c
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.inf
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/EarlySpiFlashRescueFeature.dsc
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/Ppi/FeatureInMemory.h
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PreMemory.fdf
create mode 100644 Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Readme.md
diff --git a/Features/Intel/AdvancedFeaturePkg/AdvancedFeaturePkg.dsc b/Features/Intel/AdvancedFeaturePkg/AdvancedFeaturePkg.dsc
index 63b36f4c0f7d..3847c39b68ed 100644
--- a/Features/Intel/AdvancedFeaturePkg/AdvancedFeaturePkg.dsc
+++ b/Features/Intel/AdvancedFeaturePkg/AdvancedFeaturePkg.dsc
@@ -50,6 +50,7 @@
gAcpiDebugFeaturePkgTokenSpaceGuid.PcdAcpiDebugFeatureEnable |TRUE
gAcpiDebugFeaturePkgTokenSpaceGuid.PcdUseSmmVersion |FALSE
gBeepDebugFeaturePkgTokenSpaceGuid.PcdBeepDebugFeatureEnable |TRUE
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable |TRUE
gPostCodeDebugFeaturePkgTokenSpaceGuid.PcdPostCodeDebugFeatureEnable |TRUE
gUsb3DebugFeaturePkgTokenSpaceGuid.PcdUsb3DebugFeatureEnable |TRUE
diff --git a/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeatures.dsc b/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeatures.dsc
index 804aab89bc1b..f1fc643394a3 100644
--- a/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeatures.dsc
+++ b/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeatures.dsc
@@ -21,6 +21,10 @@
!include BeepDebugFeaturePkg/Include/BeepDebugFeature.dsc
!endif
+!if gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable == TRUE
+ !include EarlySpiFlashRescueFeaturePkg/Include/EarlySpiFlashRescueFeature.dsc
+!endif
+
!if gPostCodeDebugFeaturePkgTokenSpaceGuid.PcdPostCodeDebugFeatureEnable == TRUE
!include PostCodeDebugFeaturePkg/Include/PostCodeDebugFeature.dsc
!endif
diff --git a/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeaturesPcd.dsc b/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeaturesPcd.dsc
index 56743db239b0..798839a6a228 100644
--- a/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeaturesPcd.dsc
+++ b/Features/Intel/AdvancedFeaturePkg/Include/AdvancedFeaturesPcd.dsc
@@ -22,6 +22,7 @@
#
AcpiDebugFeaturePkg/AcpiDebugFeaturePkg.dec
BeepDebugFeaturePkg/BeepDebugFeaturePkg.dec
+ EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec
PostCodeDebugFeaturePkg/PostCodeDebugFeaturePkg.dec
Usb3DebugFeaturePkg/Usb3DebugFeaturePkg.dec
@@ -66,6 +67,7 @@
gAcpiDebugFeaturePkgTokenSpaceGuid.PcdAcpiDebugFeatureEnable |FALSE
gAcpiDebugFeaturePkgTokenSpaceGuid.PcdUseSmmVersion |FALSE
gBeepDebugFeaturePkgTokenSpaceGuid.PcdBeepDebugFeatureEnable |FALSE
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable |FALSE
gPostCodeDebugFeaturePkgTokenSpaceGuid.PcdPostCodeDebugFeatureEnable |FALSE
gUsb3DebugFeaturePkgTokenSpaceGuid.PcdUsb3DebugFeatureEnable |FALSE
diff --git a/Features/Intel/AdvancedFeaturePkg/Include/PostMemory.fdf b/Features/Intel/AdvancedFeaturePkg/Include/PostMemory.fdf
index 349bdcc49105..0188d1c97293 100644
--- a/Features/Intel/AdvancedFeaturePkg/Include/PostMemory.fdf
+++ b/Features/Intel/AdvancedFeaturePkg/Include/PostMemory.fdf
@@ -22,6 +22,10 @@
!include BeepDebugFeaturePkg/Include/PostMemory.fdf
!endif
+!if gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable == TRUE
+ !include EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf
+!endif
+
!if gPostCodeDebugFeaturePkgTokenSpaceGuid.PcdPostCodeDebugFeatureEnable == TRUE
!include PostCodeDebugFeaturePkg/Include/PostMemory.fdf
!endif
diff --git a/Features/Intel/AdvancedFeaturePkg/Include/PreMemory.fdf b/Features/Intel/AdvancedFeaturePkg/Include/PreMemory.fdf
index b991a5aabf6c..46aa89f0e63f 100644
--- a/Features/Intel/AdvancedFeaturePkg/Include/PreMemory.fdf
+++ b/Features/Intel/AdvancedFeaturePkg/Include/PreMemory.fdf
@@ -22,6 +22,10 @@
!include BeepDebugFeaturePkg/Include/PreMemory.fdf
!endif
+!if gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable == TRUE
+ !include EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf
+!endif
+
!if gPostCodeDebugFeaturePkgTokenSpaceGuid.PcdPostCodeDebugFeatureEnable == TRUE
!include PostCodeDebugFeaturePkg/Include/PreMemory.fdf
!endif
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec
new file mode 100644
index 000000000000..d22a5983b8a3
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec
@@ -0,0 +1,44 @@
+## @file
+# This package provides advanced feature functionality for rescuing SPI flash.
+# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010017
+ PACKAGE_NAME = EarlySpiFlashRescueFeaturePkg
+ PACKAGE_GUID = 605FCBD8-1D5A-4B72-9874-8FD7DD4FDABD
+ PACKAGE_VERSION = 0.1
+
+[Includes]
+ Include
+
+[Guids]
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid = {0x3e9700b8, 0x98e2, 0x4db4, {0x8a, 0x46, 0xfe, 0x10, 0x77, 0x64, 0xe8, 0xd0}}
+
+[PcdsFeatureFlag]
+ ## This PCD specifies whether early rescue PEIM is built.
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable|FALSE|BOOLEAN|0xB0000001
+
+[PcdsFixedAtBuild]
+ ## This PCD specifies the wait timeout value in millisecond to await a userspace.
+ # Default timeout value is 15000 milliseconds.
+ # If user does not want system stall for long time, it can be set to small value.
+ # Delays in 250ms increments between sending HELLO. Less than this deactivates the feature.
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdUserspaceHostWaitTimeout|15000|UINT32|0xB0000002
+
+ ## This PCD specifies the size in bytes of data packets.
+ ## Dependent on implementation layer. Synchronise with userspace, user must not change without support.
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdDataXferPacketSize|64|UINT16|0xB0000003
+
+[Ppis]
+ ## Include/Ppi/FeatureInMemory.h
+ gPeiFlashRescueReadyInMemoryPpiGuid = {0xe5147285, 0x4d34, 0x415e, {0x8e, 0xa8, 0x85, 0xbd, 0xd8, 0xc6, 0x5b, 0xde }}
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dsc b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dsc
new file mode 100644
index 000000000000..5c4857a885d4
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dsc
@@ -0,0 +1,47 @@
+## @file
+# This package provides advanced feature functionality for rescuing SPI flash.
+# This package should only depend on EDK II Core packages, IntelSiliconPkg, and MinPlatformPkg.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ PLATFORM_NAME = EarlySpiFlashRescueFeaturePkg
+ PLATFORM_GUID = E703420D-AEEF-41C5-B8CA-237BE36C64EC
+ PLATFORM_VERSION = 0.1
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/$(PLATFORM_NAME)
+ SUPPORTED_ARCHITECTURES = IA32|X64
+ BUILD_TARGETS = DEBUG|RELEASE|NOOPT
+ SKUID_IDENTIFIER = DEFAULT
+ PEI_ARCH = IA32
+ DXE_ARCH = X64
+
+[Packages]
+ MinPlatformPkg/MinPlatformPkg.dec
+
+#
+# MinPlatform common include for required feature PCD
+# These PCD must be set before the core include files, CoreCommonLib,
+# CorePeiLib, and CoreDxeLib.
+#
+!include MinPlatformPkg/Include/Dsc/MinPlatformFeaturesPcd.dsc.inc
+
+#
+# Include common libraries
+#
+!include MinPlatformPkg/Include/Dsc/CoreCommonLib.dsc
+!include MinPlatformPkg/Include/Dsc/CorePeiLib.dsc
+!include MinPlatformPkg/Include/Dsc/CoreDxeLib.dsc
+
+#
+# This package always builds the feature.
+#
+!include Include/EarlySpiFlashRescueFeature.dsc
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoard.h b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoard.h
new file mode 100644
index 000000000000..ecc0e16de9e0
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoard.h
@@ -0,0 +1,85 @@
+/** @file
+ Early SPI flash rescue protocol - board implementation.
+
+ Copyright (c) 2022, Baruch Binyamin Doron.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef FLASH_RESCUE_BOARD_H
+#define FLASH_RESCUE_BOARD_H
+
+#include <Base.h>
+#include <Protocol/Spi2.h>
+
+#define SIZE_BLOCK 4096
+#define MS_IN_SECOND 1000
+#define NS_IN_SECOND (1000 * 1000 * 1000)
+
+#define EARLY_FLASH_RESCUE_PROTOCOL_VERSION 0.50
+#define EARLY_FLASH_RESCUE_COMMAND_HELLO 0x10
+#define EARLY_FLASH_RESCUE_COMMAND_CHECKSUM 0x11
+#define EARLY_FLASH_RESCUE_COMMAND_READ 0x12
+#define EARLY_FLASH_RESCUE_COMMAND_WRITE 0x13
+#define EARLY_FLASH_RESCUE_COMMAND_RESET 0x14
+#define EARLY_FLASH_RESCUE_COMMAND_EXIT 0x15
+
+#pragma pack(push, 1)
+typedef struct {
+ UINT8 Command;
+ UINT16 BlockNumber; // This 4K block in BIOS region
+} EARLY_FLASH_RESCUE_COMMAND;
+
+typedef struct {
+ UINT8 Acknowledge; // Usually, ACK == 0x01
+ UINT16 Size; // OPTIONAL?
+} EARLY_FLASH_RESCUE_RESPONSE;
+#pragma pack(pop)
+
+/**
+ Returns a pointer to the PCH SPI PPI.
+
+ @return Pointer to PCH_SPI2_PPI If an instance of the PCH SPI PPI is found
+ @return NULL If an instance of the PCH SPI PPI is not found
+
+**/
+PCH_SPI2_PROTOCOL *
+GetSpiPpi (
+ VOID
+ );
+
+/**
+ * Perform system reset to start this firmware.
+**/
+VOID
+EFIAPI
+PerformSystemReset (
+ VOID
+ );
+
+/**
+ * Send HELLO command to an awaiting userspace.
+ * Permit 15s for response.
+ *
+ * @return EFI_SUCCESS Command acknowledged.
+ * @return EFI_TIMEOUT Command timed-out.
+**/
+EFI_STATUS
+EFIAPI
+SendHelloPacket (
+ VOID
+ );
+
+/**
+ * Perform flash.
+ *
+ * @return EFI_SUCCESS Successful flash.
+ * @return EFI_DEVICE_ERROR Successful flash.
+ * @return EFI_TIMEOUT Await command timed-out.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlash (
+ VOID
+ );
+
+#endif
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardCommon.c b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardCommon.c
new file mode 100644
index 000000000000..165636e34134
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardCommon.c
@@ -0,0 +1,236 @@
+/** @file
+ Early SPI flash rescue protocol - board implementation.
+
+ Copyright (c) 2022, Baruch Binyamin Doron.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/SpiLib.h>
+#include <Library/TimerLib.h>
+#include <Protocol/Spi2.h>
+#include "FlashRescueBoard.h"
+
+// TODO: Appropriate size
+static UINT16 XferBlockSize = FixedPcdGet16 (PcdDataXferPacketSize);
+
+/**
+ * Send HELLO command to an awaiting userspace.
+ *
+ * @return EFI_SUCCESS Command acknowledged.
+ * @return EFI_TIMEOUT Command timed-out.
+**/
+EFI_STATUS
+EFIAPI
+SendHelloPacket (
+ VOID
+ )
+{
+ UINT32 WaitTimeout;
+ EARLY_FLASH_RESCUE_COMMAND CommandPacket;
+ UINTN TimeCounter;
+ EARLY_FLASH_RESCUE_RESPONSE ResponsePacket;
+
+ WaitTimeout = FixedPcdGet32 (PcdUserspaceHostWaitTimeout);
+
+ // TODO: Consider sending a total `BlockNumber`?
+ CommandPacket.Command = EARLY_FLASH_RESCUE_COMMAND_HELLO;
+
+ for (TimeCounter = 0; TimeCounter < WaitTimeout; TimeCounter += 250) {
+ // Maybe packet was not in FIFO
+ SerialPortWrite ((UINT8 *)&CommandPacket, sizeof (CommandPacket));
+
+ SerialPortRead ((UINT8 *)&ResponsePacket, sizeof (ResponsePacket));
+ if (ResponsePacket.Acknowledge == 1) {
+ return EFI_SUCCESS;
+ }
+
+ MicroSecondDelay (250 * MS_IN_SECOND);
+ }
+
+ return EFI_TIMEOUT;
+}
+
+/**
+ * Send the requested block CRC to an awaiting userspace.
+ * - TODO: NACK blocks as necessary
+**/
+VOID
+EFIAPI
+SendBlockChecksum (
+ UINTN BlockNumber
+ )
+{
+ PCH_SPI2_PROTOCOL *Spi2Ppi;
+ UINTN Address;
+ UINT8 BlockData[SIZE_BLOCK];
+ EFI_STATUS Status;
+ UINT32 Crc;
+ EARLY_FLASH_RESCUE_RESPONSE ResponsePacket;
+
+ Spi2Ppi = GetSpiPpi ();
+ if (Spi2Ppi == NULL) {
+ return;
+ }
+
+ // `BlockNumber` starting in BIOS region
+ Address = BlockNumber * SIZE_BLOCK;
+
+ Status = Spi2Ppi->FlashRead (
+ Spi2Ppi,
+ &gFlashRegionBiosGuid,
+ Address,
+ SIZE_BLOCK,
+ BlockData
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Crc = CalculateCrc32 (BlockData, SIZE_BLOCK);
+
+ // Now, acknowledge userspace request and send block CRC
+ ResponsePacket.Acknowledge = 1;
+ SerialPortWrite ((UINT8 *)&ResponsePacket, sizeof (ResponsePacket));
+ SerialPortWrite ((UINT8 *)&Crc, sizeof (Crc));
+}
+
+/**
+ * Write the requested SPI flash block.
+ * - TODO: NACK blocks as necessary
+**/
+VOID
+EFIAPI
+WriteBlock (
+ UINTN BlockNumber
+ )
+{
+ PCH_SPI2_PROTOCOL *Spi2Ppi;
+ UINTN Address;
+ UINT8 BlockData[SIZE_BLOCK];
+ EARLY_FLASH_RESCUE_RESPONSE ResponsePacket;
+ VOID *XferBlock;
+ UINTN Index;
+ EFI_STATUS Status;
+
+ Spi2Ppi = GetSpiPpi ();
+ if (Spi2Ppi == NULL) {
+ return;
+ }
+
+ // `BlockNumber` starting in BIOS region
+ Address = BlockNumber * SIZE_BLOCK;
+
+ // Acknowledge userspace command and retrieve block
+ ResponsePacket.Acknowledge = 1;
+ SerialPortWrite ((UINT8 *)&ResponsePacket, sizeof (ResponsePacket));
+
+ // Start streaming block
+ XferBlock = BlockData;
+ for (Index = 0; Index < SIZE_BLOCK; Index += XferBlockSize) {
+ // FIXME: This will incur some penalty, but we must wait
+ // - Still debugging timing parameters, especially at higher baudrate
+ // - Possible optimisation: Shorter stall if SerialPortPoll()
+ MicroSecondDelay (33 * MS_IN_SECOND);
+
+ SerialPortRead (XferBlock, XferBlockSize);
+ XferBlock += XferBlockSize;
+
+ // FIXME: This will incur some penalty, but userspace must wait
+ ResponsePacket.Acknowledge = 1;
+ SerialPortWrite ((UINT8 *)&ResponsePacket, sizeof (ResponsePacket));
+ }
+
+ // SPI flash is is fairly durable, but determine when erase is necessary.
+ Status = Spi2Ppi->FlashErase (
+ Spi2Ppi,
+ &gFlashRegionBiosGuid,
+ Address,
+ SIZE_BLOCK
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ Status = Spi2Ppi->FlashWrite (
+ Spi2Ppi,
+ &gFlashRegionBiosGuid,
+ Address,
+ SIZE_BLOCK,
+ BlockData
+ );
+}
+
+/**
+ * Perform flash.
+ *
+ * @return EFI_SUCCESS Successful flash.
+ * @return EFI_DEVICE_ERROR Initialise SPI service failed.
+ * @return EFI_TIMEOUT Await command timed-out.
+**/
+EFI_STATUS
+EFIAPI
+PerformFlash (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT8 NoUserspaceExit;
+ UINT64 LastServicedTimeNs;
+ EARLY_FLASH_RESCUE_COMMAND CommandPacket;
+
+ //
+ // TODO: Library must reinstall its PPI, backed by NEM/DRAM
+ //
+ Status = SpiServiceInit ();
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ // Userspace-side orchestrates procedure, so no looping over blocks
+ NoUserspaceExit = 1;
+
+ LastServicedTimeNs = GetTimeInNanoSecond (GetPerformanceCounter ());
+ while (NoUserspaceExit) {
+ // Check if there is command waiting for us
+ if (SerialPortPoll ()) {
+ // Stall a tiny bit, in-case the remainder of the packet is flushing
+ MicroSecondDelay (10 * MS_IN_SECOND);
+
+ SerialPortRead ((UINT8 *)&CommandPacket, sizeof (CommandPacket));
+ switch (CommandPacket.Command) {
+ case EARLY_FLASH_RESCUE_COMMAND_CHECKSUM:
+ SendBlockChecksum (CommandPacket.BlockNumber);
+ break;
+ case EARLY_FLASH_RESCUE_COMMAND_WRITE:
+ WriteBlock (CommandPacket.BlockNumber);
+ break;
+ case EARLY_FLASH_RESCUE_COMMAND_RESET:
+ PerformSystemReset ();
+ // Permit fallthrough
+ NoUserspaceExit = 0;
+ break;
+ case EARLY_FLASH_RESCUE_COMMAND_EXIT:
+ NoUserspaceExit = 0;
+ break;
+ default:
+ break;
+ }
+
+ LastServicedTimeNs = GetTimeInNanoSecond (GetPerformanceCounter ());
+ }
+
+ if ((GetTimeInNanoSecond (GetPerformanceCounter ()) - LastServicedTimeNs) >=
+ (10ULL * NS_IN_SECOND)) {
+ // This is very bad. SPI flash could be inconsistent
+ // - In CAR there's likely too little memory to stash a backup
+ return EFI_TIMEOUT;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.c b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.c
new file mode 100644
index 000000000000..60013e5538d7
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.c
@@ -0,0 +1,211 @@
+/** @file
+ Early SPI flash rescue protocol - board implementation.
+
+ Copyright (c) 2022, Baruch Binyamin Doron.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiPei.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ResetSystemLib.h>
+#include <Library/SpiLib.h>
+#include <Library/TimerLib.h>
+#include <Ppi/FeatureInMemory.h>
+#include <Ppi/Spi2.h>
+#include "FlashRescueBoard.h"
+
+STATIC CONST EFI_PEI_PPI_DESCRIPTOR mFlashRescueReadyInMemoryPpiList = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gPeiFlashRescueReadyInMemoryPpiGuid,
+ NULL
+};
+
+/**
+ Returns a pointer to the PCH SPI PPI.
+
+ @return Pointer to PCH_SPI2_PPI If an instance of the PCH SPI PPI is found
+ @return NULL If an instance of the PCH SPI PPI is not found
+
+**/
+PCH_SPI2_PPI *
+GetSpiPpi (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ PCH_SPI2_PPI *PchSpi2Ppi;
+
+ Status = PeiServicesLocatePpi (
+ &gPchSpi2PpiGuid,
+ 0,
+ NULL,
+ (VOID **) &PchSpi2Ppi
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ return PchSpi2Ppi;
+}
+
+/**
+ * Perform system reset to start this firmware.
+**/
+VOID
+EFIAPI
+PerformSystemReset (
+ VOID
+ )
+{
+ //
+ // PPI may be unavailable, but do not risk UAF. Must use silicon variant
+ //
+ ResetCold ();
+}
+
+VOID
+InternalPrintVariableData (
+ IN UINT8 *Data8,
+ IN UINTN DataSize
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < DataSize; Index++) {
+ if (Index % 0x10 == 0) {
+ DEBUG ((DEBUG_INFO, "\n%08X:", Index));
+ }
+ DEBUG ((DEBUG_INFO, " %02X", *Data8++));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+ Entry Point function
+
+ @param[in] FileHandle Handle of the file being invoked.
+ @param[in] PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS if it completed successfully.
+ @retval EFI_OUT_OF_RESOURCES if PEIM cannot be reloaded.
+**/
+EFI_STATUS
+EFIAPI
+FlashRescueBoardPeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ VOID *FlashRescueReady;
+ VOID *ThisPeimData;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS PeimCopy;
+ EFI_PEIM_ENTRY_POINT2 PeimEntryPoint;
+
+ //
+ // Second entry: Enter flash loop
+ //
+ Status = PeiServicesLocatePpi (
+ &gPeiFlashRescueReadyInMemoryPpiGuid,
+ 0,
+ NULL,
+ (VOID **)&FlashRescueReady
+ );
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "perform flash now. Time to be quiet\n"));
+
+ Status = PerformFlash ();
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // First entry: Establish communication with board or don't reload
+ //
+ DEBUG ((DEBUG_INFO, "HELLO begins. Re-connect with userspace-side now\n"));
+ MicroSecondDelay (5000 * MS_IN_SECOND);
+
+ Status = SendHelloPacket ();
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Find this PEIM, then obtain a PE context with its data handle
+ //
+ Status = PeiServicesFfsFindSectionData (
+ EFI_SECTION_PE32,
+ FileHandle,
+ &ThisPeimData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+
+ ImageContext.Handle = ThisPeimData;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate memory from NEM or DRAM
+ // - RegisterForShadow() is simpler for DRAM, but simplify code paths
+ //
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES ((UINT32)ImageContext.ImageSize),
+ &PeimCopy
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DEBUG ((DEBUG_INFO, "there are %d pages for us at 0x%x\n", EFI_SIZE_TO_PAGES ((UINT32)ImageContext.ImageSize), PeimCopy));
+
+ //
+ // Load and relocate into the new buffer
+ //
+ ImageContext.ImageAddress = PeimCopy;
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install flag PPI and call entrypoint
+ //
+ PeiServicesInstallPpi (&mFlashRescueReadyInMemoryPpiList);
+ ASSERT_EFI_ERROR (Status);
+DEBUG ((DEBUG_INFO, "ATTN: Spewing the PEIM to be executed before invalidate...\n"));
+ InternalPrintVariableData ((UINT8 *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ DEBUG ((DEBUG_INFO, "ATTN: Spewing the PEIM to be executed after invalidate. I think this is same...\n"));
+ InternalPrintVariableData ((UINT8 *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+ PeimEntryPoint = (EFI_PEIM_ENTRY_POINT2)(UINTN)ImageContext.EntryPoint;
+ DEBUG ((DEBUG_INFO, "ATTN: Shall jump into our 0x%p entrypoint! ready to go!\n", PeimEntryPoint));
+ Status = PeimEntryPoint (FileHandle, PeiServices);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((DEBUG_INFO, "ATTN: back from 0x%p entrypoint! good !\n", PeimEntryPoint));
+
+ //
+ // Cleanup. It is important that PPIs do not point here
+ //
+ Status = SpiServiceInit ();
+ ASSERT_EFI_ERROR (Status);
+
+ Status = PeiServicesFreePages (
+ PeimCopy,
+ EFI_SIZE_TO_PAGES ((UINT32)ImageContext.ImageSize)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.inf b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.inf
new file mode 100644
index 000000000000..2bc4ce5e4c26
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.inf
@@ -0,0 +1,53 @@
+## @file
+# Early SPI flash rescue protocol - board implementation.
+#
+# Copyright (c) 2022, Baruch Binyamin Doron.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = FlashRescueBoardPei
+ FILE_GUID = D1B51B35-E01A-4633-991F-E1B639B8D3AA
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 0.50
+ ENTRY_POINT = FlashRescueBoardPeiEntryPoint
+
+[Sources]
+ FlashRescueBoardPei.c
+ FlashRescueBoardCommon.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EarlySpiFlashRescueFeaturePkg/EarlySpiFlashRescueFeaturePkg.dec
+ IntelSiliconPkg/IntelSiliconPkg.dec
+ KabylakeSiliconPkg/SiPkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ PeiServicesLib
+ BaseLib
+ BaseMemoryLib
+ CacheMaintenanceLib
+ DebugLib
+ MemoryAllocationLib
+ PeCoffLib
+ ResetSystemLib
+ SerialPortLib
+ SpiLib
+ TimerLib
+
+[Ppis]
+ gPeiFlashRescueReadyInMemoryPpiGuid
+
+[Guids]
+ gFlashRegionBiosGuid
+
+[Pcd]
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdUserspaceHostWaitTimeout
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdDataXferPacketSize
+
+[Depex]
+ TRUE
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/EarlySpiFlashRescueFeature.dsc b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/EarlySpiFlashRescueFeature.dsc
new file mode 100644
index 000000000000..938c0740c7ce
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/EarlySpiFlashRescueFeature.dsc
@@ -0,0 +1,34 @@
+## @file
+# This is a build description file for the SPI flash rescue advanced feature.
+# This file should be included into another package DSC file to build this feature.
+#
+# The DEC files are used by the utilities that parse DSC and
+# INF files to generate AutoGen.c and AutoGen.h files
+# for the build infrastructure.
+#
+# Copyright (c) 2019 - 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+!ifndef $(PEI_ARCH)
+ !error "PEI_ARCH must be specified to build this feature!"
+!endif
+!ifndef $(DXE_ARCH)
+ !error "DXE_ARCH must be specified to build this feature!"
+!endif
+
+################################################################################
+#
+# Components section - list of all components needed by this feature.
+#
+################################################################################
+[Components.IA32]
+ EarlySpiFlashRescueFeaturePkg/FlashRescueBoardPei/FlashRescueBoardPei.inf
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf
new file mode 100644
index 000000000000..6f6e94a51cd3
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PostMemory.fdf
@@ -0,0 +1,8 @@
+## @file
+# FDF file for post-memory modules that enable USB3 Debug
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/Ppi/FeatureInMemory.h b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/Ppi/FeatureInMemory.h
new file mode 100644
index 000000000000..1f68c4abd423
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/Ppi/FeatureInMemory.h
@@ -0,0 +1,23 @@
+/** @file
+ This file declares that this feature is relocated into memory from XIP.
+
+ This PPI is published by the feature PEIM after relocation. There is no
+ interface, it is used as a global variable. This is necessary to mitigate
+ possible bugs from flashing over XIP code.
+
+ Copyright (c) 2022, Baruch Binyamin Doron.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __FEATURE_IN_MEMORY_H__
+#define __FEATURE_IN_MEMORY_H__
+
+#define PEI_FLASH_RESCUE_READY_IN_MEMORY_PPI_GUID \
+ { \
+ 0xe5147285, 0x4d34, 0x415e, {0x8e, 0xa8, 0x85, 0xbd, 0xd8, 0xc6, 0x5b, 0xde } \
+ }
+
+extern EFI_GUID gPeiFlashRescueReadyInMemoryPpiGuid;
+
+#endif
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PreMemory.fdf b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PreMemory.fdf
new file mode 100644
index 000000000000..28441c0b9ad0
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Include/PreMemory.fdf
@@ -0,0 +1,8 @@
+## @file
+# FDF file for pre-memory modules that enable USB3 Debug.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
diff --git a/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Readme.md b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Readme.md
new file mode 100644
index 000000000000..72d399f4ed40
--- /dev/null
+++ b/Features/Intel/Debugging/EarlySpiFlashRescueFeaturePkg/Readme.md
@@ -0,0 +1,119 @@
+# Overview
+* **Feature Name:** Early SPI Flash Rescue
+* **PI Phase(s) Supported:** PEI
+* **SMM Required?** No
+
+More Information:
+* [GitHub repo](https://github.com/benjamindoron/early_flash_rescue)
+
+## Purpose
+The Early SPI Flash Rescue feature enables the use of a serial port to
+rescue systems from broken firmware by delivering an update image to flash.
+With an appropriate serial port library, this is an important capability in
+firmware development, as debugging broken images on laptops is inefficient
+and wastes the developer's time on tedium. Now, simply flash the image under
+test, retrieve the broken debug log, then reflash another image. Even before
+permanent memory, it is assumed that the right serial port could complete
+this task in a few minutes. Presently, optimisation is underway to reduce the
+time for even slow serial ports down from 30 minutes and make this less a
+mere proof of concept.
+
+The feature is intended to be used with the userspace-side [here](https://github.com/benjamindoron/early_flash_rescue/tree/main/flash_rescue_userspace)
+presently implemented for POSIX Linux.
+
+# High-Level Theory of Operation
+*_TODO_*
+A description of how the device works at a high-level.
+
+The description should not be constrained to implementation details but provide a simple mental model of how the
+feature is supposed to work.
+
+## Firmware Volumes
+It is the user's responsibility to configure where the module is located.
+PEI APRIORI (MinPlatform PreMem BootFV) is recommended, but post-mem FVs
+are also expected.
+
+## Modules
+* EarlyFlashRescueBoardPei
+
+## <Module Name>
+*_TODO_*
+Each module in the feature should have a section that describes the module in a level of detail that is useful
+to better understand the module source code.
+
+## <Library Name>
+*_TODO_*
+Each library in the feature should have a section that describes the library in a level of detail that is useful
+to better understand the library source code.
+
+## Key Functions
+*_TODO_*
+A bulleted list of key functions for interacting with the feature.
+
+Not all features need to be listed. Only functions exposed through external interfaces that are important for feature
+users to be aware of.
+
+## Configuration
+*_TODO_*
+Information that is useful for configuring the feature.
+
+Not all configuration options need to be listed. This section is used to provide more background on configuration
+options than possible elsewhere.
+
+## Data Flows
+*_TODO_*
+Architecturally defined data structures and flows for the feature.
+
+## Control Flows
+*_TODO_*
+Key control flows for the feature.
+
+## Build Flows
+*_TODO_*
+Any special build flows should be described in this section.
+
+This is particularly useful for features that use custom build tools or require non-standard tool configuration. If the
+standard flow in the feature package template is used, this section may be empty.
+
+## Test Point Results
+No test points implemented
+
+## Functional Exit Criteria
+*_TODO_*
+The testable functionality for the feature.
+
+This section should provide an ordered list of criteria that a board integrator can reference to ensure the feature is
+functional on their board.
+
+## TODO: Feature Enabling Checklist
+* In the board DSC file, enable the feature
+```
+[PcdsFeatureFlag]
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdFlashRescueFeatureEnable|TRUE
+```
+* In the board FDF file, insert the module into FV (and APRIORI)
+```
+APRIORI PEI {
+ # Optionally, other modules prepended/appended...
+ INF EarlySpiFlashRescueFeaturePkg/EarlyFlashRescueBoardPei/EarlyFlashRescueBoardPei.inf
+}
+
+INF EarlySpiFlashRescueFeaturePkg/EarlyFlashRescueBoardPei/EarlyFlashRescueBoardPei.inf
+```
+
+
+## Performance Impact
+A general expectation for the impact on overall boot performance due to using this feature.
+
+This section is expected to provide guidance on:
+* How to estimate performance impact due to the feature
+* How to measure performance impact of the feature
+* How to manage performance impact of the feature
+
+## Common Optimizations
+* In the board DSC file, tune the timeout value and packet size
+```
+[PcdsFixedAtBuild]
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdUserspaceHostWaitTimeout|15000
+ gEarlySpiFlashRescueFeaturePkgTokenSpaceGuid.PcdDataXferPacketSize|64
+```
--
2.37.2
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2022-09-06 17:54 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-09-06 17:54 [edk2-devel][edk2-platforms][PATCH v1] EarlySpiFlashRescueFeaturePkg: Initial commit of new feature Benjamin Doron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox