This replaces the EmuVariableRuntime driver (which loses its memory at reset) with the real VariableRuntimeDxe runtime driver backed by the SPI flash which is accessed via the SCP.
This involves keeping a copy of the varstore contents in memory, and keeping it in sync with the Write() and Erase() commands that are issued via the firmware volume protocol.
Only mildly tested. Not tested yet under the OS.
Ard Biesheuvel (4): Platforms/AMD/Styx: implement SPI flash runtime driver to back the varstore Platforms/AMD/Styx: reshuffle flash layout and add variable store region Platforms/AMD/Styx: reallocate the in-memory copy of the varstore FV Platforms/AMD/Styx: switch to the real variable runtime driver
Platforms/AMD/Styx/AmdStyx.dec | 6 + Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc | 14 +- Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf | 10 +- Platforms/AMD/Styx/Common/Varstore.fdf.inc | 70 +++ Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c | 503 ++++++++++++++++++++ Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf | 63 +++ Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c | 41 ++ Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf | 9 + Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc | 15 +- Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf | 10 +- 10 files changed, 729 insertions(+), 12 deletions(-) create mode 100644 Platforms/AMD/Styx/Common/Varstore.fdf.inc create mode 100644 Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c create mode 100644 Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf
This implements a firmware volume block I/O protocol driver on top of the SPI flash that is exposed by the SCP. Since the generic FTW and variable drivers cannot deal with non-memorymapped flash, this driver uses a RuntimeServicesData buffer to expose the varstore slice of the SPI flash, and keeps it in sync when the Write() or Erase() methods are called.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- Platforms/AMD/Styx/AmdStyx.dec | 6 + Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c | 503 ++++++++++++++++++++ Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf | 63 +++ 3 files changed, 572 insertions(+)
diff --git a/Platforms/AMD/Styx/AmdStyx.dec b/Platforms/AMD/Styx/AmdStyx.dec index 0ce16cb3baff..3e5f5e8a8f2d 100644 --- a/Platforms/AMD/Styx/AmdStyx.dec +++ b/Platforms/AMD/Styx/AmdStyx.dec @@ -112,3 +112,9 @@ gAmdStyxTokenSpaceGuid.PcdParkingProtocolBase|0x8000E80000|UINT64|0x000b0001 gAmdStyxTokenSpaceGuid.PcdParkingProtocolSize|0x0000008000|UINT64|0x000b0002
+ # The original offset in memory of the NV store firmware volume, before + # relocating it to a dynamically allocated buffer. We need this to correlate + # flash accesses to the in-memory copy with LBAs in the actual SPI flash + gAmdStyxTokenSpaceGuid.PcdFlashNvStorageOriginalBase|0|UINT64|0x000c0000 + # block size to use when invoking the ISCP FV methods + gAmdStyxTokenSpaceGuid.PcdFlashNvStorageBlockSize|0x1000|UINT32|0x000c0001 diff --git a/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c b/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c new file mode 100644 index 000000000000..e27d9afd6c22 --- /dev/null +++ b/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.c @@ -0,0 +1,503 @@ +/** @file + + FV block I/O protocol driver for Styx SPI flash exposed via ISCP + + Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR> + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include <PiDxe.h> + +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiRuntimeLib.h> + +#include <Protocol/AmdIscpDxeProtocol.h> +#include <Protocol/FirmwareVolumeBlock.h> + +// TODO: replace with FixedPcdGet64 (PcdFdBaseAddress) once we have updated +// the .FDF to let STYX_EFI.fd cover the entire SPI flash +#define SPI_BASE 0x8000C80000UL +#define BLOCK_SIZE (FixedPcdGet32 (PcdFlashNvStorageBlockSize)) + +STATIC AMD_ISCP_DXE_PROTOCOL *mIscpDxeProtocol; +STATIC EFI_HANDLE mStyxSpiFvHandle; + +STATIC EFI_EVENT mVirtualAddressChangeEvent; + +STATIC UINT64 mNvStorageBase; +STATIC UINT64 mNvStorageLbaOffset; + +STATIC CONST UINT64 mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize); + + +/** + Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE. + + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + It convers pointer to new virtual address. + + @param Event Event whose notification function is being invoked. + @param Context Pointer to the notification function's context. + +**/ +STATIC +VOID +EFIAPI +VariableClassAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EfiConvertPointer (0x0, (VOID **)&mIscpDxeProtocol); + EfiConvertPointer (0x0, (VOID **)&mNvStorageBase); +} + +/** + The GetAttributes() function retrieves the attributes and + current settings of the block. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the + attributes and current settings are + returned. Type EFI_FVB_ATTRIBUTES_2 is defined + in EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were + returned. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled + EFI_FVB2_READ_STATUS | // Reads are currently enabled + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled + EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be enabled + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped + EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1') + + return EFI_SUCCESS; +} + +/** + The SetAttributes() function sets configurable firmware volume + attributes and returns the new settings of the firmware volume. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Attributes On input, Attributes is a pointer to + EFI_FVB_ATTRIBUTES_2 that contains the + desired firmware volume settings. On + successful return, it contains the new + settings of the firmware volume. Type + EFI_FVB_ATTRIBUTES_2 is defined in + EFI_FIRMWARE_VOLUME_HEADER. + + @retval EFI_SUCCESS The firmware volume attributes were returned. + + @retval EFI_INVALID_PARAMETER The attributes requested are in + conflict with the capabilities + as declared in the firmware + volume header. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + return EFI_SUCCESS; // ignore for now +} + +/** + The GetPhysicalAddress() function retrieves the base address of + a memory-mapped firmware volume. This function should be called + only for memory-mapped firmware volumes. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Address Pointer to a caller-allocated + EFI_PHYSICAL_ADDRESS that, on successful + return from GetPhysicalAddress(), contains the + base address of the firmware volume. + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_UNSUPPORTED The firmware volume is not memory mapped. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase; + return EFI_SUCCESS; +} + +/** + The GetBlockSize() function retrieves the size of the requested + block. It also returns the number of additional blocks with + the identical size. The GetBlockSize() function is used to + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER). + + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba Indicates the block for which to return the size. + + @param BlockSize Pointer to a caller-allocated UINTN in which + the size of the block is returned. + + @param NumberOfBlocks Pointer to a caller-allocated UINTN in + which the number of consecutive blocks, + starting with Lba, is returned. All + blocks in this range have a size of + BlockSize. + + + @retval EFI_SUCCESS The firmware volume base address was returned. + + @retval EFI_INVALID_PARAMETER The requested LBA is out of range. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumberOfBlocks + ) +{ + *BlockSize = BLOCK_SIZE; + *NumberOfBlocks = mNvStorageSize / BLOCK_SIZE - (UINTN)Lba; + + return EFI_SUCCESS; +} + +/** + Reads the specified number of bytes into a buffer from the specified block. + + The Read() function reads the requested number of bytes from the + requested block and stores them in the provided buffer. + Implementations should be mindful that the firmware volume + might be in the ReadDisabled state. If it is in this state, + the Read() function must return the status code + EFI_ACCESS_DENIED without modifying the contents of the + buffer. The Read() function must also prevent spanning block + boundaries. If a read is requested that would span a block + boundary, the read must read up to the boundary but not + beyond. The output parameter NumBytes must be set to correctly + indicate the number of bytes actually read. The caller must be + aware that a read may be partially completed. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index + from which to read. + + @param Offset Offset into the block at which to begin reading. + + @param NumBytes Pointer to a UINTN. At entry, *NumBytes + contains the total size of the buffer. At + exit, *NumBytes contains the total number of + bytes read. + + @param Buffer Pointer to a caller-allocated buffer that will + be used to hold the data that is read. + + @retval EFI_SUCCESS The firmware volume was read successfully, + and contents are in Buffer. + + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA + boundary. On output, NumBytes + contains the total number of bytes + returned in Buffer. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + ReadDisabled state. + + @retval EFI_DEVICE_ERROR The block device is not + functioning correctly and could + not be read. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN OUT UINT8 *Buffer + ) +{ + VOID *Base; + + if (Offset + *NumBytes > BLOCK_SIZE) { + return EFI_BAD_BUFFER_SIZE; + } + + Base = (VOID *)mNvStorageBase + Lba * BLOCK_SIZE + Offset; + + // + // Copy the data from the in-memory image + // + CopyMem (Buffer, Base, *NumBytes); + + DEBUG_CODE_BEGIN (); + EFI_STATUS Status; + + if (!EfiAtRuntime ()) { + Lba += mNvStorageLbaOffset; + Status = mIscpDxeProtocol->AmdExecuteLoadFvBlockDxe (mIscpDxeProtocol, + Lba * BLOCK_SIZE + Offset, Buffer, *NumBytes); + ASSERT_EFI_ERROR (Status); + + ASSERT (CompareMem (Base, Buffer, *NumBytes) == 0); + } + DEBUG_CODE_END (); + + return EFI_SUCCESS; +} + +/** + Writes the specified number of bytes from the input buffer to the block. + + The Write() function writes the specified number of bytes from + the provided buffer to the specified block and offset. If the + firmware volume is sticky write, the caller must ensure that + all the bits of the specified range to write are in the + EFI_FVB_ERASE_POLARITY state before calling the Write() + function, or else the result will be unpredictable. This + unpredictability arises because, for a sticky-write firmware + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY + state but cannot flip it back again. Before calling the + Write() function, it is recommended for the caller to first call + the EraseBlocks() function to erase the specified block to + write. A block erase cycle will transition bits from the + (NOT)EFI_FVB_ERASE_POLARITY state back to the + EFI_FVB_ERASE_POLARITY state. Implementations should be + mindful that the firmware volume might be in the WriteDisabled + state. If it is in this state, the Write() function must + return the status code EFI_ACCESS_DENIED without modifying the + contents of the firmware volume. The Write() function must + also prevent spanning block boundaries. If a write is + requested that spans a block boundary, the write must store up + to the boundary but not beyond. The output parameter NumBytes + must be set to correctly indicate the number of bytes actually + written. The caller must be aware that a write may be + partially completed. All writes, partial or otherwise, must be + fully flushed to the hardware before the Write() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param Lba The starting logical block index to write to. + + @param Offset Offset into the block at which to begin writing. + + @param NumBytes The pointer to a UINTN. At entry, *NumBytes + contains the total size of the buffer. At + exit, *NumBytes contains the total number of + bytes actually written. + + @param Buffer The pointer to a caller-allocated buffer that + contains the source for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully. + + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an + LBA boundary. On output, NumBytes + contains the total number of bytes + actually written. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + WriteDisabled state. + + @retval EFI_DEVICE_ERROR The block device is malfunctioning + and could not be written. + + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + VOID *Base; + + if (Offset + *NumBytes > BLOCK_SIZE) { + return EFI_BAD_BUFFER_SIZE; + } + + Base = (VOID *)mNvStorageBase + Lba * BLOCK_SIZE + Offset; + + Lba += mNvStorageLbaOffset; + Status = mIscpDxeProtocol->AmdExecuteUpdateFvBlockDxe (mIscpDxeProtocol, + Lba * BLOCK_SIZE + Offset, Buffer, *NumBytes); + if (!EFI_ERROR (Status)) { + // + // Copy the data we just wrote to the in-memory copy of the + // firmware volume + // + CopyMem (Base, Buffer, *NumBytes); + } + return Status; +} + +/** + Erases and initializes a firmware volume block. + + The EraseBlocks() function erases one or more blocks as denoted + by the variable argument list. The entire parameter list of + blocks must be verified before erasing any blocks. If a block is + requested that does not exist within the associated firmware + volume (it has a larger index than the last block of the + firmware volume), the EraseBlocks() function must return the + status code EFI_INVALID_PARAMETER without modifying the contents + of the firmware volume. Implementations should be mindful that + the firmware volume might be in the WriteDisabled state. If it + is in this state, the EraseBlocks() function must return the + status code EFI_ACCESS_DENIED without modifying the contents of + the firmware volume. All calls to EraseBlocks() must be fully + flushed to the hardware before the EraseBlocks() service + returns. + + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL + instance. + + @param ... The variable argument list is a list of tuples. + Each tuple describes a range of LBAs to erase + and consists of the following: + - An EFI_LBA that indicates the starting LBA + - A UINTN that indicates the number of blocks to + erase. + + The list is terminated with an + EFI_LBA_LIST_TERMINATOR. For example, the + following indicates that two ranges of blocks + (5-7 and 10-11) are to be erased: EraseBlocks + (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR); + + @retval EFI_SUCCESS The erase request successfully + completed. + + @retval EFI_ACCESS_DENIED The firmware volume is in the + WriteDisabled state. + @retval EFI_DEVICE_ERROR The block device is not functioning + correctly and could not be written. + The firmware device may have been + partially erased. + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed + in the variable argument list do + not exist in the firmware volume. + +**/ +STATIC +EFI_STATUS +StyxSpiFvDxeErase ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This, + ... + ) +{ + VA_LIST Args; + EFI_LBA Start; + UINTN Length; + EFI_STATUS Status; + + VA_START (Args, This); + + for (Start = VA_ARG (Args, EFI_LBA); + Start != EFI_LBA_LIST_TERMINATOR; + Start = VA_ARG (Args, EFI_LBA)) { + Start += mNvStorageLbaOffset; + Length = VA_ARG (Args, UINTN); + Status = mIscpDxeProtocol->AmdExecuteEraseFvBlockDxe (mIscpDxeProtocol, + (Start + mNvStorageLbaOffset) * BLOCK_SIZE, + Length * BLOCK_SIZE); + if (!EFI_ERROR (Status)) { + SetMem64 ((VOID *)mNvStorageBase + Start * BLOCK_SIZE, + Length * BLOCK_SIZE, ~0UL); + } + } + + VA_END (Args); + + return EFI_SUCCESS; +} + +STATIC +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mStyxSpiFvProtocol = { + StyxSpiFvDxeGetAttributes, + StyxSpiFvDxeSetAttributes, + StyxSpiFvDxeGetPhysicalAddress, + StyxSpiFvDxeGetBlockSize, + StyxSpiFvDxeRead, + StyxSpiFvDxeWrite, + StyxSpiFvDxeErase +}; + +EFI_STATUS +EFIAPI +StyxSpiFvDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64); + mNvStorageLbaOffset = (FixedPcdGet64 (PcdFlashNvStorageOriginalBase) - + SPI_BASE) / BLOCK_SIZE; + + DEBUG ((EFI_D_INFO, + "%a: Using NV store FV in-memory copy at 0x%lx, LBA offset == 0x%lx\n", + __FUNCTION__, mNvStorageBase, mNvStorageLbaOffset)); + + Status = gBS->LocateProtocol (&gAmdIscpDxeProtocolGuid, NULL, + (VOID **)&mIscpDxeProtocol); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL, TPL_NOTIFY, + VariableClassAddressChangeEvent, NULL, + &gEfiEventVirtualAddressChangeGuid, + &mVirtualAddressChangeEvent); + ASSERT_EFI_ERROR (Status); + + return gBS->InstallMultipleProtocolInterfaces (&mStyxSpiFvHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, &mStyxSpiFvProtocol, + NULL); +} diff --git a/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf b/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf new file mode 100644 index 000000000000..2c1f243c76e9 --- /dev/null +++ b/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf @@ -0,0 +1,63 @@ +#/** @file +# +# Component description file for StyxSpiFvDxe module +# +# Copyright (c) 2016, Linaro Ltd. All rights reserved.<BR> +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = StyxSpiFvDxe + FILE_GUID = F549FC67-C4A6-4E92-B9BA-297E1F82A1A8 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = StyxSpiFvDxeInitialize + +[Sources] + StyxSpiFvDxe.c + +[Packages] + ArmPkg/ArmPkg.dec + AmdModulePkg/AmdModulePkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + OpenPlatformPkg/Platforms/AMD/Styx/AmdStyx.dec + +[LibraryClasses] + BaseLib + DebugLib + UefiLib + UefiDriverEntryPoint + UefiBootServicesTableLib + UefiRuntimeLib + DxeServicesTableLib + +[FixedPcd] + gArmTokenSpaceGuid.PcdFdBaseAddress + + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gAmdStyxTokenSpaceGuid.PcdFlashNvStorageOriginalBase + gAmdStyxTokenSpaceGuid.PcdFlashNvStorageBlockSize + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + +[Protocols] + gAmdIscpDxeProtocolGuid ## CONSUMES + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES + +[Depex] + gAmdIscpDxeProtocolGuid
This reduces the size of the overall image to 2 MB, and reserves the top 128 KB for the variable store and the fault tolerant write working and spare areas.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf | 7 +- Platforms/AMD/Styx/Common/Varstore.fdf.inc | 70 ++++++++++++++++++++ Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf | 7 +- 3 files changed, 78 insertions(+), 6 deletions(-)
diff --git a/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf b/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf index 1d66264fc1b3..e4bdfdb7671c 100644 --- a/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf +++ b/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf @@ -26,12 +26,12 @@
[FD.STYX_EFI] BaseAddress = 0x8000E80000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in NOR Flash. -Size = 0x00300000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device +Size = 0x00200000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device ErasePolarity = 1
# This one is tricky, it must be: BlockSize * NumBlocks = Size BlockSize = 0x00001000 -NumBlocks = 0x300 +NumBlocks = 0x200
################################################################################ # @@ -49,10 +49,11 @@ NumBlocks = 0x300 # ################################################################################
-0x00000000|0x00280000 +0x00000000|0x001E0000 gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize FV = FVMAIN_COMPACT
+!include OpenPlatformPkg/Platforms/AMD/Styx/Common/Varstore.fdf.inc
################################################################################ # diff --git a/Platforms/AMD/Styx/Common/Varstore.fdf.inc b/Platforms/AMD/Styx/Common/Varstore.fdf.inc new file mode 100644 index 000000000000..64b48ef3ed82 --- /dev/null +++ b/Platforms/AMD/Styx/Common/Varstore.fdf.inc @@ -0,0 +1,70 @@ +## @file +# FDF include file with Layout Regions that define an empty variable store. +# +# Copyright (C) 2016, Linaro, Ltd. +# Copyright (C) 2014, Red Hat, Inc. +# Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> +# +# This program and the accompanying materials are licensed and made available +# under the terms and conditions of the BSD License which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR +# IMPLIED. +# +## + +0x001E0000|0x0000F000 +gAmdStyxTokenSpaceGuid.PcdFlashNvStorageOriginalBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize +DATA = { + ## This is the EFI_FIRMWARE_VOLUME_HEADER + # ZeroVector [] + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + # FileSystemGuid: gEfiSystemNvDataFvGuid = + # { 0xFFF12B8D, 0x7696, 0x4C8B, + # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }} + 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C, + 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50, + # FvLength: 0x30000 + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + # Signature "_FVH" # Attributes + 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00, + # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision + 0x48, 0x00, 0x19, 0xF9, 0x00, 0x00, 0x00, 0x02, + # Blockmap[0]: 0xF Blocks * 0x1000 Bytes / Block + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + # Blockmap[1]: End + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ## This is the VARIABLE_STORE_HEADER + # It is compatible with SECURE_BOOT_ENABLE == FALSE as well. + # Signature: gEfiAuthenticatedVariableGuid = + # { 0xaaf32c78, 0x947b, 0x439a, + # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }} + 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, + 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92, + # Size: 0xF000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) - + # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0xefb8 + # This can speed up the Variable Dispatch a bit. + 0xB8, 0xEF, 0x00, 0x00, + # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32 + 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +0x001EF000|0x00001000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize +DATA = { + # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid = + # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} + 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49, + 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95, + # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved + 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF, + # WriteQueueSize: UINT64 + 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} + +0x001F0000|0x00010000 +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize diff --git a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf index 7ff8c89cfde6..dc6585c62d01 100644 --- a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf +++ b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf @@ -26,12 +26,12 @@
[FD.STYX_EFI] BaseAddress = 0x8000E80000|gArmTokenSpaceGuid.PcdFdBaseAddress # The base address of the Firmware in NOR Flash. -Size = 0x00300000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device +Size = 0x00200000|gArmTokenSpaceGuid.PcdFdSize # The size in bytes of the FLASH Device ErasePolarity = 1
# This one is tricky, it must be: BlockSize * NumBlocks = Size BlockSize = 0x00001000 -NumBlocks = 0x300 +NumBlocks = 0x200
################################################################################ # @@ -49,10 +49,11 @@ NumBlocks = 0x300 # ################################################################################
-0x00000000|0x00280000 +0x00000000|0x001E0000 gArmTokenSpaceGuid.PcdFvBaseAddress|gArmTokenSpaceGuid.PcdFvSize FV = FVMAIN_COMPACT
+!include OpenPlatformPkg/Platforms/AMD/Styx/Common/Varstore.fdf.inc
################################################################################ #
Before the DXE core has a chance to overwrite the in-memory copy of the varstore FV, relocate it to a dynamically allocated buffer. Note that, while this allocation is not made from the temporary PEI heap, the bookkeeping involved in calling AllocateAlignedRuntimePages() appears to push the envelope slightly, and so we need to increase the initial stack size (which is actually stack + heap)
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc | 5 ++- Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c | 41 ++++++++++++++++++++ Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf | 9 +++++ Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc | 6 ++- 4 files changed, 59 insertions(+), 2 deletions(-)
diff --git a/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc b/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc index 892068f62025..458b444159fc 100644 --- a/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc +++ b/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc @@ -401,7 +401,7 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2)
# Stacks for MPCores in Normal World gArmPlatformTokenSpaceGuid.PcdCPUCoresStackBase|0x8001680000 - gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x6000 + gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x10000 gArmPlatformTokenSpaceGuid.PcdCPUCoreSecondaryStackSize|0x800
# Stacks for MPCores in Monitor Mode @@ -537,6 +537,9 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2) gAmdModulePkgTokenSpaceGuid.PcdEthMacB|0x02B1B2B3B4B5 !endif
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0x0 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
################################################################################ # diff --git a/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c b/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c index 971e3a193d91..4f7f6bb1c942 100644 --- a/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c +++ b/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.c @@ -24,6 +24,7 @@ #include <PiPei.h>
#include <Library/ArmPlatformLib.h> +#include <Library/BaseMemoryLib.h> #include <Library/DebugLib.h> #include <Library/HobLib.h> #include <Library/MemoryAllocationLib.h> @@ -56,6 +57,44 @@ InitMmu ( } }
+STATIC +VOID +MoveNvStoreImage ( + VOID + ) +{ + VOID *OldBase, *NewBase; + UINTN Size; + + // + // Move the in-memory image of the NV store firmware volume to a dynamically + // allocated buffer. This gets rid of the annoying static memory reservation + // at the base of memory where all other UEFI allocations are near the top. + // + OldBase = (VOID *)FixedPcdGet64 (PcdFlashNvStorageOriginalBase); + + Size = FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize); + + NewBase = AllocateAlignedRuntimePages (EFI_SIZE_TO_PAGES (Size), SIZE_64KB); + ASSERT (NewBase != NULL); + + CopyMem (NewBase, OldBase, Size); + + DEBUG ((EFI_D_INFO, "%a: Relocating NV store FV from %p to %p\n", + __FUNCTION__, OldBase, NewBase)); + + PcdSet64 (PcdFlashNvStorageVariableBase64, (UINT64)NewBase); + + PcdSet64 (PcdFlashNvStorageFtwWorkingBase64, (UINT64)NewBase + + FixedPcdGet32 (PcdFlashNvStorageVariableSize)); + + PcdSet64 (PcdFlashNvStorageFtwSpareBase64, (UINT64)NewBase + + FixedPcdGet32 (PcdFlashNvStorageVariableSize) + + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize)); +} + /*++
Routine Description: @@ -135,5 +174,7 @@ MemoryPeim ( BuildMemoryTypeInformationHob (); }
+ MoveNvStoreImage (); + return EFI_SUCCESS; } diff --git a/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf b/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf index c1cca09da3ff..8b35d9f604be 100644 --- a/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf +++ b/Platforms/AMD/Styx/Library/MemoryInitPei/MemoryInitPeiLib.inf @@ -80,9 +80,18 @@ gAmdStyxTokenSpaceGuid.PcdNsISCPMemoryBase gAmdStyxTokenSpaceGuid.PcdNsISCPMemorySize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize + gAmdStyxTokenSpaceGuid.PcdFlashNvStorageOriginalBase + [Pcd] gArmTokenSpaceGuid.PcdSystemMemoryBase gArmTokenSpaceGuid.PcdSystemMemorySize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64 + [Depex] gAmdStyxPlatInitPpiGuid diff --git a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc index 32d97c017b46..60d1c8ecbbaf 100644 --- a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc +++ b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc @@ -404,7 +404,7 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2)
# Stacks for MPCores in Normal World gArmPlatformTokenSpaceGuid.PcdCPUCoresStackBase|0x8001680000 - gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x6000 + gArmPlatformTokenSpaceGuid.PcdCPUCorePrimaryStackSize|0x10000 gArmPlatformTokenSpaceGuid.PcdCPUCoreSecondaryStackSize|0x800
# Stacks for MPCores in Monitor Mode @@ -549,6 +549,10 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2) gAmdModulePkgTokenSpaceGuid.PcdEthMacB|0x02B1B2B3B4B5 !endif
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|0x0 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0 + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0 +
################################################################################ #
Add the Styx SPI DXE driver to the Cello and OverDrive builds, and replace the emulated variable runtime driver with the real deal.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel ard.biesheuvel@linaro.org --- Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc | 9 ++++++++- Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf | 3 ++- Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc | 9 ++++++++- Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf | 3 ++- 4 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc b/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc index 458b444159fc..7a14a8ea6ed3 100644 --- a/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc +++ b/Platforms/AMD/Styx/CelloBoard/CelloBoard.dsc @@ -614,7 +614,14 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2) # # Environment Variables Protocol # - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { + <LibraryClasses> + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf + TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf + VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf + } + OpenPlatformPkg/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf
# # Iscp support diff --git a/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf b/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf index e4bdfdb7671c..c1df319f9832 100644 --- a/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf +++ b/Platforms/AMD/Styx/CelloBoard/CelloBoard.fdf @@ -125,7 +125,8 @@ READ_LOCK_STATUS = TRUE # # Environment Variables Protocol # - INF MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + INF OpenPlatformPkg/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf
# # Iscp support diff --git a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc index 60d1c8ecbbaf..83c0c81330d2 100644 --- a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc +++ b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.dsc @@ -623,7 +623,14 @@ DEFINE TRANS_CODE = $(EL3_TO_EL2) # # Environment Variables Protocol # - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf { + <LibraryClasses> + AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLibNull.inf + TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf + VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf + NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf + } + OpenPlatformPkg/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf
# # Iscp support diff --git a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf index dc6585c62d01..0770016ce512 100644 --- a/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf +++ b/Platforms/AMD/Styx/OverdriveBoard/OverdriveBoard.fdf @@ -125,7 +125,8 @@ READ_LOCK_STATUS = TRUE # # Environment Variables Protocol # - INF MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariableRuntimeDxe.inf + INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf + INF OpenPlatformPkg/Platforms/AMD/Styx/Drivers/StyxSpiFvDxe/StyxSpiFvDxe.inf
# # Iscp support