From 26aab7effb41957820b1696f27bf9aff632473f0 Mon Sep 17 00:00:00 2001 From: Guo Mang Date: Wed, 3 Aug 2016 09:53:32 +0800 Subject: BraswellPlatformPkg: Move Flash to Common/Flash Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang Reviewed-by: David Wei --- .../Common/Flash/FvbRuntimeDxe/FvbInfo.c | 369 ++++++ .../Common/Flash/FvbRuntimeDxe/FvbRuntimeDxe.inf | 91 ++ .../Common/Flash/FvbRuntimeDxe/FvbService.c | 1226 ++++++++++++++++++++ .../Common/Flash/FvbRuntimeDxe/FvbService.h | 187 +++ .../Common/Flash/FvbRuntimeDxe/FvbServiceDxe.c | 197 ++++ .../Common/Flash/FvbRuntimeDxe/FvbServiceSmm.c | 263 +++++ .../Common/Flash/FvbRuntimeDxe/FvbSmm.inf | 93 ++ .../Common/Flash/FvbRuntimeDxe/FvbSmmCommon.h | 75 ++ .../Common/Flash/FvbRuntimeDxe/FvbSmmDxe.c | 933 +++++++++++++++ .../Common/Flash/FvbRuntimeDxe/FvbSmmDxe.h | 231 ++++ .../Common/Flash/FvbRuntimeDxe/FvbSmmDxe.inf | 57 + .../Common/Flash/SpiDeviceDxe/SpiDevice.c | 659 +++++++++++ .../Common/Flash/SpiDeviceDxe/SpiDevice.h | 211 ++++ .../Common/Flash/SpiDeviceDxe/SpiDeviceDxe.c | 152 +++ .../Common/Flash/SpiDeviceDxe/SpiDeviceDxe.inf | 64 + .../Common/Flash/SpiDeviceDxe/SpiDeviceSmm.c | 222 ++++ .../Common/Flash/SpiDeviceDxe/SpiDeviceSmm.inf | 62 + .../Common/Flash/SpiDeviceDxe/SpiDeviceSmmComm.h | 73 ++ .../Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.c | 437 +++++++ .../Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.inf | 51 + .../Common/Flash/SpiFlashParts/MX25/MX25.c | 208 ++++ .../Common/Flash/SpiFlashParts/MX25/MX25.inf | 41 + .../Common/Flash/SpiFlashParts/W25/W25.c | 192 +++ .../Common/Flash/SpiFlashParts/W25/W25.inf | 41 + 24 files changed, 6135 insertions(+) create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbInfo.c create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbRuntimeDxe.inf create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.c create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.h create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceDxe.c create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceSmm.c create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmm.inf create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmCommon.h create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.c create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.h create mode 100644 BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.inf create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.h create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.inf create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.inf create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmComm.h create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.inf create mode 100644 BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.inf create mode 100644 BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.c create mode 100644 BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.inf (limited to 'BraswellPlatformPkg/Common') diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbInfo.c b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbInfo.c new file mode 100644 index 0000000000..15aae661e9 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbInfo.c @@ -0,0 +1,369 @@ +/** @file + Defines data structure that is the volume header found. + These data is intent to decouple FVB driver with FV header. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include "FvbService.h" + +#define FVB_MEDIA_BLOCK_SIZE PcdGet32(PcdFlashMinEraseSize) + +typedef struct { + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_FIRMWARE_VOLUME_HEADER FvbInfo; + // + //EFI_FV_BLOCK_MAP_ENTRY ExtraBlockMap[n];//n=0 + // + EFI_FV_BLOCK_MAP_ENTRY End[1]; +} EFI_FVB2_MEDIA_INFO; + +// +// This data structure contains a template of all correct FV headers, which is used to restore +// Fv header if it's corrupted. +// +EFI_FVB2_MEDIA_INFO mPlatformFvbMediaInfo[] = { + // + // Main BIOS FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_FIRMWARE_FILE_SYSTEM2_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum, check the FD for the value. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + }, + // + // Systen NvStorage FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + }, + // + // Recovery BIOS FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_FIRMWARE_FILE_SYSTEM2_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + }, + // + // Recovery 2 BIOS FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_FIRMWARE_FILE_SYSTEM2_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + }, + // + // Payload FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_FIRMWARE_FILE_SYSTEM2_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0x60, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + } +}; + +// +// FTW working space and FTW spare space don't have FV header. +// We need create one for them and use it for FVB protocol. +// +EFI_FVB2_MEDIA_INFO mPlatformFtwFvbInfo[] = { + // + // System variable FTW working FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + }, + // + // Systen NV variable FTW spare FVB + // + { + 0, + { + {0,}, //ZeroVector[16] + EFI_SYSTEM_NV_DATA_FV_GUID, + 0, + EFI_FVH_SIGNATURE, + 0x0004feff, // check MdePkg/Include/Pi/PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2 + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY), + 0, //CheckSum which will be calucated dynamically. + 0, //ExtHeaderOffset + {0,}, //Reserved[1] + 2, //Revision + { + { + 0, + 0, + } + } + }, + { + { + 0, + 0 + } + } + } +}; + +EFI_STATUS +GetFtwFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +{ + UINTN Index; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + + // + // Init Fvb data + // + mPlatformFtwFvbInfo[0].BaseAddress = PcdGet32 (PcdFlashNvStorageFtwWorkingBase); + mPlatformFtwFvbInfo[0].FvbInfo.FvLength = PcdGet32 (PcdFlashNvStorageFtwWorkingSize); + mPlatformFtwFvbInfo[0].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFtwFvbInfo[0].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + mPlatformFtwFvbInfo[1].BaseAddress = PcdGet32 (PcdFlashNvStorageFtwSpareBase); + mPlatformFtwFvbInfo[1].FvbInfo.FvLength = PcdGet32 (PcdFlashNvStorageFtwSpareSize); + mPlatformFtwFvbInfo[1].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashNvStorageFtwSpareSize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFtwFvbInfo[1].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashNvStorageFtwSpareSize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + for (Index=0; Index < sizeof (mPlatformFtwFvbInfo)/sizeof (mPlatformFtwFvbInfo[0]); Index += 1) { + if (mPlatformFtwFvbInfo[Index].BaseAddress == FvBaseAddress) { + FvHeader = &mPlatformFtwFvbInfo[Index].FvbInfo; + // + // Update the checksum value of FV header. + // + FvHeader->Checksum = CalculateCheckSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); + + *FvbInfo = FvHeader; + + DEBUG ((EFI_D_INFO, "\nFTW BaseAddr: 0x%lx \n", FvBaseAddress)); + DEBUG ((EFI_D_INFO, "FvLength: 0x%lx \n", (*FvbInfo)->FvLength)); + DEBUG ((EFI_D_INFO, "HeaderLength: 0x%x \n", (*FvbInfo)->HeaderLength)); + DEBUG ((EFI_D_INFO, "FvBlockMap[0].NumBlocks: 0x%x \n", (*FvbInfo)->BlockMap[0].NumBlocks)); + DEBUG ((EFI_D_INFO, "FvBlockMap[0].BlockLength: 0x%x \n", (*FvbInfo)->BlockMap[0].Length)); + DEBUG ((EFI_D_INFO, "FvBlockMap[1].NumBlocks: 0x%x \n", (*FvbInfo)->BlockMap[1].NumBlocks)); + DEBUG ((EFI_D_INFO, "FvBlockMap[1].BlockLength: 0x%x \n\n", (*FvbInfo)->BlockMap[1].Length)); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +EFI_STATUS +GetFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ) +{ + UINTN Index; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + + // + // Init Fvb data + // + mPlatformFvbMediaInfo[0].BaseAddress = PcdGet32 (PcdFlashFvMainBase); + mPlatformFvbMediaInfo[0].FvbInfo.FvLength = PcdGet32 (PcdFlashFvMainSize); + mPlatformFvbMediaInfo[0].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashFvMainSize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFvbMediaInfo[0].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashFvMainSize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + mPlatformFvbMediaInfo[1].BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase); + mPlatformFvbMediaInfo[1].FvbInfo.FvLength = PcdGet32 (PcdFlashNvStorageVariableSize); + mPlatformFvbMediaInfo[1].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashNvStorageVariableSize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFvbMediaInfo[1].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashNvStorageVariableSize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + mPlatformFvbMediaInfo[2].BaseAddress = PcdGet32 (PcdFlashFvRecoveryBase); + mPlatformFvbMediaInfo[2].FvbInfo.FvLength = PcdGet32 (PcdFlashFvRecoverySize); + mPlatformFvbMediaInfo[2].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashFvRecoverySize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFvbMediaInfo[2].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashFvRecoverySize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + mPlatformFvbMediaInfo[3].BaseAddress = PcdGet32 (PcdFlashFvRecovery2Base); + mPlatformFvbMediaInfo[3].FvbInfo.FvLength = PcdGet32 (PcdFlashFvRecovery2Size); + mPlatformFvbMediaInfo[3].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashFvRecovery2Size) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFvbMediaInfo[3].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashFvRecovery2Size) % FVB_MEDIA_BLOCK_SIZE) == 0); + + mPlatformFvbMediaInfo[4].BaseAddress = PcdGet32 (PcdFlashPayloadBase); + mPlatformFvbMediaInfo[4].FvbInfo.FvLength = PcdGet32 (PcdFlashPayloadSize); + mPlatformFvbMediaInfo[4].FvbInfo.BlockMap[0].NumBlocks = PcdGet32 (PcdFlashPayloadSize) / FVB_MEDIA_BLOCK_SIZE; + mPlatformFvbMediaInfo[4].FvbInfo.BlockMap[0].Length = FVB_MEDIA_BLOCK_SIZE; + ASSERT ((PcdGet32 (PcdFlashPayloadSize) % FVB_MEDIA_BLOCK_SIZE) == 0); + + for (Index=0; Index < sizeof (mPlatformFvbMediaInfo)/sizeof (mPlatformFvbMediaInfo[0]); Index += 1) { + if (mPlatformFvbMediaInfo[Index].BaseAddress == FvBaseAddress) { + FvHeader = &mPlatformFvbMediaInfo[Index].FvbInfo; + // + // Update the checksum value of FV header. + // + FvHeader->Checksum = CalculateCheckSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); + + *FvbInfo = FvHeader; + + DEBUG ((EFI_D_INFO, "\nBaseAddr: 0x%lx \n", FvBaseAddress)); + DEBUG ((EFI_D_INFO, "FvLength: 0x%lx \n", (*FvbInfo)->FvLength)); + DEBUG ((EFI_D_INFO, "HeaderLength: 0x%x \n", (*FvbInfo)->HeaderLength)); + DEBUG ((EFI_D_INFO, "FvBlockMap[0].NumBlocks: 0x%x \n", (*FvbInfo)->BlockMap[0].NumBlocks)); + DEBUG ((EFI_D_INFO, "FvBlockMap[0].BlockLength: 0x%x \n", (*FvbInfo)->BlockMap[0].Length)); + DEBUG ((EFI_D_INFO, "FvBlockMap[1].NumBlocks: 0x%x \n", (*FvbInfo)->BlockMap[1].NumBlocks)); + DEBUG ((EFI_D_INFO, "FvBlockMap[1].BlockLength: 0x%x \n\n", (*FvbInfo)->BlockMap[1].Length)); + + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbRuntimeDxe.inf b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbRuntimeDxe.inf new file mode 100644 index 0000000000..347ed88159 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbRuntimeDxe.inf @@ -0,0 +1,91 @@ +## @file +# Firmware Volume Block access module +# +# Provides the ability to perform read, write and erase operations on a Firmware +# Volume. Read and write operations are possible at the byte level but the +# erase operation can only be done at the block level. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = FvbRuntimeDxe + FILE_GUID = 7CB9C516-E7AA-4582-86A2-371EA9B3AFA3 + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = DxeFvbInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# +# + +[Sources] + FvbInfo.c + FvbService.h + FvbService.c + FvbServiceDxe.c + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + +[LibraryClasses] + PcdLib + MemoryAllocationLib + CacheMaintenanceLib + IoLib + BaseMemoryLib + DebugLib + BaseLib + UefiLib + UefiRuntimeLib + UefiBootServicesTableLib + UefiDriverEntryPoint + HobLib + +[Guids] + gEfiFirmwareFileSystem2Guid ## SOMETIMES_CONSUMES ## GUID + gEfiSystemNvDataFvGuid ## SOMETIMES_CONSUMES ## GUID + gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event + +[Protocols] + gEfiDevicePathProtocolGuid ## SOMETIMES_PRODUCES + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES + gSpiDeviceProtocolGuid ## CONSUMES + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvMainBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvMainSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoveryBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoverySize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecovery2Base ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecovery2Size ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashPayloadBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashPayloadSize ## CONSUMES + + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashMinEraseSize ## CONSUMES + +[Depex] + gSpiDeviceProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.c b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.c new file mode 100644 index 0000000000..1e5f151620 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.c @@ -0,0 +1,1226 @@ +/** @file + Firmware Volume Block Driver for Braswell Platform. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 "FvbService.h" + +// +// Global variable for this FVB driver which contains +// the private data of all firmware volume block instances +// +FWB_GLOBAL mFvbModuleGlobal; + +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) + } + }, + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS) 0, + (EFI_PHYSICAL_ADDRESS) 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { + { + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + { + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) + } + }, + { 0 } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +// +// Template structure used when installing FVB protocol +// +EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = { + FVB_DEVICE_SIGNATURE, + NULL, + 0, // Instance + { + FvbProtocolGetAttributes, + FvbProtocolSetAttributes, + FvbProtocolGetPhysicalAddress, + FvbProtocolGetBlockSize, + FvbProtocolRead, + FvbProtocolWrite, + FvbProtocolEraseBlocks, + NULL + } // FwVolBlockInstance +}; + +SPI_DEVICE_PROTOCOL *mSpiDeviceProtocol; + +/** + Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed + by mFvbModuleGlobal.FvInstance based on a index. + Each EFI_FW_VOL_INSTANCE is with variable length as + we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER. + + @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. + + @return A pointer to EFI_FW_VOL_INSTANCE. + +**/ +EFI_FW_VOL_INSTANCE * +GetFvbInstance ( + IN UINTN Instance + ) +{ + EFI_FW_VOL_INSTANCE *FwhRecord; + + if ( Instance >= mFvbModuleGlobal.NumFv ) { + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER); + return NULL; + } + + // + // Find the right instance of the FVB private data + // + FwhRecord = mFvbModuleGlobal.FvInstance; + while ( Instance > 0 ) { + FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + + FwhRecord->VolumeHeader.HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + Instance --; + } + + return FwhRecord; +} + +/** + Get the EFI_FVB_ATTRIBUTES_2 of a FV. + + @param[in] The index of the EFI_FW_VOL_INSTANCE. + + @return EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance. + +**/ +STATIC +EFI_FVB_ATTRIBUTES_2 +FvbGetVolumeAttributes ( + IN UINTN Instance + ) +{ + return GetFvbInstance (Instance)->VolumeHeader.Attributes; +} + +/** + Retrieves the starting address of an LBA in an FV. It also + return a few other attribut of the FV. + + @param[in] Instance The index of the EFI_FW_VOL_INSTANCE. + @param[in] Lba The logical block address + @param[out] FlashLinearAddress Provides the linear address into the flash device. + @param[out] LbaAddress On output, contains the physical starting address + of the Lba + @param[out] LbaLength On output, contains the length of the block + @param[out] NumOfBlocks A 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 Successfully returns + @retval EFI_INVALID_PARAMETER Instance not found + +**/ +STATIC +EFI_STATUS +FvbGetLbaAddress ( + IN UINTN Instance, + IN EFI_LBA Lba, + OUT UINTN *FlashLinearAddress, + OUT UINTN *LbaAddress, + OUT UINTN *LbaLength, + OUT UINTN *NumOfBlocks + ) +{ + UINT32 NumBlocks; + UINT32 BlockLength; + UINTN Offset; + EFI_LBA StartLba; + EFI_LBA NextLba; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FV_BLOCK_MAP_ENTRY *BlockMap; + + // + // Find the right instance of the FVB private data + // + FwhInstance = GetFvbInstance (Instance); + + StartLba = 0; + Offset = 0; + BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]); + + // + // Parse the blockmap of the FV to find which map entry the Lba belongs to + // + while (TRUE) { + NumBlocks = BlockMap->NumBlocks; + BlockLength = BlockMap->Length; + + if (NumBlocks == 0 || BlockLength == 0) { + return EFI_INVALID_PARAMETER; + } + + NextLba = StartLba + NumBlocks; + + // + // The map entry found + // + if (Lba >= StartLba && Lba < NextLba) { + Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength); + if (FlashLinearAddress) { + *FlashLinearAddress = FwhInstance->FvFlashLinearAddress + Offset; + } + + if (LbaAddress) { + *LbaAddress = FwhInstance->FvBase + Offset; + } + + if (LbaLength) { + *LbaLength = BlockLength; + } + + if (NumOfBlocks) { + *NumOfBlocks = (UINTN)(NextLba - Lba); + } + return EFI_SUCCESS; + } + + StartLba = NextLba; + Offset = Offset + NumBlocks * BlockLength; + BlockMap++; + } +} + +/** + Reads specified number of bytes into a buffer from the specified block + + @param[in] Instance The FV instance to be read from + @param[in] Lba The logical block address to be read from + @param[in] BlockOffset Offset into the block at which to begin reading + @param[in] NumBytes Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes read + @param[in] Buffer Pointer to a caller allocated buffer that will be + used to hold the data read + + @retval EFI_SUCCESS The firmware volume was read successfully and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a 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 + @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL + +**/ +STATIC +EFI_STATUS +FvbReadBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaLength; + EFI_STATUS Status; + EFI_STATUS Status1; + UINTN FlashAddress; + + // + // Validate input parameters. + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return (EFI_INVALID_PARAMETER); + } + if (*NumBytes == 0) { + return (EFI_INVALID_PARAMETER); + } + + // + // Get information for the specific LBA. + // + Status = FvbGetLbaAddress (Instance, Lba, &FlashAddress, NULL, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if operation can happen in the current state. + // + Attributes = FvbGetVolumeAttributes (Instance); + if ((Attributes & EFI_FVB2_READ_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Check to make sure that block information is valid for the current FV and + // correct it if needed. + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + if (LbaLength < (*NumBytes + BlockOffset)) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + // + // Perform read. + // + Status1 = mSpiDeviceProtocol->SpiRead (FlashAddress + BlockOffset, NumBytes, Buffer); + if (Status1 == EFI_DEVICE_ERROR) { + return Status1; + } + + return Status; +} + +/** + Writes specified number of bytes from the input buffer to the block + + @param[in] Instance The FV instance to be written to + @param[in] Lba The starting logical block index to write to + @param[in] BlockOffset Offset into the block at which to begin writing + @param[in] NumBytes Pointer that on input contains the total size of + the buffer. On output, it contains the total number + of bytes actually written + @param[in] Buffer 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 Write attempted across a 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 not functioning correctly and + could not be written + @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL + +**/ +EFI_STATUS +FvbWriteBlock ( + IN UINTN Instance, + IN EFI_LBA Lba, + IN UINTN BlockOffset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + UINTN LbaLength; + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_STATUS Status; + EFI_STATUS Status1; + UINTN FlashAddress; + + // + // Validate input parameters. + // + if ((NumBytes == NULL) || (Buffer == NULL)) { + return (EFI_INVALID_PARAMETER); + } + if (*NumBytes == 0) { + return (EFI_INVALID_PARAMETER); + } + + // + // Get the information for the FV specified. + // + FwhInstance = GetFvbInstance (Instance); + Status = FvbGetLbaAddress (Instance, Lba, &FlashAddress, &LbaAddress, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if the FV is write enabled + // + Attributes = FvbGetVolumeAttributes (Instance); + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Perform boundary checks and adjust NumBytes if needed. + // + if (BlockOffset > LbaLength) { + return EFI_INVALID_PARAMETER; + } + if ( LbaLength < ( *NumBytes + BlockOffset ) ) { + *NumBytes = (UINT32) (LbaLength - BlockOffset); + Status = EFI_BAD_BUFFER_SIZE; + } + + // + // Perform the write and flush the cache. + // + mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, FALSE); + Status1 = mSpiDeviceProtocol->SpiWrite (FlashAddress + BlockOffset, NumBytes, Buffer); + mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, TRUE); + WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes); + + // + // Determine the error to return based on PI spec. + // + if (Status1 == EFI_DEVICE_ERROR) { + return Status1; + } + + return Status; +} + +/** + Erases and initializes a firmware volume block + + @param[in] Instance The FV instance to be erased + @param[in] Lba The logical block index to be erased + + @retval EFI_SUCCESS The erase request was 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. Firmware device may have been + partially erased + @retval EFI_INVALID_PARAMETER Instance not found + +**/ +EFI_STATUS +FvbEraseBlock ( + IN UINTN Instance, + IN EFI_LBA Lba + ) +{ + EFI_FVB_ATTRIBUTES_2 Attributes; + UINTN LbaAddress; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN LbaLength; + EFI_STATUS Status; + EFI_STATUS Status1; + UINTN FlashAddress; + + // + // Find the right instance of the FVB private data + // + FwhInstance = GetFvbInstance (Instance); + + // + // Check if the FV is write enabled + // + Attributes = FvbGetVolumeAttributes (Instance); + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Get the starting address of the block for erase. + // + Status = FvbGetLbaAddress (Instance, Lba, &FlashAddress, &LbaAddress, &LbaLength, NULL); + if (EFI_ERROR (Status)) { + return EFI_INVALID_PARAMETER; + } + + // + // Perform erase. + // + mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, FALSE); + Status1 = mSpiDeviceProtocol->SpiErase (FlashAddress, LbaLength); + mSpiDeviceProtocol->SpiLock (FlashAddress, LbaLength, TRUE); + WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength); + + // + // Check to see if the erase was successful. If not return a device error to + // meet PI required return values. + // + if (Status1 == EFI_DEVICE_ERROR) { + return Status1; + } + + return EFI_SUCCESS; +} + +/** + Modifies the current settings of the firmware volume according to the + input parameter, and returns the new setting of the volume + + @param[in] Instance The FV instance whose attributes is going to be + modified + @param[in] Attributes On input, it is a pointer to EFI_FVB_ATTRIBUTES_2 + containing the desired firmware volume settings. + On successful return, it contains the new settings + of the firmware volume + + @retval EFI_SUCCESS Successfully returns + @retval EFI_ACCESS_DENIED The volume setting is locked and cannot be modified + @retval EFI_INVALID_PARAMETER Instance not found, or The attributes requested are + in conflict with the capabilities as declared in the + firmware volume header + +**/ +STATIC +EFI_STATUS +FvbSetVolumeAttributes ( + IN UINTN Instance, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FVB_ATTRIBUTES_2 OldAttributes; + EFI_FVB_ATTRIBUTES_2 *AttribPtr; + EFI_FVB_ATTRIBUTES_2 UnchangedAttributes; + UINT32 Capabilities; + UINT32 OldStatus, NewStatus; + + // + // Find the right instance of the FVB private data + // + FwhInstance = GetFvbInstance (Instance); + + AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes); + OldAttributes = *AttribPtr; + Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES; + OldStatus = OldAttributes & EFI_FVB2_STATUS; + NewStatus = *Attributes & EFI_FVB2_STATUS; + + UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP | \ + EFI_FVB2_STICKY_WRITE | \ + EFI_FVB2_MEMORY_MAPPED | \ + EFI_FVB2_ERASE_POLARITY | \ + EFI_FVB2_READ_LOCK_CAP | \ + EFI_FVB2_WRITE_LOCK_CAP | \ + EFI_FVB2_ALIGNMENT; + + // + // Some attributes of FV is read only can *not* be set + // + if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) { + return EFI_INVALID_PARAMETER; + } + + // + // If firmware volume is locked, no status bit can be updated + // + if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) { + if ( OldStatus ^ NewStatus ) { + return EFI_ACCESS_DENIED; + } + } + + // + // Test read disable + // + if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test read enable + // + if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_READ_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write disable + // + if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) { + if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test write enable + // + if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) { + if (NewStatus & EFI_FVB2_WRITE_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + // + // Test lock + // + if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) { + if (NewStatus & EFI_FVB2_LOCK_STATUS) { + return EFI_INVALID_PARAMETER; + } + } + + *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS)); + *AttribPtr = (*AttribPtr) | NewStatus; + *Attributes = *AttribPtr; + + return EFI_SUCCESS; +} + +// +// FVB protocol APIs +// + +/** + Retrieves the physical address of the device. + + @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[out] Address Output buffer containing the address. + + retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + *Address = GetFvbInstance (FvbDevice->Instance)->FvBase; + + return EFI_SUCCESS; +} + +/** + Retrieve the size of a logical block + + @param[in] This Calling context + @param[in] Lba Indicates which block to return the size for. + @param[out] BlockSize A pointer to a caller allocated UINTN in which + the size of the block is returned + @param[out] NumOfBlocks A 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 function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + return FvbGetLbaAddress ( + FvbDevice->Instance, + Lba, + NULL, + NULL, + BlockSize, + NumOfBlocks + ); +} + +/** + Retrieves Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance); + + return EFI_SUCCESS; +} + +/** + Sets Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_STATUS Status; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + Status = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes); + + return Status; +} + +/** + The EraseBlock() function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be verified + prior to 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 EraseBlock() function must return + EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + + @param[in] This Calling context + @param[in] ... Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + @retval EFI_SUCCESS The erase request was 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. Firmware device may have been + partially erased + +**/ +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN NumOfBlocks; + VA_LIST args; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_STATUS Status; + EFI_FVB_ATTRIBUTES_2 Attributes; + + // + // Initialize data. + // + FvbDevice = FVB_DEVICE_FROM_THIS (This); + FwhInstance = GetFvbInstance (FvbDevice->Instance); + NumOfBlocks = FwhInstance->NumOfBlocks; + + // + // Check if this FV can be written to. + // + Attributes = FvbGetVolumeAttributes (FvbDevice->Instance); + if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) { + return EFI_ACCESS_DENIED; + } + + // + // Validate LBA information passed in by caller. + // + VA_START (args, This); + do { + // + // Check for last entry in variable argument list. + // + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + // + // Get parameter from stack. + // + NumOfLba = VA_ARG (args, UINT32); + + // + // Check input parameters + // + if (NumOfLba == 0) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + if ((StartingLba + NumOfLba) > NumOfBlocks) { + VA_END (args); + return EFI_INVALID_PARAMETER; + } + } while (1); + VA_END (args); + + // + // Perform erase operation on all selected LBA. + // + VA_START (args, This); + do { + // + // Check for last entry in variable argument list. + // + StartingLba = VA_ARG (args, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + // + // Get parameter from stack. + // + NumOfLba = VA_ARG (args, UINT32); + + // + // Perform the erase operation for the specific LBA. + // + while (NumOfLba > 0) { + Status = FvbEraseBlock (FvbDevice->Instance, StartingLba); + if (EFI_ERROR (Status)) { + VA_END (args); + return Status; + } + StartingLba ++; + NumOfLba --; + } + } while (1); + VA_END (args); + + return EFI_SUCCESS; +} + +/** + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully + @retval EFI_BAD_BUFFER_SIZE Write attempted across a 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 not functioning correctly and + could not be written + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + Status = FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); + + return Status; +} + +/** + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + +Returns: + @retval EFI_SUCCESS The firmware volume was read successfully and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a 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 + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ) +{ + + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_STATUS Status; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + Status = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer); + + return Status; +} + +/** + Check the integrity of firmware volume header + + @param[in] FwVolHeader A pointer to a firmware volume header + + @retval TRUE The firmware volume is consistent + @retval FALSE The firmware volume has corrupted. + +**/ +STATIC +BOOLEAN +IsFvHeaderValid ( + IN EFI_PHYSICAL_ADDRESS FvBase, + IN CONST EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader + ) +{ + UINT16 Checksum; + + if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) { + if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) { + return FALSE; + } + } else { + if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) { + return FALSE; + } + } + if ((FwVolHeader->Revision != EFI_FVH_REVISION) || + (FwVolHeader->Signature != EFI_FVH_SIGNATURE) || + (FwVolHeader->FvLength == ((UINTN) -1)) || + ((FwVolHeader->HeaderLength & 0x01 ) !=0)) { + return FALSE; + } + + Checksum = CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength); + if (Checksum != 0) { + DEBUG (( DEBUG_ERROR, + "ERROR - Invalid Firmware Volume Header Checksum, change 0x%04x to 0x%04x\r\n", + FwVolHeader->Checksum, + (UINT16)( Checksum + FwVolHeader->Checksum ))); + return FALSE; + } + + return TRUE; +} + +/** + The driver entry point for Firmware Volume Block Driver. + + The function does the necessary initialization work + Firmware Volume Block Driver. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI system table. + + @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. + It will ASSERT on errors. + +**/ +EFI_STATUS +FvbInitialize ( + ) +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; + EFI_PHYSICAL_ADDRESS BaseAddress; + EFI_STATUS Status; + UINTN BufferSize; + UINTN TmpHeaderLength; + UINTN Idx; + UINT32 MaxLbaSize; + BOOLEAN FvHeaderValid; + UINTN FvFlashLinearAddress; + EFI_BOOT_MODE BootMode; + UINT32 Index; + UINT32 PlatformFvBaseAddress[5]; + UINT32 PlatformFvBaseAddressCount; + UINT32 PlatformFvLockList[4]; + UINT32 PlatformFvLockListCount; + + // + // This platform driver knows there are 3 FVs on + // FD, which are FvRecovery, FvMain and FvNvStorage. + // + BootMode = GetBootModeHob (); + if (BootMode == BOOT_IN_RECOVERY_MODE) { + // + // On recovery boot, don't report any firmware FV images except payload, because their data can't be trusted. + // + PlatformFvBaseAddressCount = 2; + PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageVariableBase); + PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashPayloadBase); + } else { + PlatformFvBaseAddressCount = 5; + PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashFvMainBase); + PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageVariableBase); + PlatformFvBaseAddress[2] = PcdGet32 (PcdFlashFvRecoveryBase); + PlatformFvBaseAddress[3] = PcdGet32 (PcdFlashFvRecovery2Base); + PlatformFvBaseAddress[4] = PcdGet32 (PcdFlashPayloadBase); + } + + // + // List of FVs that should be write protected on normal boots. + // + PlatformFvLockListCount = 4; + PlatformFvLockList[0] = PcdGet32 (PcdFlashFvMainBase); + PlatformFvLockList[1] = PcdGet32 (PcdFlashFvRecoveryBase); + PlatformFvLockList[2] = PcdGet32 (PcdFlashFvRecovery2Base); + PlatformFvLockList[3] = PcdGet32 (PcdFlashPayloadBase); + + // + // Calculate the total size for all firmware volume block instances and + // allocate a buffer to store them in. + // + BufferSize = 0; + for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PlatformFvBaseAddress[Idx]; + if (FvHeader == NULL) { + continue; + } + BufferSize += (FvHeader->HeaderLength + + sizeof (EFI_FW_VOL_INSTANCE) - + sizeof (EFI_FIRMWARE_VOLUME_HEADER) + ); + } + mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize); + ASSERT (NULL != mFvbModuleGlobal.FvInstance); + + // + // Perform other variable initialization. + // + MaxLbaSize = 0; + FwhInstance = mFvbModuleGlobal.FvInstance; + mFvbModuleGlobal.NumFv = 0; + + for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { + + if ((BootMode == BOOT_ASSUMING_NO_CONFIGURATION_CHANGES) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashNvStorageVariableBase) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashPayloadBase)) { + continue; + } + // + // Get base address information. + // + BaseAddress = PlatformFvBaseAddress[Idx]; + FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; + if (FwVolHeader == NULL) { + continue; + } + // + // Find the flash linear address of the current FV. + // + FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress); + + if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) { + FvHeaderValid = FALSE; + + // + // If not valid, get FvbInfo from the information carried in + // FVB driver. + // + DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress)); + Status = GetFvbInfo (BaseAddress, &FwVolHeader); + ASSERT_EFI_ERROR(Status); + + // + // Write back a healthy FV header. + // + DEBUG ((EFI_D_INFO, "FwBlockService.c: Writing back healthy FV header\n")); + mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, FALSE); + + Status = mSpiDeviceProtocol->SpiErase (FvFlashLinearAddress, FwVolHeader->BlockMap->Length); + + TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength; + Status = mSpiDeviceProtocol->SpiWrite ( + FvFlashLinearAddress, + &TmpHeaderLength, + (UINT8 *) FwVolHeader + ); + + mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, TRUE); + + WriteBackInvalidateDataCacheRange ( + (VOID *) (UINTN) BaseAddress, + FwVolHeader->BlockMap->Length + ); + + } + + // + // Copy FV header into local storage and assign base address. + // + CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); + FwVolHeader = &(FwhInstance->VolumeHeader); + FwhInstance->FvBase = (UINTN)BaseAddress; + FwhInstance->FvFlashLinearAddress = FvFlashLinearAddress; + + // + // In some cases the Recovery and Main FVs should be considered locked from + // write access by this protocol. Only in the case of flash updates and + // configuration mode should they be left unlocked. + // + if (BootMode != BOOT_IN_RECOVERY_MODE && + BootMode != BOOT_ON_FLASH_UPDATE) { + for (Index = 0; Index < PlatformFvLockListCount; Index++) { + if (FwhInstance->FvBase == PlatformFvLockList[Index]) { + // + // For all FVs in the lock list we need to clear the write status bit + // and lock write status updates. This will make sure this protocol + // will not attempt to write to the FV. + // + FwhInstance->VolumeHeader.Attributes &= (UINT64) ~EFI_FVB2_WRITE_STATUS; + FwhInstance->VolumeHeader.Attributes |= (EFI_FVB2_LOCK_STATUS | EFI_FVB2_WRITE_LOCK_STATUS); + } + } + } + + // + // Process the block map for each FV + // + FwhInstance->NumOfBlocks = 0; + for (PtrBlockMapEntry = FwVolHeader->BlockMap; + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { + // + // Get the maximum size of a block. + // + if (MaxLbaSize < PtrBlockMapEntry->Length) { + MaxLbaSize = PtrBlockMapEntry->Length; + } + FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; + } + + // + // Add a FVB Protocol Instance + // + mFvbModuleGlobal.NumFv++; + InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); + + // + // Move on to the next FwhInstance + // + FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + + FwVolHeader->HeaderLength + + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); + } + + if ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) == 0) || (PcdGet32 (PcdFlashNvStorageFtwSpareBase) == 0)) { + return EFI_SUCCESS; + } + + // + // Install FVB protocols for FTW spare space and FTW working space. + // These is no FV header for these 2 spaces. + // + mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) ReallocateRuntimePool ( + BufferSize, + BufferSize + (sizeof (EFI_FW_VOL_INSTANCE) + sizeof (EFI_FV_BLOCK_MAP_ENTRY)) * 2, + mFvbModuleGlobal.FvInstance + ); + ASSERT (NULL != mFvbModuleGlobal.FvInstance); + PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageFtwWorkingBase); + PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageFtwSpareBase); + + for (Idx = 0; Idx < 2; Idx++) { + BaseAddress = PlatformFvBaseAddress[Idx]; + Status = GetFtwFvbInfo (BaseAddress, &FwVolHeader); + ASSERT_EFI_ERROR(Status); + + // + // Copy FV header into local storage and assign base address. + // + mFvbModuleGlobal.NumFv++; + FwhInstance = GetFvbInstance (mFvbModuleGlobal.NumFv - 1); + CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); + FwVolHeader = &(FwhInstance->VolumeHeader); + + // + // Process the block map for each FV + // + FwhInstance->NumOfBlocks = 0; + for (PtrBlockMapEntry = FwVolHeader->BlockMap; + PtrBlockMapEntry->NumBlocks != 0; + PtrBlockMapEntry++) { + FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; + } + + FwhInstance->FvBase = (UINTN)BaseAddress; + FwhInstance->FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress); + + InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); + } + + return EFI_SUCCESS; +} + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.h b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.h new file mode 100644 index 0000000000..ed9e579307 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbService.h @@ -0,0 +1,187 @@ +/** @file + The header file for Firmware volume block driver. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _FW_BLOCK_SERVICE_H +#define _FW_BLOCK_SERVICE_H + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Define two helper macro to extract the Capability field or Status field in FVB +// bit fields +// +#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \ + EFI_FVB2_READ_ENABLED_CAP | \ + EFI_FVB2_WRITE_DISABLED_CAP | \ + EFI_FVB2_WRITE_ENABLED_CAP | \ + EFI_FVB2_LOCK_CAP \ + ) + +#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS) + +typedef struct { + UINTN FvBase; + UINTN NumOfBlocks; + UINTN FvFlashLinearAddress; + // + // Note!!!: VolumeHeader must be the last element + // of the structure. + // + EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; +} EFI_FW_VOL_INSTANCE; + +typedef struct { + EFI_FW_VOL_INSTANCE *FvInstance; + UINT32 NumFv; +} FWB_GLOBAL; + +// +// Fvb Protocol instance data +// +#define FVB_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE) +#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE) +#define FVB_DEVICE_SIGNATURE SIGNATURE_32('F','V','B','C') + +typedef struct { + MEDIA_FW_VOL_DEVICE_PATH FvDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_PIWG_DEVICE_PATH; + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_MEMMAP_DEVICE_PATH; + +typedef struct { + UINT32 Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + UINTN Instance; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance; +} EFI_FW_VOL_BLOCK_DEVICE; + +EFI_STATUS +GetFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ); + +EFI_STATUS +GetFtwFvbInfo ( + IN EFI_PHYSICAL_ADDRESS FvBaseAddress, + OUT EFI_FIRMWARE_VOLUME_HEADER **FvbInfo + ); + +VOID +InstallFvbProtocol ( + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN InstanceNum + ); + +EFI_STATUS +FvbInitialize ( + ); + +EFI_FW_VOL_INSTANCE * +GetFvbInstance ( + IN UINTN Instance + ); + +// +// Protocol APIs +// +EFI_STATUS +EFIAPI +FvbProtocolGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +EFI_STATUS +EFIAPI +FvbProtocolGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ); + +EFI_STATUS +EFIAPI +FvbProtocolRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +FvbProtocolEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ); + +extern FWB_GLOBAL mFvbModuleGlobal; +extern EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate; +extern FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate; +extern FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate; +extern SPI_DEVICE_PROTOCOL *mSpiDeviceProtocol; + +#endif + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceDxe.c b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceDxe.c new file mode 100644 index 0000000000..26effe7181 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceDxe.c @@ -0,0 +1,197 @@ +/** @file + Firmware Volume Block Driver for Tunnel Mountain Platform. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include "FvbService.h" + +/** + Call back function on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event. + + Fixup internal data so that the driver is callable in EFI runtime + in virtual mode. Convert the mFvbModuleGlobal date items to there + virtual address. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context The context of the Notification context. Not used in + this call back function. + +**/ +VOID +EFIAPI +FvbVirtualddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_FW_VOL_INSTANCE *FwhInstance; + UINTN Index; + + // + // Convert the base address of all the instances + // + for (Index = 0; Index < mFvbModuleGlobal.NumFv; Index++) { + FwhInstance = GetFvbInstance (Index); + EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase); + } + + EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal.FvInstance); + + EfiConvertPointer (0, (VOID **)&mSpiDeviceProtocol); +} + +/** + The function installs EFI_FIRMWARE_VOLUME_BLOCK protocol + for each FV in the system. + + @param[in] FwhInstance The pointer to a FW volume instance structure, + which contains the information about one FV. + @param[in] InstanceNum The instance number which can be used as a ID + to locate this FwhInstance in other functions. + + @retval VOID + +**/ +VOID +InstallFvbProtocol ( + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN InstanceNum + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_STATUS Status; + EFI_HANDLE FwbHandle; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface; + + FvbDevice = (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool ( + sizeof (EFI_FW_VOL_BLOCK_DEVICE), + &mFvbDeviceTemplate + ); + ASSERT (FvbDevice != NULL); + + FvbDevice->Instance = InstanceNum; + FwVolHeader = &FwhInstance->VolumeHeader; + + // + // Set up the devicepath + // + DEBUG ((EFI_D_INFO, "FwBlockService.c: Setting up DevicePath for 0x%lx:\n", FwhInstance->FvBase)); + if (FwVolHeader->ExtHeaderOffset == 0) { + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH + // + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = FwhInstance->FvBase; + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = FwhInstance->FvBase + FwVolHeader->FvLength - 1; + } else { + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); + CopyGuid ( + &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, + (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset) + ); + } + + // + // Find a handle with a matching device path that has supports FW Block protocol + // + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FwbHandle); + if (EFI_ERROR (Status) ) { + // + // LocateDevicePath fails so install a new interface and device path + // + DEBUG ((EFI_D_INFO, "FwBlockService.c: LocateDevicePath failed, install new interface 0x%lx:\n", FwhInstance->FvBase)); + FwbHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->FwVolBlockInstance, + &gEfiDevicePathProtocolGuid, + FvbDevice->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + DEBUG ((EFI_D_INFO, "FwBlockService.c: IMPI FirmwareVolBlockProt, DevPath 0x%lx: %r\n", FwhInstance->FvBase, Status)); + + } else if (IsDevicePathEnd (FvbDevice->DevicePath)) { + // + // Device allready exists, so reinstall the FVB protocol + // + DEBUG ((EFI_D_INFO, "FwBlockService.c: LocateDevicePath succeeded, reinstall interface 0x%lx:\n", FwhInstance->FvBase)); + Status = gBS->HandleProtocol ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &OldFwbInterface + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->ReinstallProtocolInterface ( + FwbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + OldFwbInterface, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + + } else { + // + // There was a FVB protocol on an End Device Path node + // + ASSERT (FALSE); + } + +} + +EFI_STATUS +EFIAPI +DxeFvbInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_EVENT Event; + + // + // Register for a callback when virtual addressing is updated. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + FvbVirtualddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + ASSERT_EFI_ERROR (Status); + + // + // Locate required protocol for access to flash. + // + Status = gBS->LocateProtocol ( + &gSpiDeviceProtocolGuid, + NULL, + (VOID **) &mSpiDeviceProtocol + ); + ASSERT_EFI_ERROR(Status); + + // + // Initialize the rest of the module. + // + Status = FvbInitialize (); + + return Status; +} diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceSmm.c b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceSmm.c new file mode 100644 index 0000000000..ffe101e08e --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbServiceSmm.c @@ -0,0 +1,263 @@ +/** @file + SMM Firmware Volume Block Driver for the Tunnel Creek Platform. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include "FvbSmmCommon.h" +#include "FvbService.h" + +/** + Communication service SMI Handler entry. + + This SMI handler provides communication services with the SMM FVB runtime driver. + + @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister(). + @param[in] RegisterContext Points to an optional handler context which was specified when the + handler was registered. + @param[in, out] CommBuffer A pointer to a collection of data in memory that will + be conveyed from a non-SMM environment into an SMM environment. + @param[in, out] CommBufferSize The size of the CommBuffer. + + @retval EFI_SUCCESS The interrupt was handled successfully. + @retval EFI_UNSUPPORTED The request was not supported by the handler. + +**/ +EFI_STATUS +EFIAPI +FvbSmmHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader; + SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader; + SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader; + SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader; + SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader; + SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader; + + ASSERT (CommBuffer != NULL); + + // + // Determine the function that is being requested and execute it. + // + SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) CommBuffer; + switch (SmmFvbFunctionHeader->Function) { + case EFI_FUNCTION_GET_ATTRIBUTES: + SmmFvbAttributesHeader = (SMM_FVB_ATTRIBUTES_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolGetAttributes ( + SmmFvbAttributesHeader->SmmFvb, + &SmmFvbAttributesHeader->Attributes + ); + break; + case EFI_FUNCTION_SET_ATTRIBUTES: + SmmFvbAttributesHeader = (SMM_FVB_ATTRIBUTES_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolSetAttributes ( + SmmFvbAttributesHeader->SmmFvb, + &SmmFvbAttributesHeader->Attributes + ); + break; + case EFI_FUNCTION_GET_PHYSICAL_ADDRESS: + SmmFvbPhysicalAddressHeader = (SMM_FVB_PHYSICAL_ADDRESS_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolGetPhysicalAddress ( + SmmFvbPhysicalAddressHeader->SmmFvb, + &SmmFvbPhysicalAddressHeader->Address + ); + break; + case EFI_FUNCTION_GET_BLOCK_SIZE: + SmmFvbBlockSizeHeader = (SMM_FVB_BLOCK_SIZE_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolGetBlockSize ( + SmmFvbBlockSizeHeader->SmmFvb, + SmmFvbBlockSizeHeader->Lba, + &SmmFvbBlockSizeHeader->BlockSize, + &SmmFvbBlockSizeHeader->NumOfBlocks + ); + break; + case EFI_FUNCTION_READ: + SmmFvbReadWriteHeader = (SMM_FVB_READ_WRITE_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolRead ( + SmmFvbReadWriteHeader->SmmFvb, + SmmFvbReadWriteHeader->Lba, + SmmFvbReadWriteHeader->Offset, + &SmmFvbReadWriteHeader->NumBytes, + (UINT8 *) (SmmFvbReadWriteHeader + 1) + ); + break; + case EFI_FUNCTION_WRITE: + SmmFvbReadWriteHeader = (SMM_FVB_READ_WRITE_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolWrite ( + SmmFvbReadWriteHeader->SmmFvb, + SmmFvbReadWriteHeader->Lba, + SmmFvbReadWriteHeader->Offset, + &SmmFvbReadWriteHeader->NumBytes, + (UINT8 *) (SmmFvbReadWriteHeader + 1) + ); + break; + case EFI_FUNCTION_ERASE_BLOCKS: + SmmFvbBlocksHeader = (SMM_FVB_BLOCKS_HEADER *) SmmFvbFunctionHeader->Data; + Status = FvbProtocolEraseBlocks ( + SmmFvbBlocksHeader->SmmFvb, + SmmFvbBlocksHeader->StartLba, + SmmFvbBlocksHeader->NumOfLba, + EFI_LBA_LIST_TERMINATOR, + 0 + ); + break; + default: + ASSERT (FALSE); + Status = EFI_UNSUPPORTED; + } + + // + // Set the return value. + // + SmmFvbFunctionHeader->ReturnStatus = Status; + + return EFI_SUCCESS; +} + +/** + The function installs EFI_SMM_FIRMWARE_VOLUME_BLOCK protocol + for each FV in the system. + + @param[in] FwhInstance The pointer to a FW volume instance structure, + which contains the information about one FV. + @param[in] InstanceNum The instance number which can be used as a ID + to locate this FwhInstance in other functions. + + @retval VOID + +**/ +VOID +InstallFvbProtocol ( + IN EFI_FW_VOL_INSTANCE *FwhInstance, + IN UINTN InstanceNum + ) +{ + EFI_FW_VOL_BLOCK_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + + FvbDevice = (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool ( + sizeof (EFI_FW_VOL_BLOCK_DEVICE), + &mFvbDeviceTemplate + ); + ASSERT (FvbDevice != NULL); + + FvbDevice->Instance = InstanceNum; + FwVolHeader = &FwhInstance->VolumeHeader; + + // + // Set up the devicepath + // + if (FwVolHeader->ExtHeaderOffset == 0) { + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH + // + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = FwhInstance->FvBase; + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = FwhInstance->FvBase + FwVolHeader->FvLength - 1; + } else { + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); + CopyGuid ( + &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, + (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset) + ); + } + + // + // Install the SMM Firmware Volume Block Protocol and Device Path Protocol + // + FvbHandle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &FvbHandle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvbDevice->FwVolBlockInstance + ); + ASSERT_EFI_ERROR (Status); + + Status = gSmst->SmmInstallProtocolInterface ( + &FvbHandle, + &gEfiDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + FvbDevice->DevicePath + ); + ASSERT_EFI_ERROR (Status); + + // + // Notify the Fvb wrapper driver SMM fvb is ready + // + FvbHandle = NULL; + Status = gBS->InstallProtocolInterface ( + &FvbHandle, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + EFI_NATIVE_INTERFACE, + &FvbDevice->FwVolBlockInstance + ); +} + +/** + The driver entry point for SMM Firmware Volume Block Driver. + + The function does the necessary initialization work + Firmware Volume Block Driver. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI system table. + + @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. + It will ASSERT on errors. + +**/ +EFI_STATUS +EFIAPI +FvbSmmInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + + // + // Locate required protocol for access to flash. + // + Status = gSmst->SmmLocateProtocol ( + &gSmmSpiDeviceProtocolGuid, + NULL, + (VOID **) &mSpiDeviceProtocol + ); + ASSERT_EFI_ERROR(Status); + + // + // Initialize the rest of the module. + // + FvbInitialize (); + + // + // Register SMM variable SMI handler + // + Status = gSmst->SmiHandlerRegister (FvbSmmHandler, &gEfiSmmFirmwareVolumeBlockProtocolGuid, &FvbHandle); + ASSERT_EFI_ERROR (Status); + + return EFI_SUCCESS; +} + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmm.inf b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmm.inf new file mode 100644 index 0000000000..a295cb512c --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmm.inf @@ -0,0 +1,93 @@ +## @file +# Firmware volume block service SMM driver. +# +# Provides the ability to perform read, write and erase operations on a Firmware +# Volume based on SMM. Read and write operations are possible at the byte level +# but the erase operation can only be done at the block level. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = FvbSmm + FILE_GUID = 564188F4-B6DD-48D0-A33A-F62507FA4FBF + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = FvbSmmInitialize + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# +# VIRTUAL_ADDRESS_MAP_CALLBACK = FvbVirtualddressChangeEvent +# + +[Sources] + FvbInfo.c + FvbService.h + FvbService.c + FvbServiceSmm.c + FvbSmmCommon.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + +[LibraryClasses] + PcdLib + MemoryAllocationLib + CacheMaintenanceLib + IoLib + BaseMemoryLib + DebugLib + BaseLib + UefiLib + UefiBootServicesTableLib + UefiDriverEntryPoint + SmmServicesTableLib + HobLib + +[Guids] + gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID + gEfiSystemNvDataFvGuid ## CONSUMES ## GUID + +[Protocols] + gEfiDevicePathProtocolGuid ## PRODUCES + gEfiSmmFirmwareVolumeBlockProtocolGuid ## PRODUCES # GUID value is also used to register an SMI Handler + gSmmSpiDeviceProtocolGuid ## CONSUMES + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvMainBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvMainSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoveryBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecoverySize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecovery2Base ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashFvRecovery2Size ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashPayloadBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashPayloadSize ## CONSUMES + + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashMinEraseSize ## CONSUMES + +[Depex] + gSmmSpiDeviceProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmCommon.h b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmCommon.h new file mode 100644 index 0000000000..a3c6f97829 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmCommon.h @@ -0,0 +1,75 @@ +/** @file + The common header file for SMM FVB module and SMM FVB runtime Module. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _SMM_FVB_COMMON_H_ +#define _SMM_FVB_COMMON_H_ + +#include + +#define EFI_FUNCTION_GET_ATTRIBUTES 1 +#define EFI_FUNCTION_SET_ATTRIBUTES 2 +#define EFI_FUNCTION_GET_PHYSICAL_ADDRESS 3 +#define EFI_FUNCTION_GET_BLOCK_SIZE 4 +#define EFI_FUNCTION_READ 5 +#define EFI_FUNCTION_WRITE 6 +#define EFI_FUNCTION_ERASE_BLOCKS 7 + +typedef struct { + UINTN Function; + EFI_STATUS ReturnStatus; + UINT8 Data[1]; +} SMM_FVB_COMMUNICATE_FUNCTION_HEADER; + +/// +/// Size of SMM communicate header, without including the payload. +/// +#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) + +/// +/// Size of SMM FVB communicate function header, without including the payload. +/// +#define SMM_FVB_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_FVB_COMMUNICATE_FUNCTION_HEADER, Data)) + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_ATTRIBUTES_2 Attributes; +} SMM_FVB_ATTRIBUTES_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_PHYSICAL_ADDRESS Address; +} SMM_FVB_PHYSICAL_ADDRESS_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA Lba; + UINTN BlockSize; + UINTN NumOfBlocks; +} SMM_FVB_BLOCK_SIZE_HEADER; + +typedef struct { + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA Lba; + UINTN Offset; + UINTN NumBytes; +} SMM_FVB_READ_WRITE_HEADER; + +typedef struct { + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_LBA StartLba; + UINTN NumOfLba; +} SMM_FVB_BLOCKS_HEADER; + +#endif diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.c b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.c new file mode 100644 index 0000000000..c82be4ba40 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.c @@ -0,0 +1,933 @@ +/** @file + Implement the Firmware Volume Block (FVB) services based on SMM FVB + module and install FVB protocol. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 "FvbSmmDxe.h" + +EFI_HANDLE mHandle = NULL; +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL; + +// +// Template structure used when installing FVB protocol +// +EFI_FVB_DEVICE mFvbDeviceTemplate = { + FVB_DEVICE_SIGNATURE, + NULL, + { + FvbGetAttributes, + FvbSetAttributes, + FvbGetPhysicalAddress, + FvbGetBlockSize, + FvbRead, + FvbWrite, + FvbEraseBlocks, + NULL + }, + NULL +}; + +FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = { + { + { + HARDWARE_DEVICE_PATH, + HW_MEMMAP_DP, + { + (UINT8)(sizeof (MEMMAP_DEVICE_PATH)), + (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8) + } + }, + EfiMemoryMappedIO, + (EFI_PHYSICAL_ADDRESS) 0, + (EFI_PHYSICAL_ADDRESS) 0, + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = { + { + { + MEDIA_DEVICE_PATH, + MEDIA_PIWG_FW_VOL_DP, + { + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)), + (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8) + } + }, + { 0 } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + END_DEVICE_PATH_LENGTH, + 0 + } + } +}; + +/** + Initialize the communicate buffer using DataSize and Function. + + The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + + DataSize. + + @param[out] CommunicateBuffer The communicate buffer. Caller should free it after use. + @param[out] DataPtr Points to the data in the communicate buffer. Caller should not free it. + @param[in] DataSize The payload size. + @param[in] Function The function number used to initialize the communicate header. + + @retval EFI_INVALID_PARAMETER The data size is too big. + @retval EFI_SUCCESS Find the specified variable. + +**/ +EFI_STATUS +InitCommunicateBuffer ( + OUT VOID **CommunicateBuffer, + OUT VOID **DataPtr, + IN UINTN DataSize, + IN UINTN Function + ) +{ + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader; + + // + // The whole buffer size: SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE + DataSize. + // + SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE); + ASSERT (SmmCommunicateHeader != NULL); + + // + // Prepare data buffer. + // + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmFirmwareVolumeBlockProtocolGuid); + SmmCommunicateHeader->MessageLength = DataSize + SMM_FVB_COMMUNICATE_HEADER_SIZE; + + SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data; + SmmFvbFunctionHeader->Function = Function; + + *CommunicateBuffer = SmmCommunicateHeader; + *DataPtr = SmmFvbFunctionHeader->Data; + + return EFI_SUCCESS; +} + +/** + Send the data in communicate buffer to SMM. + + @param[out] SmmCommunicateHeader The communicate buffer. + @param[in] DataSize The payload size. + +**/ +EFI_STATUS +SendCommunicateBuffer ( + IN EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + UINTN CommSize; + SMM_FVB_COMMUNICATE_FUNCTION_HEADER *SmmFvbFunctionHeader; + + CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_FVB_COMMUNICATE_HEADER_SIZE; + Status = mSmmCommunication->Communicate (mSmmCommunication, SmmCommunicateHeader, &CommSize); + ASSERT_EFI_ERROR (Status); + + SmmFvbFunctionHeader = (SMM_FVB_COMMUNICATE_FUNCTION_HEADER *) SmmCommunicateHeader->Data; + + return SmmFvbFunctionHeader->ReturnStatus; +} + +/** + This function retrieves the attributes and current settings of the block. + + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param[out] 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. + @retval EFI_INVALID_PARAMETER Attributes is NULL +**/ +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + if (Attributes == NULL) { + return EFI_INVALID_PARAMETER; + } + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER); + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbAttributesHeader, PayloadSize, EFI_FUNCTION_GET_ATTRIBUTES); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbAttributesHeader->SmmFvb = SmmFvb; + SmmFvbAttributesHeader->Attributes = 0; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *Attributes = SmmFvbAttributesHeader->Attributes; + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + Sets Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS Set the Attributes successfully. + @retval EFI_INVALID_PARAMETER Attributes is NULL + +**/ +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_ATTRIBUTES_HEADER *SmmFvbAttributesHeader; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + if (Attributes == NULL) { + return EFI_INVALID_PARAMETER; + } + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_ATTRIBUTES_HEADER); + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbAttributesHeader, PayloadSize, EFI_FUNCTION_SET_ATTRIBUTES); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbAttributesHeader->SmmFvb = SmmFvb; + SmmFvbAttributesHeader->Attributes = *Attributes; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *Attributes = SmmFvbAttributesHeader->Attributes; + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + Retrieves the physical address of the FVB instance. + + @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[out] Address Output buffer containing the address. + + @retval EFI_SUCCESS Get the address successfully. + @retval Others Failed to get address. + +**/ +EFI_STATUS +GetPhysicalAddress ( + IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_PHYSICAL_ADDRESS_HEADER *SmmFvbPhysicalAddressHeader; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_PHYSICAL_ADDRESS_HEADER); + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbPhysicalAddressHeader, PayloadSize, EFI_FUNCTION_GET_PHYSICAL_ADDRESS); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbPhysicalAddressHeader->SmmFvb = SmmFvb; + SmmFvbPhysicalAddressHeader->Address = 0; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *Address = SmmFvbPhysicalAddressHeader->Address; + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + Retrieves the physical address of the FVB instance. + + @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[out] Address Output buffer containing the address. + + @retval EFI_SUCCESS Get the address successfully. + @retval Others Failed to get the address. + +**/ +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ) +{ + EFI_STATUS Status; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + if (Address == NULL) { + return EFI_INVALID_PARAMETER; + } + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + Status = GetPhysicalAddress (SmmFvb, Address); + + return Status; +} + +/** + Retrieve the size of a logical block + + @param[in] SmmFvb A pointer to EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[in] Lba Indicates which block to return the size for. + @param[out] BlockSize A pointer to a caller allocated UINTN in which + the size of the block is returned + @param[out] NumOfBlocks A 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 Get BlockSize and NumOfBlocks successfully. + @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL. +**/ +EFI_STATUS +GetBlockSize ( + IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_BLOCK_SIZE_HEADER *SmmFvbBlockSizeHeader; + + if ((BlockSize == NULL) || (NumOfBlocks == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_BLOCK_SIZE_HEADER); + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbBlockSizeHeader, PayloadSize, EFI_FUNCTION_GET_BLOCK_SIZE); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbBlockSizeHeader->SmmFvb = SmmFvb; + SmmFvbBlockSizeHeader->Lba = Lba; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *BlockSize = SmmFvbBlockSizeHeader->BlockSize; + *NumOfBlocks = SmmFvbBlockSizeHeader->NumOfBlocks; + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + Retrieve the size of a logical block + + @param[in] This Calling context + @param[in] Lba Indicates which block to return the size for. + @param[out] BlockSize A pointer to a caller allocated UINTN in which + the size of the block is returned + @param[out] NumOfBlocks A 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 Get BlockSize and NumOfBlocks successfully. + @retval EFI_INVALID_PARAMETER BlockSize or NumOfBlocks are NULL. +**/ +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ) +{ + EFI_STATUS Status; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + Status = GetBlockSize (SmmFvb, Lba, BlockSize, NumOfBlocks); + return Status; +} + +/** + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + +Returns: + @retval EFI_SUCCESS The firmware volume was read successfully and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a 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 + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes; + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbReadWriteHeader, PayloadSize, EFI_FUNCTION_READ); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbReadWriteHeader->SmmFvb = SmmFvb; + SmmFvbReadWriteHeader->Lba = Lba; + SmmFvbReadWriteHeader->Offset = Offset; + SmmFvbReadWriteHeader->NumBytes = *NumBytes; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *NumBytes = SmmFvbReadWriteHeader->NumBytes; + if (!EFI_ERROR (Status)) { + CopyMem (Buffer, (UINT8 *)(SmmFvbReadWriteHeader + 1), *NumBytes); + } + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully + @retval EFI_BAD_BUFFER_SIZE Write attempted across a 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 not functioning correctly and + could not be written + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_READ_WRITE_HEADER *SmmFvbReadWriteHeader; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + if ((NumBytes == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_READ_WRITE_HEADER) + *NumBytes; + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbReadWriteHeader, PayloadSize, EFI_FUNCTION_WRITE); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbReadWriteHeader->SmmFvb = SmmFvb; + SmmFvbReadWriteHeader->Lba = Lba; + SmmFvbReadWriteHeader->Offset = Offset; + SmmFvbReadWriteHeader->NumBytes = *NumBytes; + CopyMem ((UINT8 *)(SmmFvbReadWriteHeader + 1), Buffer, *NumBytes); + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + *NumBytes = SmmFvbReadWriteHeader->NumBytes; + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + The EraseBlock() function erases NumOfLba blocks started from StartingLba. + + @param[in] This Calling context + @param[in] StartingLba Starting LBA followed to erase. + @param[in] NumOfLba Number of block to erase. + + @retval EFI_SUCCESS The erase request was 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. Firmware device may have been + partially erased + +**/ +EFI_STATUS +EraseBlock ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA StartingLba, + IN UINTN NumOfLba + ) +{ + EFI_STATUS Status; + UINTN PayloadSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_FVB_BLOCKS_HEADER *SmmFvbBlocksHeader; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + EFI_FVB_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + SmmFvb = FvbDevice->SmmFvbInstance; + + // + // Initialize the communicate buffer. + // + PayloadSize = sizeof (SMM_FVB_BLOCKS_HEADER); + Status = InitCommunicateBuffer ((VOID **)&SmmCommunicateHeader, (VOID **)&SmmFvbBlocksHeader, PayloadSize, EFI_FUNCTION_ERASE_BLOCKS); + if (EFI_ERROR (Status)) { + return Status; + } + + SmmFvbBlocksHeader->SmmFvb = SmmFvb; + SmmFvbBlocksHeader->StartLba = StartingLba; + SmmFvbBlocksHeader->NumOfLba = NumOfLba; + + // + // Send data to SMM. + // + Status = SendCommunicateBuffer (SmmCommunicateHeader, PayloadSize); + + // + // Get data from SMM + // + FreePool (SmmCommunicateHeader); + + return Status; +} + +/** + The EraseBlocks() function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be verified + prior to 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 EraseBlock() function must return + EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + + @param[in] This Calling context + @param[in] ... Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + @retval EFI_SUCCESS The erase request was 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. Firmware device may have been + partially erased + +**/ +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ) +{ + EFI_STATUS Status; + VA_LIST Marker; + EFI_LBA StartingLba; + UINTN NumOfLba; + EFI_FVB_DEVICE *FvbDevice; + + FvbDevice = FVB_DEVICE_FROM_THIS (This); + Status = EFI_SUCCESS; + + // + // Check the parameter + // + VA_START (Marker, This); + do { + StartingLba = VA_ARG (Marker, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR) { + break; + } + + NumOfLba = VA_ARG (Marker, UINT32); + if (NumOfLba == 0) { + VA_END (Marker); + return EFI_INVALID_PARAMETER; + } + + if ((StartingLba + NumOfLba) > FvbDevice->NumOfBlocks) { + VA_END (Marker); + return EFI_INVALID_PARAMETER; + } + } while (1); + VA_END (Marker); + + // + // Erase the blocks + // + VA_START (Marker, This); + do { + StartingLba = VA_ARG (Marker, EFI_LBA); + if (StartingLba == EFI_LBA_LIST_TERMINATOR ) { + break; + } + NumOfLba = VA_ARG (Marker, UINT32); + Status = EraseBlock (This, StartingLba, NumOfLba); + if (EFI_ERROR (Status)) { + break; + } + } while (1); + VA_END (Marker); + + return Status; +} + +/** + Install the FVB protocol which based on SMM FVB protocol. + + @param[in] SmmFvb The SMM FVB protocol. + +**/ +VOID +InstallFvb ( + IN EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb + ) +{ + EFI_STATUS Status; + EFI_HANDLE FvbHandle; + EFI_FVB_DEVICE *FvbDevice; + EFI_FIRMWARE_VOLUME_HEADER *VolumeHeader; + EFI_PHYSICAL_ADDRESS Address; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFvbInterface; + UINTN BlockSize; + UINTN NumOfBlocks; + + FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FVB_DEVICE), &mFvbDeviceTemplate); + ASSERT (FvbDevice != NULL); + FvbDevice->SmmFvbInstance = SmmFvb; + + Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication); + ASSERT_EFI_ERROR (Status); + + Status = GetBlockSize (SmmFvb, 0, &BlockSize, &NumOfBlocks); + ASSERT_EFI_ERROR (Status); + FvbDevice->NumOfBlocks = NumOfBlocks; + + Status = GetPhysicalAddress (SmmFvb, &Address); + ASSERT_EFI_ERROR (Status); + + VolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)Address; + + // + // Set up the devicepath + // + if (VolumeHeader->ExtHeaderOffset == 0) { + // + // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH + // + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate); + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = (UINTN)Address; + ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = (UINTN)Address + VolumeHeader->FvLength - 1; + } else { + FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate); + CopyGuid ( + &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName, + (GUID *)(UINTN)((UINTN)Address + VolumeHeader->ExtHeaderOffset) + ); + } + + // + // Find a handle with a matching device path that has supports FW Block protocol + // + Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FvbHandle); + if (EFI_ERROR (Status) ) { + // + // LocateDevicePath fails so install a new interface and device path + // + FvbHandle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + &FvbDevice->FvbInstance, + &gEfiDevicePathProtocolGuid, + FvbDevice->DevicePath, + NULL + ); + ASSERT_EFI_ERROR (Status); + } else if (IsDevicePathEnd (FvbDevice->DevicePath)) { + // + // Device allready exists, so reinstall the FVB protocol + // + Status = gBS->HandleProtocol ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + (VOID **) &OldFvbInterface + ); + ASSERT_EFI_ERROR (Status); + + Status = gBS->ReinstallProtocolInterface ( + FvbHandle, + &gEfiFirmwareVolumeBlockProtocolGuid, + OldFvbInterface, + &FvbDevice->FvbInstance + ); + ASSERT_EFI_ERROR (Status); + } else { + // + // There was a FVB protocol on an End Device Path node + // + ASSERT (FALSE); + } +} + +/** + SMM Firmware Volume Block Protocol notification event handler. + + Discover NV Variable Store and install Variable Write Arch Protocol. + + @param[in] Event Event whose notification function is being invoked. + @param[in] Context Pointer to the notification function's context. +**/ +VOID +EFIAPI +SmmFvbReady ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN HandleCount; + UINTN Index; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb; + + // + // Locate all handles of Smm Fvb protocol. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Install FVB protocol. + // + for (Index = 0; Index < HandleCount; Index++) { + SmmFvb = NULL; + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + (VOID **) &SmmFvb + ); + if (EFI_ERROR (Status)) { + break; + } + + InstallFvb (SmmFvb); + } + + FreePool (HandleBuffer); +} + +/** + The driver entry point for Firmware Volume Block Driver. + + The function does the necessary initialization work + Firmware Volume Block Driver. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI system table. + + @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. + It will ASSERT on errors. + +**/ +EFI_STATUS +EFIAPI +FvbSmmDxeInitialize ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *SmmFvbRegistration; + + // + // Smm FVB driver is ready + // + EfiCreateProtocolNotifyEvent ( + &gEfiSmmFirmwareVolumeBlockProtocolGuid, + TPL_CALLBACK, + SmmFvbReady, + NULL, + &SmmFvbRegistration + ); + + return EFI_SUCCESS; +} + diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.h b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.h new file mode 100644 index 0000000000..cee43bae72 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.h @@ -0,0 +1,231 @@ +/** @file + The internal header file includes the common header files, defines + internal structure and functions used by FVB module. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _SMM_FVB_DXE_H_ +#define _SMM_FVB_DXE_H_ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "FvbSmmCommon.h" + +#define FVB_DEVICE_SIGNATURE SIGNATURE_32 ('F', 'V', 'B', 'S') +#define FVB_DEVICE_FROM_THIS(a) CR (a, EFI_FVB_DEVICE, FvbInstance, FVB_DEVICE_SIGNATURE) + +typedef struct { + MEDIA_FW_VOL_DEVICE_PATH FvDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_PIWG_DEVICE_PATH; + +typedef struct { + MEMMAP_DEVICE_PATH MemMapDevPath; + EFI_DEVICE_PATH_PROTOCOL EndDevPath; +} FV_MEMMAP_DEVICE_PATH; + +typedef struct { + UINTN Signature; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FvbInstance; + EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvbInstance; + UINTN NumOfBlocks; +} EFI_FVB_DEVICE; + +/** + This function retrieves the attributes and current settings of the block. + + @param[in] This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance. + + @param[out] 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. + +**/ +EFI_STATUS +EFIAPI +FvbGetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + + /** + Sets Volume attributes. No polarity translations are done. + + @param[in] This Calling context + @param[out] Attributes Output buffer which contains attributes + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbSetAttributes ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes + ); + +/** + Retrieves the physical address of the device. + + @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL. + @param[out] Address Output buffer containing the address. + + @retval EFI_SUCCESS The function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbGetPhysicalAddress ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + OUT EFI_PHYSICAL_ADDRESS *Address + ); + +/** + Retrieve the size of a logical block + + @param[in] This Calling context + @param[in] Lba Indicates which block to return the size for. + @param[out] BlockSize A pointer to a caller allocated UINTN in which + the size of the block is returned + @param[out] NumOfBlocks A 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 function always return successfully. + +**/ +EFI_STATUS +EFIAPI +FvbGetBlockSize ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + OUT UINTN *BlockSize, + OUT UINTN *NumOfBlocks + ); + +/** + Reads data beginning at Lba:Offset from FV. The Read terminates either + when *NumBytes of data have been read, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + +Returns: + @retval EFI_SUCCESS The firmware volume was read successfully and + contents are in Buffer + @retval EFI_BAD_BUFFER_SIZE Read attempted across a 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 + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbRead ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + OUT UINT8 *Buffer + ); + +/** + Writes data beginning at Lba:Offset from FV. The write terminates either + when *NumBytes of data have been written, or when a block boundary is + reached. *NumBytes is updated to reflect the actual number of bytes + written. The write opertion does not include erase. This routine will + attempt to write only the specified bytes. If the writes do not stick, + it will return an error. + + @param[in] This Calling context + @param[in] Lba Block in which to begin write + @param[in] Offset Offset in the block at which to begin write + @param[in, out] NumBytes On input, indicates the requested write size. On + output, indicates the actual number of bytes written + @param[in] Buffer Buffer containing source data for the write. + + @retval EFI_SUCCESS The firmware volume was written successfully + @retval EFI_BAD_BUFFER_SIZE Write attempted across a 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 not functioning correctly and + could not be written + @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL + +**/ +EFI_STATUS +EFIAPI +FvbWrite ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + IN EFI_LBA Lba, + IN UINTN Offset, + IN OUT UINTN *NumBytes, + IN UINT8 *Buffer + ); + +/** + The EraseBlock() function erases one or more blocks as denoted by the + variable argument list. The entire parameter list of blocks must be verified + prior to 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 EraseBlock() function must return + EFI_INVALID_PARAMETER without modifying the contents of the firmware volume. + + @param[in] This Calling context + @param[in] ... Starting LBA followed by Number of Lba to erase. + a -1 to terminate the list. + + @retval EFI_SUCCESS The erase request was 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. Firmware device may have been + partially erased + +**/ +EFI_STATUS +EFIAPI +FvbEraseBlocks ( + IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This, + ... + ); + +#endif diff --git a/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.inf b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.inf new file mode 100644 index 0000000000..d1ae766266 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/FvbRuntimeDxe/FvbSmmDxe.inf @@ -0,0 +1,57 @@ +## @file +# SMM based Firmware Volume Block Dxe Driver +# +# This driver provides the Firmware Volume Block (FVB) services based on SMM +# FVB module and install FVB protocol. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = FvbSmmDxe + FILE_GUID = BEB88806-1143-4156-A2AF-4CA781EA313B + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = FvbSmmDxeInitialize +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FvbSmmDxe.c + FvbSmmDxe.h + FvbSmmCommon.h + +[Packages] + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + +[LibraryClasses] + BaseLib + UefiBootServicesTableLib + DebugLib + DxeServicesTableLib + UefiDriverEntryPoint + PcdLib + +[Protocols] + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES + gEfiSmmCommunicationProtocolGuid ## CONSUMES + gEfiSmmFirmwareVolumeBlockProtocolGuid ## CONSUMES # GUID value is also used with SMM Communication Protocol to invoke an SMI Handler + +[Depex] + gEfiSmmCommunicationProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.c b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.c new file mode 100644 index 0000000000..d4eaced0d4 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.c @@ -0,0 +1,659 @@ +/** @file + SPI Device driver for Braswell Platform. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include "SpiDevice.h" + +EFI_SPI_PROTOCOL *mSpiProtocol; + +UINTN mNvStorageBase = 0; + +EFI_STATUS +EFIAPI +SpiRead ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + VOID *BiosMmioAddress; + UINTN RegionOffset; + UINTN Length; + UINTN RemainingBytes; + + // + // Validate parameters. + // + if (Size == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + if (SpiOffset + *Size > PcdGet32 (PcdFlashAreaSize)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check to see if the read is taking place in a memory mapped part of the flash. + // Some flash regions may not be mapped for runtime access by the OS and must + // be accessed through the controller and not MMIO. + // + if (ReadUsingMmio (SpiOffset)) { + // + // Convert BIOS region offset into an actual memory address. + // + BiosMmioAddress = (VOID*) (SpiOffset + PcdGet32 (PcdFlashAreaBaseAddress)); + + // + // Do memory copy instead of using SPI controller. + // + CopyMem ((VOID*) Buffer, BiosMmioAddress, *Size); + } else if ((SpiOffset >= VN_STORAGE_REGION_FLASH_OFFSET) && (SpiOffset < (VN_STORAGE_REGION_FLASH_OFFSET + PcdGet32 (PcdFlashAreaSize)))) { + // + // Convert the offset into a memory address into the NV Storage region. At + // runtime this is the only region of the flash that is mapped for runtime + // access. Prior to runtime the preceding case will cover MMIO flash access. + // + BiosMmioAddress = (VOID*) ((SpiOffset - VN_STORAGE_REGION_FLASH_OFFSET) + mNvStorageBase); + + // + // Do memory copy instead of using SPI controller. + // + CopyMem ((VOID*) Buffer, BiosMmioAddress, *Size); + } else { + Status = EFI_SUCCESS; + RemainingBytes = *Size; + RegionOffset = SpiOffset; + while (RemainingBytes > 0) { + if (RemainingBytes > SIZE_4KB) { + Length = SIZE_4KB; + } else { + Length = RemainingBytes; + } + Status = mSpiProtocol->Execute ( + mSpiProtocol, + SPI_READ, + 0, + TRUE, + TRUE, + FALSE, + (UINT32) RegionOffset, + (UINT32) Length, + Buffer, + EnumSpiRegionAll + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Failed to read SPI region.\n")); + break; + } + RemainingBytes -= Length; + RegionOffset += Length; + Buffer += Length; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +SpiWrite ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN RegionOffset; + UINTN Length; + UINTN RemainingBytes; + + // + // Validate the input parameters + // + if (Size == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + if (SpiOffset + *Size > PcdGet32 (PcdFlashAreaSize)) { + return EFI_INVALID_PARAMETER; + } + + Status = EFI_SUCCESS; + RemainingBytes = *Size; + RegionOffset = SpiOffset; + + while (RemainingBytes > 0) { + if (RemainingBytes > SIZE_4KB) { + Length = SIZE_4KB; + } else { + Length = RemainingBytes; + } + Status = mSpiProtocol->Execute ( + mSpiProtocol, + SPI_PROG, + SPI_WREN, + TRUE, + TRUE, + TRUE, + (UINT32) RegionOffset, + (UINT32) Length, + Buffer, + EnumSpiRegionAll + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Failed to write SPI region.\n")); + break; + } + RemainingBytes -= Length; + RegionOffset += Length; + Buffer += Length; + } + + return Status; +} + +EFI_STATUS +EFIAPI +SpiErase ( + IN UINTN SpiOffset, + IN OUT UINTN Size + ) +{ + EFI_STATUS Status; + UINTN RegionOffset; + UINTN BytesRemaining; + + // + // Validate the input parameters + // + Status = EFI_INVALID_PARAMETER; + if (SpiOffset + Size > PcdGet32 (PcdFlashAreaSize)) { + return EFI_INVALID_PARAMETER; + } + + // + // Force the minimal alignment of 4k. + // + BytesRemaining = Size; + RegionOffset = SpiOffset; + if (RegionOffset & (SIZE_4KB - 1)) { + DEBUG((EFI_D_INFO, "Forcing SPI Device Erase alignment to a 4k base.\n")); + BytesRemaining += (RegionOffset & (SIZE_4KB - 1)); + RegionOffset = RegionOffset & (SIZE_4KB - 1); + } + + // + // Perform as many erase operations as needed to erase requested region. + // + while (BytesRemaining > 0) { + Status = mSpiProtocol->Execute ( + mSpiProtocol, + SPI_SERASE, + SPI_WREN, + FALSE, + TRUE, + FALSE, + (UINT32) RegionOffset, + 0, + NULL, + EnumSpiRegionAll + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Failed to erase SPI region.\n")); + break; + } + + // + // Update the number of bytes left to erase. + // + BytesRemaining -= SIZE_4KB; + RegionOffset += SIZE_4KB; + } + + return Status; +} + +EFI_STATUS +EFIAPI +SpiLock ( + IN UINTN SpiOffset, + IN OUT UINTN Size, + IN BOOLEAN Lock + ) +{ + // + // Block/Sector locking is not supported in this implementation. Use SpiSetRange + // and SpiLockRanges to protect areas of the flash. + // + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +SpiSetRange ( + IN UINTN SpiOffset, + IN UINTN Size, + IN BOOLEAN ReadLock, + IN BOOLEAN WriteLock + ) +{ + return EFI_UNSUPPORTED; +} + +EFI_STATUS +EFIAPI +SpiLockRanges ( + ) +{ + // + // Call lock on the SPI interface. This will lock down further configuration + // changes in the SPI controller. + // + return mSpiProtocol->Lock (mSpiProtocol); +} + +/** + Get the JEDED ID from the SPI flash part. + + @param[in] Context Pointer to a context data structure + needed by the SPI controller driver + @param[in] Description Description of the flash device + @param[in] BufferLength Length of the JedecId buffer + @param[out] JedecId Pointer to a buffer to fill with + the JEDEC ID value + + @retval EFI_SUCCESS The JEDEC ID value is in the buffer + @retval EFI_INVALID_PARAMETER JedecId is NULL + @retval EFI_INVALID_PARAMETER Description is NULL + @retval EFI_INVALID_PARAMETER Too few opcode entries + @retval EFI_INVALID_PARAMETER JEDEC ID response buffer too small + @retval EFI_UNSUPPORTED JEDEC ID opcode not found + +**/ +EFI_STATUS +EFIAPI +JedecIdRead ( + IN VOID *Context, + IN CONST FLASH_PART_DESCRIPTION *Description, + IN UINTN BufferLength, + OUT UINT8 *JedecId + ) +{ + // + // Validate parameters. + // + if ((JedecId == NULL) + || (Description == NULL) + || (BufferLength < Description->JededIdResponseLengthInBytes)) { + return EFI_INVALID_PARAMETER; + } + + return mSpiProtocol->ReadId (mSpiProtocol, 0, JedecId); +} + +/** + Determine the flash size and description + + @param[in] PerformJedecIdOperation Callback routine to initiate + the JEDEC ID operation using + the SPI controller to identify + the flash part. + @param[in] Context Pointer to a context structure to pass + to PerformJedecIdOperation + @param[out] FlashDescription Pointer to a buffer to receive a + pointer to a FLASH_PART_DESCRIPTION + data structure containing the flash + part information. + + @return This routine returns the size of the flash part if it is + supported. Zero is returned if the flash part is not + supported. + +**/ +UINT64 +EFIAPI +FindFlashSupport ( + IN PERFORM_JEDEC_ID_OPERATION PerformJedecIdOperation, + IN VOID *Context, + OUT CONST FLASH_PART_DESCRIPTION **FlashDescription + ) +{ + UINTN BufferLength; + CONST FLASH_PART_DESCRIPTION *Description; + UINT64 FlashSize; + EFI_HANDLE *HandleArray; + UINTN HandleCount; + UINTN HandleIndex; + UINT8 *JedecId; + UINT32 MaxPriority; + UINT32 Priority; + SPI_FLASH_PART_PROTOCOL *Protocol; + SPI_FLASH_PART_PROTOCOL **SpiFlashPartProtocol; + EFI_STATUS Status; + + // + // Assume failure + // + FlashSize = 0; + HandleArray = NULL; + JedecId = NULL; + SpiFlashPartProtocol = NULL; + + // + // Locate handles containing SPI_FLASH_PART_PROTOCOLS + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gSpiFlashPartProtocolGuid, + NULL, + &HandleCount, + &HandleArray + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR - Failed to locate SPI_FLASH_PART_PROTOCOL, Status: %r\r\n", Status)); + } else { + // + // Allocate and fill in the protocol array + // + DEBUG ((DEBUG_INFO, "%d SPI flash part descriptions found\r\n", HandleCount)); + SpiFlashPartProtocol = AllocatePool (HandleCount * sizeof (*SpiFlashPartProtocol)); + if (SpiFlashPartProtocol == NULL) { + DEBUG ((DEBUG_ERROR, "ERROR - Failed to allocate SpiFlashDataProtocol buffer\r\n")); + } else { + for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { + Status = gBS->OpenProtocol ( + HandleArray [HandleIndex], + &gSpiFlashPartProtocolGuid, + (VOID **) &SpiFlashPartProtocol [HandleIndex], + NULL, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR - Failed to open SPI_FLASH_DATA_PROTOCOL, Status: %r\r\n", Status)); + break; + } + } + if (!EFI_ERROR (Status)) { + // + // Allocate the JEDEC ID buffer + // + BufferLength = 0; + for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { + // + // Get the JEDEC ID opcode description + // + Protocol = SpiFlashPartProtocol [HandleIndex]; + Description = Protocol->GetFlashDescription ( + Protocol, + NULL, + NULL + ); + if (BufferLength < Description->JededIdResponseLengthInBytes) { + BufferLength = Description->JededIdResponseLengthInBytes; + } + } + JedecId = AllocatePool (BufferLength); + if (JedecId == NULL) { + DEBUG ((DEBUG_ERROR, "ERROR - Failed to allocate JedecId buffer\r\n")); + } else { + // + // Start with the first flash type description; + // + MaxPriority = 0xffffffff; + do { + // + // Determine the highest priority protocol + // + Priority = 0; + for (HandleIndex = 0; HandleCount > HandleIndex; HandleIndex++) { + Protocol = SpiFlashPartProtocol [HandleIndex]; + if ((MaxPriority >= Protocol->Priority) + && (Priority < Protocol->Priority)) + Priority = Protocol->Priority; + } + if (Priority == 0) { + // + // The flash is not supported + // + break; + } + + // + // Walk the handles containing the SPI flash part protocol + // + HandleIndex = 0; + do { + // + // Verify the description type matches and the opcode table + // supports the minimum number of entries required for the code + // + Protocol = SpiFlashPartProtocol [HandleIndex]; + if (Priority == Protocol->Priority) { + // + // Get the JEDEC ID opcode description + // + Description = Protocol->GetFlashDescription ( + Protocol, + NULL, + NULL + ); + if ((Description == NULL) + || (SPI_FLASH_PART_OPCODE_JEDEC_ID == Description->OpcodeTableEntries)) { + DEBUG ((DEBUG_ERROR, "ERROR - JEDEC ID opcode not available\r\n")); + } else { + // + // Display the flash part + // + DEBUG ((DEBUG_INFO, "Priority: 0x%08x, SPI Flash Part: %s\r\n", Priority, Description->PartNumber )); + + // + // Attempt to read the JEDEC ID + // + Status = PerformJedecIdOperation ( + Context, + Description, + Description->JededIdResponseLengthInBytes, + JedecId + ); + if (!EFI_ERROR (Status)) { + // + // Display the JEDEC ID + // + DEBUG_CODE_BEGIN (); + { + UINTN Index; + + DEBUG ((DEBUG_INFO, "JEDEC ID:")); + for (Index = 0; Description->JededIdResponseLengthInBytes > Index; Index++) { + DEBUG ((DEBUG_INFO, " 0x%02x", JedecId [Index])); + } + DEBUG ((DEBUG_INFO, "\r\n")); + } + DEBUG_CODE_END (); + + // + // Verify support and determine flash size + // + Description = Protocol->GetFlashDescription ( + Protocol, + JedecId, + &FlashSize + ); + if (Description != NULL) { + // + // The flash device is supported + // Return the table for this flash device + // + DEBUG ((DEBUG_INFO, "SPI flash device found: %s\r\n", Description->PartNumber)); + *FlashDescription = Description; + goto PartFound; + } + } + } + } + + // + // Set next handle + // + HandleIndex += 1; + } while (HandleCount > HandleIndex); + + // + // Set the next priority + // + MaxPriority = Priority - 1; + } while (Priority != 0); + + // + // No flash device found + // + DEBUG ((DEBUG_ERROR, "Matching SPI flash description not found\r\n")); + } + } + } + } + +PartFound: + // + // Free the buffers + // + if (JedecId != NULL) { + FreePool (JedecId); + } + if (SpiFlashPartProtocol != NULL) { + FreePool (SpiFlashPartProtocol); + } + if (HandleArray != NULL) { + FreePool (HandleArray); + } + + // + // Return the flash size + // Zero (0) indicates flash not found or not supported + // + return FlashSize; +} + +/** + Load opcode into the SPI controller for specific flash device + + @param[in] FlashDescription Description of the flash device + + @retval EFI_SUCCESS The opcode was successfully loaded + @retval EFI_UNSUPPORTED The opcode was not found + +**/ +EFI_STATUS +SpiFlashInit ( + IN CONST FLASH_PART_DESCRIPTION *FlashDescription + ) +{ + EFI_STATUS Status; + SPI_INIT_DATA SpiInitTable; + UINTN Index; + UINT8 CmdCfgIndex; + CONST UINT8 OpcodeMap [] = { + SPI_READ_ID, // SPI_FLASH_PART_OPCODE_JEDEC_ID + SPI_RDSR, // SPI_FLASH_PART_OPCODE_READ_STATUS + SPI_WRSR, // SPI_FLASH_PART_OPCODE_WRITE_STATUS + SPI_READ, // SPI_FLASH_PART_OPCODE_READ_BYTES + SPI_PROG, // SPI_FLASH_PART_OPCODE_WRITE_256_BYTE_PAGE + SPI_SERASE, // SPI_FLASH_PART_OPCODE_ERASE_4K_BYTE_BLOCK + SPI_BERASE, // SPI_FLASH_PART_OPCODE_ERASE_64K_BYTE_BLOCK + SPI_WRDI_SFDP // SPI_FLASH_PART_OPCODE_WRITE_DISABLE + }; + + Status = EFI_SUCCESS; + + ZeroMem (&SpiInitTable, sizeof (SPI_INIT_DATA)); + + SpiInitTable.PrefixOpcode[SPI_WREN] = FlashDescription->WriteEnable; + SpiInitTable.PrefixOpcode[SPI_EWSR] = FlashDescription->WriteStatusEnable; + + SpiInitTable.BiosStartOffset = (UINTN)BIOS_REGION_FLASH_OFFSET; + SpiInitTable.BiosSize = (UINTN)PcdGet32 (PcdBiosImageSize); + SpiInitTable.SpecialOpcodeEntry = NULL; + + ASSERT (FlashDescription->OpcodeTableEntries <= SPI_NUM_OPCODE); + + for (Index = 0;Index < FlashDescription->OpcodeTableEntries;Index++) { + CmdCfgIndex = OpcodeMap[Index]; + switch (FlashDescription->OpcodeTable[Index].MaxFrequency) { + case 20000000: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Frequency = EnumSpiCycle20MHz; + break; + + case 33000000: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Frequency = EnumSpiCycle33MHz; + break; + + case 50000000: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Frequency = EnumSpiCycle50MHz; + break; + + case 66000000: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Frequency = EnumSpiCycle66MHz; + break; + + default: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Frequency = EnumSpiCycle33MHz; + break; + } + + switch (FlashDescription->OpcodeTable[Index].OpcodeIndex) { + case SPI_FLASH_PART_OPCODE_JEDEC_ID: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationJedecId; + break; + + case SPI_FLASH_PART_OPCODE_READ_STATUS: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationReadStatus; + break; + + case SPI_FLASH_PART_OPCODE_WRITE_STATUS: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationWriteStatus; + break; + + case SPI_FLASH_PART_OPCODE_READ_BYTES: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationReadData; + break; + + case SPI_FLASH_PART_OPCODE_WRITE_256_BYTE_PAGE: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationProgramData_1_Byte; + break; + + case SPI_FLASH_PART_OPCODE_ERASE_4K_BYTE_BLOCK: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationErase_4K_Byte; + break; + + case SPI_FLASH_PART_OPCODE_ERASE_64K_BYTE_BLOCK: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationErase_64K_Byte; + break; + + case SPI_FLASH_PART_OPCODE_WRITE_DISABLE_DISCOVERY: + SpiInitTable.SpiCmdConfig[CmdCfgIndex].Operation = EnumSpiOperationWriteDisable; + break; + + default: + DEBUG ((DEBUG_ERROR, "Unrecognized opcode index\r\n")); + ASSERT(FALSE); + break; + } + } + + Status = mSpiProtocol->Init (mSpiProtocol, &SpiInitTable); + + return Status; +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.h b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.h new file mode 100644 index 0000000000..cb8229629d --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDevice.h @@ -0,0 +1,211 @@ +/** @file + SPI Device driver for Braswell Platform. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _SPI_DEVICE_H_ +#define _SPI_DEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +// +// Defines the offset in the SPI device where the BIOS region starts. +// +#define BIOS_REGION_FLASH_OFFSET (PcdGet32 (PcdBiosImageBase) - PcdGet32 (PcdFlashAreaBaseAddress)) +#define VN_STORAGE_REGION_FLASH_OFFSET (PcdGet32 (PcdFlashNvStorageVariableBase) - PcdGet32 (PcdFlashAreaBaseAddress)) + +extern EFI_SPI_PROTOCOL *mSpiProtocol; +extern UINTN mNvStorageBase; + +// +// Prefix Opcode Index on the host SPI controller +// +typedef enum { + SPI_WREN, // Prefix Opcode 0: Write Enable + SPI_EWSR, // Prefix Opcode 1: Enable Write Status Register +} PREFIX_OPCODE_INDEX; + +// +// Opcode Menu Index on the host SPI controller +// +typedef enum { + SPI_READ_ID, // Opcode 0: READ ID, Read cycle with address + SPI_READ, // Opcode 1: READ, Read cycle with address + SPI_RDSR, // Opcode 2: Read Status Register, No address + SPI_WRDI_SFDP, // Opcode 3: Write Disable or Discovery Parameters, No address + SPI_SERASE, // Opcode 4: Sector Erase (4KB), Write cycle with address + SPI_BERASE, // Opcode 5: Block Erase (32KB), Write cycle with address + SPI_PROG, // Opcode 6: Byte Program, Write cycle with address + SPI_WRSR, // Opcode 7: Write Status Register, No address +} SPI_OPCODE_INDEX; + +EFI_STATUS +EFIAPI +InitSpiDevice ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +EFI_STATUS +EFIAPI +SpiRead ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + OUT UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +SpiWrite ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + IN UINT8 *Buffer + ); + +EFI_STATUS +EFIAPI +SpiErase ( + IN UINTN SpiOffset, + IN OUT UINTN Size + ); + +EFI_STATUS +EFIAPI +SpiLock ( + IN UINTN SpiOffset, + IN OUT UINTN Size, + IN BOOLEAN Lock + ); + +EFI_STATUS +EFIAPI +SpiSetRange ( + IN UINTN SpiOffset, + IN UINTN Size, + IN BOOLEAN ReadLock, + IN BOOLEAN WriteLock + ); + +EFI_STATUS +EFIAPI +SpiLockRanges ( + ); + +BOOLEAN +ReadUsingMmio ( + IN UINTN SpiOffset + ); + +/** + Get the JEDED ID from the SPI flash part. + + @param[in] Context Pointer to a context data structure + needed by the SPI controller driver + @param[in] Description Description of the flash device + @param[in] BufferLength Length of the JedecId buffer + @param[out] JedecId Pointer to a buffer to fill with + the JEDEC ID value + + @retval EFI_SUCCESS The JEDEC ID value is in the buffer + @retval EFI_INVALID_PARAMETER JedecId is NULL + @retval EFI_INVALID_PARAMETER Description is NULL + @retval EFI_INVALID_PARAMETER Too few opcode entries + @retval EFI_INVALID_PARAMETER JEDEC ID response buffer too small + @retval EFI_UNSUPPORTED JEDEC ID opcode not found + +**/ +EFI_STATUS +EFIAPI +JedecIdRead ( + IN VOID *Context, + IN CONST FLASH_PART_DESCRIPTION *Description, + IN UINTN BufferLength, + OUT UINT8 *JedecId + ); + +/** + Get the JEDED ID from the SPI flash part. + + @param[in] Context Pointer to a context data structure + needed by the SPI controller driver + @param[in] Description Description of the flash device + @param[in] BufferLength Length of the JedecId buffer + @param[out] JedecId Pointer to a buffer to fill with + the JEDEC ID value + + @retval EFI_SUCCESS The JEDEC ID value is in the buffer + @retval EFI_INVALID_PARAMETER JedecId is NULL + @retval EFI_INVALID_PARAMETER Description is NULL + @retval EFI_INVALID_PARAMETER Too few opcode entries + @retval EFI_INVALID_PARAMETER JEDEC ID response buffer too small + +**/ +typedef +EFI_STATUS +(EFIAPI *PERFORM_JEDEC_ID_OPERATION) ( + IN VOID *Context, + IN CONST FLASH_PART_DESCRIPTION *Description, + IN UINTN BufferLength, + OUT UINT8 *JedecId + ); + +/** + Determine the flash size and description + + @param[in] PerformJedecIdOperation Callback routine to initiate + the JEDEC ID operation using + the SPI controller to identify + the flash part. + @param[in] Context Pointer to a context structure to pass + to PerformJedecIdOperation + @param[out] FlashDescription Pointer to a buffer to receive a + pointer to a FLASH_PART_DESCRIPTION + data structure containing the flash + part information. + + @return This routine returns the size of the flash part if it is + supported. Zero is returned if the flash part is not + supported. + +**/ +UINT64 +EFIAPI +FindFlashSupport ( + IN PERFORM_JEDEC_ID_OPERATION PerformJedecIdOperation, + IN VOID *Context, + OUT CONST FLASH_PART_DESCRIPTION **FlashDescription + ); + + +/** + Load opcode into the SPI controller for specific flash device + + @param[in] FlashDescription Description of the flash device + + @retval EFI_SUCCESS The opcode was successfully loaded + @retval EFI_UNSUPPORTED The opcode was not found + +**/ +EFI_STATUS +SpiFlashInit ( + IN CONST FLASH_PART_DESCRIPTION *FlashDescription + ); + +#endif diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.c b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.c new file mode 100644 index 0000000000..907b8e9517 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.c @@ -0,0 +1,152 @@ +/** @file + This driver for SPI Device initialization + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include +#include +#include +#include +#include "SpiDevice.h" + +SPI_DEVICE_PROTOCOL mSpiDevProtocol = { + SpiRead, + SpiWrite, + SpiErase, + SpiLock, + SpiSetRange, + SpiLockRanges +}; + +VOID +EFIAPI +SpiDeviceVirtualAddressChangeEvent ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + // + // Update protocol pointer to the SPI Controller interface. + // + EfiConvertPointer (0x00, (VOID**) &(mSpiProtocol)); + + // + // Update the NV Storage location for runtime access. + // + EfiConvertPointer (0x00, (VOID**) &(mNvStorageBase)); + + // + // Take care of pointers in protocol. + // + EfiConvertPointer (0x00, (VOID**) &(mSpiDevProtocol.SpiRead)); + EfiConvertPointer (0x00, (VOID**) &(mSpiDevProtocol.SpiWrite)); + EfiConvertPointer (0x00, (VOID**) &(mSpiDevProtocol.SpiErase)); + EfiConvertPointer (0x00, (VOID**) &(mSpiDevProtocol.SpiLock)); +} + +EFI_STATUS +EFIAPI +InitSpiDevice ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_EVENT Event; + CONST FLASH_PART_DESCRIPTION *FlashDescription; + UINT64 FlashSize; + EFI_HANDLE Handle; + EFI_STATUS Status; + + mNvStorageBase = PcdGet32 (PcdFlashNvStorageVariableBase); + + // + // Locate the SPI controller protocol and save it for later. + // + DEBUG((EFI_D_INFO, "Locating SPI Controller Protocol.\n")); + Status = gBS->LocateProtocol ( + &gEfiSpiProtocolGuid, + NULL, + (VOID **) &mSpiProtocol + ); + ASSERT_EFI_ERROR(Status); + + // + // Loop through all the flash devices that are supported and see if one will + // initialize the SPI Controller interface. + // + FlashSize = FindFlashSupport ( + &JedecIdRead, + NULL, + &FlashDescription + ); + if (FlashSize == 0) { + DEBUG((EFI_D_ERROR, "No SPI flash part description found!\r\n")); + } else { + // + // Attempt to configure the SPI controller for this device. + // + DEBUG((EFI_D_INFO, "SPI flash size: %d MBytes\n", DivU64x32(FlashSize, 1024 * 1024 ))); + DEBUG((EFI_D_INFO, "Configuring SPI Controller.\n")); + + Status = SpiFlashInit (FlashDescription); + if (!EFI_ERROR (Status)) { + // + // Publish the SPI Device protocol. + // + DEBUG((EFI_D_INFO, "Installing SPI Device Protocol.\n")); + Handle = NULL; + Status = gBS->InstallMultipleProtocolInterfaces ( + &Handle, + &gSpiDeviceProtocolGuid, + &mSpiDevProtocol, + NULL + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Make sure we can handle virtual address changes. + // + Event = NULL; + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + SpiDeviceVirtualAddressChangeEvent, + NULL, + &gEfiEventVirtualAddressChangeGuid, + &Event + ); + + return EFI_SUCCESS; + } + } + + // + // Unable to find a supported SPI device + // + DEBUG((EFI_D_ERROR, "Unable to configure SPI Controller for SPI device present.\n")); + + return EFI_UNSUPPORTED; +} + +BOOLEAN +ReadUsingMmio ( + IN UINTN SpiOffset + ) +{ + return (BOOLEAN) ((SpiOffset >= BIOS_REGION_FLASH_OFFSET) && (SpiOffset < (BIOS_REGION_FLASH_OFFSET + PcdGet32 (PcdBiosImageSize))) && (!EfiAtRuntime ())); +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.inf b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.inf new file mode 100644 index 0000000000..9db458076c --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceDxe.inf @@ -0,0 +1,64 @@ +## @file +# SPI Flash Device Driver +# +# Adds platform support to configure the SPI controller with the correct values +# to be used when using software sequencing. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = SpiDeviceDxe + FILE_GUID = DA28E378-C84B-4969-BD4D-90AA883C091A + MODULE_TYPE = DXE_RUNTIME_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitSpiDevice + +[Sources] + SpiDeviceDxe.c + SpiDevice.c + SpiDevice.h + +[Packages] + ChvRefCodePkg/ChvRefCodePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DebugLib + DxeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiRuntimeLib + MemoryAllocationLib + +[Protocols] + gEfiSpiProtocolGuid ## CONSUMES + gSpiDeviceProtocolGuid ## PRODUCES + gSpiFlashPartProtocolGuid ## CONSUMES + gEfiSmmCommunicationProtocolGuid ## UNDEFINED + +[Guids] + gEfiEventVirtualAddressChangeGuid ## SOMETIMES_CONSUMES ## NOTIFY + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashAreaSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdBiosImageBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdBiosImageSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + +[Depex] + gEfiSpiProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.c b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.c new file mode 100644 index 0000000000..7d02aff9d0 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.c @@ -0,0 +1,222 @@ +/** @file + SMM driver for SPI Device initialization. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include +#include +#include "SpiDevice.h" +#include "SpiDeviceSmmComm.h" + +SPI_DEVICE_PROTOCOL mSpiDevProtocol = { + SpiRead, + SpiWrite, + SpiErase, + SpiLock, + SpiSetRange, + SpiLockRanges +}; + +EFI_STATUS +EFIAPI +SpiDeviceSmmHandler ( + IN EFI_HANDLE DispatchHandle, + IN CONST VOID *RegisterContext, + IN OUT VOID *CommBuffer, + IN OUT UINTN *CommBufferSize + ) +{ + EFI_STATUS Status; + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER *SpiDevCommHeader; + SMM_SPI_DEV_READ_WRITE_ERASE_HEADER *SpiDevDataOpHeader; + SMM_SPI_DEV_LOCK_HEADER *SpiDevLockHeader; + SMM_SPI_DEV_SET_RANGE_HEADER *SpiDevSetRangeHeader; + + ASSERT (CommBuffer != NULL); + + SpiDevCommHeader = (SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER*) CommBuffer; + switch (SpiDevCommHeader->Function) { + case SPI_DEV_FUNCTION_READ: + SpiDevDataOpHeader = (SMM_SPI_DEV_READ_WRITE_ERASE_HEADER*) SpiDevCommHeader->Data; + Status = SpiRead ( + SpiDevDataOpHeader->Offset, + &SpiDevDataOpHeader->Size, + (UINT8*) (SpiDevDataOpHeader + 1) + ); + break; + case SPI_DEV_FUNCTION_WRITE: + SpiDevDataOpHeader = (SMM_SPI_DEV_READ_WRITE_ERASE_HEADER*) SpiDevCommHeader->Data; + Status = SpiWrite ( + SpiDevDataOpHeader->Offset, + &SpiDevDataOpHeader->Size, + (UINT8*) (SpiDevDataOpHeader + 1) + ); + break; + case SPI_DEV_FUNCTION_ERASE: + SpiDevDataOpHeader = (SMM_SPI_DEV_READ_WRITE_ERASE_HEADER*) SpiDevCommHeader->Data; + Status = SpiErase ( + SpiDevDataOpHeader->Offset, + SpiDevDataOpHeader->Size + ); + break; + case SPI_DEV_FUNCTION_LOCK: + SpiDevLockHeader = (SMM_SPI_DEV_LOCK_HEADER*) SpiDevCommHeader->Data; + Status = SpiLock ( + SpiDevLockHeader->Offset, + SpiDevLockHeader->Size, + SpiDevLockHeader->Lock + ); + break; + case SPI_DEV_FUNCTION_SET_RANGE: + SpiDevSetRangeHeader = (SMM_SPI_DEV_SET_RANGE_HEADER*) SpiDevCommHeader->Data; + Status = SpiSetRange ( + SpiDevSetRangeHeader->Offset, + SpiDevSetRangeHeader->Size, + SpiDevSetRangeHeader->ReadLock, + SpiDevSetRangeHeader->WriteLock + ); + break; + case SPI_DEV_FUNCTION_LOCK_RANGES: + Status = SpiLockRanges (); + break; + default: + ASSERT (FALSE); + Status = EFI_UNSUPPORTED; + break; + } + + // + // Set the return value. + // + SpiDevCommHeader->ReturnStatus = Status; + + return EFI_SUCCESS; +} + +EFI_STATUS +EFIAPI +InitSpiDevice ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + CONST FLASH_PART_DESCRIPTION *FlashDescription; + UINT64 FlashSize; + EFI_HANDLE Handle; + EFI_STATUS Status; + + //-------------------------------------------------- + // + // Note only this routine is able to make calls + // into the DXE environment since it is called + // synchronously from that environment and DXE + // is still executing in physical mode. + // + //-------------------------------------------------- + + mNvStorageBase = PcdGet32 (PcdFlashNvStorageVariableBase); + + // + // Locate the SPI controller protocol and save it for later. + // + DEBUG((EFI_D_INFO, "Locating SPI Controller Protocol.\n")); + Status = gSmst->SmmLocateProtocol ( + &gEfiSmmSpi2ProtocolGuid, + NULL, + (VOID **) &mSpiProtocol + ); + ASSERT_EFI_ERROR(Status); + + + // + // Loop through all the flash devices that are supported and see if one will + // initialize the SPI Controller interface. + // + FlashSize = FindFlashSupport ( + &JedecIdRead, + NULL, + &FlashDescription + ); + if (FlashSize == 0) { + DEBUG((EFI_D_ERROR, "No SPI flash part description found!\r\n")); + } else { + // + // Attempt to configure the SPI controller for this device. + // + DEBUG((EFI_D_INFO, "SPI flash size: %d MBytes\n", DivU64x32(FlashSize, 1024 * 1024 ))); + DEBUG((EFI_D_INFO, "Configuring SPI Controller.\n")); + Status = SpiFlashInit (FlashDescription); + if (!EFI_ERROR (Status)) { + // + // Publish the SMM SPI Device protocol for FVB service + // + DEBUG((EFI_D_INFO, "Installing SPI Device Protocol.\n")); + Handle = NULL; + Status = gSmst->SmmInstallProtocolInterface ( + &Handle, + &gSmmSpiDeviceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSpiDevProtocol + ); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Install protocol to inform other DXE drivers the SMM service is available. + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gSmmSpiDeviceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSpiDevProtocol + ); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Unable to install SMM SPI device protocol, Status: %r\n", Status)); + return Status; + } + + // + // Install communication handler. + // + Handle = NULL; + Status = gSmst->SmiHandlerRegister (SpiDeviceSmmHandler, &gSmmSpiDeviceProtocolGuid, &Handle); + if (EFI_ERROR (Status)) { + DEBUG((EFI_D_ERROR, "Unable to register SMM SPI handler, Status: %r\n", Status)); + return Status; + } + + DEBUG((EFI_D_INFO, "SPI flash controller configured successfully\n", Status)); + return EFI_SUCCESS; + } + } + + // + // Unable to find a supported SPI device + // + DEBUG((EFI_D_ERROR, "Unable to configure SPI Controller for SPI device present.\n")); + + return EFI_UNSUPPORTED; +} + +BOOLEAN +ReadUsingMmio ( + IN UINTN SpiOffset + ) +{ + return (BOOLEAN) ((SpiOffset >= BIOS_REGION_FLASH_OFFSET) && (SpiOffset < (BIOS_REGION_FLASH_OFFSET + PcdGet32 (PcdBiosImageSize)))); +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.inf b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.inf new file mode 100644 index 0000000000..d698f25159 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmm.inf @@ -0,0 +1,62 @@ +## @file +# SPI Device SMM Driver +# +# Adds platform support to configure the SPI controller with the correct values +# to be used when using software sequencing. This driver initializes EMST* F25L016A +# SPI flash device and installs gSmmSpiDeviceProtocolGuid protocol. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = SpiDeviceSmm + FILE_GUID = 163774A8-917F-40E5-AB54-B4BFA11D41F9 + MODULE_TYPE = DXE_SMM_DRIVER + VERSION_STRING = 1.0 + PI_SPECIFICATION_VERSION = 0x0001000A + ENTRY_POINT = InitSpiDevice + +[Sources] + SpiDeviceSmm.c + SpiDevice.c + SpiDevice.h + +[Packages] + ChvRefCodePkg/ChvRefCodePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + UefiBootServicesTableLib + UefiDriverEntryPoint + DebugLib + SmmServicesTableLib + BaseLib + MemoryAllocationLib + +[Protocols] + gEfiSmmSpi2ProtocolGuid ## CONSUMES + gSmmSpiDeviceProtocolGuid ## PRODUCES + gSpiFlashPartProtocolGuid ## CONSUMES + +[Pcd] + gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdFlashAreaSize ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdBiosImageBase ## CONSUMES + gPlatformModuleTokenSpaceGuid.PcdBiosImageSize ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase ## CONSUMES + +[Depex] + gEfiSmmSpi2ProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmComm.h b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmComm.h new file mode 100644 index 0000000000..ee2d0a42a4 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmComm.h @@ -0,0 +1,73 @@ +/** @file + SMM Communication formats for the SPI Device protocols. + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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. + +**/ + +#ifndef _SPI_DEVICE_SMM_COMM_H_ +#define _SPI_DEVICE_SMM_COMM_H_ + +#include + +// +// Define communication constants +// +#define SPI_DEV_FUNCTION_READ 1 +#define SPI_DEV_FUNCTION_WRITE 2 +#define SPI_DEV_FUNCTION_ERASE 3 +#define SPI_DEV_FUNCTION_LOCK 4 +#define SPI_DEV_FUNCTION_SET_RANGE 5 +#define SPI_DEV_FUNCTION_LOCK_RANGES 6 + +// +// Generic SPI Device communication structure header. +// +typedef struct { + UINTN Function; + EFI_STATUS ReturnStatus; + UINT8 Data[1]; +} SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER; + +// +// Macros used to determine size of the headers without data size. +// +#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data)) +#define SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER_SIZE (OFFSET_OF (SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER, Data)) + +// +// SPI Read, Write and Erase Data. Erase will not have any extra data. +// +typedef struct { + UINTN Offset; + UINTN Size; +} SMM_SPI_DEV_READ_WRITE_ERASE_HEADER; + +// +// SPI Lock +// +typedef struct { + UINTN Offset; + UINTN Size; + BOOLEAN Lock; +} SMM_SPI_DEV_LOCK_HEADER; + +// +// SPI Set Range +// +typedef struct { + UINTN Offset; + UINTN Size; + BOOLEAN ReadLock; + BOOLEAN WriteLock; +} SMM_SPI_DEV_SET_RANGE_HEADER; + +#endif diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.c b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.c new file mode 100644 index 0000000000..392c549a95 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.c @@ -0,0 +1,437 @@ +/** @file + Provides an interface to the SMM SPI Device driver. + + gSpiDeviceProtocolGuid (DXE: SpiDeviceSmmDxe) + | + | via gEfiSmmCommunicationProtocolGuid + V + gSmmSpiDeviceProtocolGuid (SMM: SpiDeviceSmm) + | + | + V + gEfiSmmSpi2ProtocolGuid (SMM: SpiSmm) + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include +#include +#include +#include "SpiDevice.h" +#include "SpiDeviceSmmComm.h" + +EFI_SMM_COMMUNICATION_PROTOCOL *mSmmComm = NULL; + +SPI_DEVICE_PROTOCOL mSpiDevProtocol = { + SpiRead, + SpiWrite, + SpiErase, + SpiLock, + SpiSetRange, + SpiLockRanges +}; + +VOID +EFIAPI +SmmSpiDeviceReady ( + IN EFI_EVENT Event, + IN VOID *Context + ); + +EFI_STATUS +CreateCommBuffer ( + OUT VOID **CommBuffer, + OUT VOID **DataArea, + IN UINTN DataSize, + IN UINTN Function + ) +{ + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER *SmmSpiDevFunctionHeader; + + // + // Allocate communication buffer. + // + SmmCommunicateHeader = AllocatePool (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER_SIZE); + if (SmmCommunicateHeader == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Fill in new structure will data from caller. + // + CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gSmmSpiDeviceProtocolGuid); + SmmCommunicateHeader->MessageLength = DataSize + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER_SIZE; + SmmSpiDevFunctionHeader = (SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER*) SmmCommunicateHeader->Data; + SmmSpiDevFunctionHeader->Function = Function; + + // + // Assign return values. + // + *CommBuffer = SmmCommunicateHeader; + if (DataArea != NULL) { + *DataArea = SmmSpiDevFunctionHeader->Data; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +SendCommBuffer ( + IN OUT EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader, + IN UINTN DataSize + ) +{ + EFI_STATUS Status; + UINTN CommSize; + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER *SmmSpiDevFunctionHeader; + + // + // Compute actual size of communication data. + // + CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER_SIZE; + + // + // Send the message to be processed in SMM. + // + Status = mSmmComm->Communicate (mSmmComm, SmmCommunicateHeader, &CommSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Get the return value from the SMM function. + // + SmmSpiDevFunctionHeader = (SMM_SPI_DEV_COMMUNICATE_FUNCTION_HEADER*) SmmCommunicateHeader->Data; + + return SmmSpiDevFunctionHeader->ReturnStatus; +} + +EFI_STATUS +EFIAPI +SpiRead ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + OUT UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_READ_WRITE_ERASE_HEADER *SpiDevReadHeader; + + // + // Validate input parameters. + // + if (Size == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the actual data size required for the transaction. + // + DataSize = *Size + sizeof(SMM_SPI_DEV_READ_WRITE_ERASE_HEADER); + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, (VOID**) &SpiDevReadHeader, DataSize, SPI_DEV_FUNCTION_READ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in communication buffer parameters. + // + SpiDevReadHeader->Offset = SpiOffset; + SpiDevReadHeader->Size = *Size; + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, DataSize); + *Size = SpiDevReadHeader->Size; + if (!EFI_ERROR (Status)) { + CopyMem (Buffer, (UINT8*)(SpiDevReadHeader + 1), *Size); + } + + return Status; +} + +EFI_STATUS +EFIAPI +SpiWrite ( + IN UINTN SpiOffset, + IN OUT UINTN *Size, + IN UINT8 *Buffer + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_READ_WRITE_ERASE_HEADER *SpiDevWriteHeader; + + // + // Validate input parameters. + // + if (Size == NULL || Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Determine the actual data size required for the transaction. + // + DataSize = *Size + sizeof(SMM_SPI_DEV_READ_WRITE_ERASE_HEADER); + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, (VOID**) &SpiDevWriteHeader, DataSize, SPI_DEV_FUNCTION_WRITE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in communication buffer parameters. + // + SpiDevWriteHeader->Offset = SpiOffset; + SpiDevWriteHeader->Size = *Size; + CopyMem ((UINT8*)(SpiDevWriteHeader + 1), Buffer, *Size); + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, DataSize); + *Size = SpiDevWriteHeader->Size; + + return Status; +} + +EFI_STATUS +EFIAPI +SpiErase ( + IN UINTN SpiOffset, + IN OUT UINTN Size + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_READ_WRITE_ERASE_HEADER *SpiDevEraseHeader; + + // + // Determine the actual data size required for the transaction. + // + DataSize = sizeof(SMM_SPI_DEV_READ_WRITE_ERASE_HEADER); + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, (VOID**) &SpiDevEraseHeader, DataSize, SPI_DEV_FUNCTION_ERASE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in communication buffer parameters. + // + SpiDevEraseHeader->Offset = SpiOffset; + SpiDevEraseHeader->Size = Size; + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, DataSize); + + return Status; +} + +EFI_STATUS +EFIAPI +SpiLock ( + IN UINTN SpiOffset, + IN OUT UINTN Size, + IN BOOLEAN Lock + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_LOCK_HEADER *SmmSpiDevLockHeader; + + // + // Compute data size required for the transaction. + // + DataSize = sizeof(SMM_SPI_DEV_LOCK_HEADER); + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, (VOID**) &SmmSpiDevLockHeader, DataSize, SPI_DEV_FUNCTION_LOCK); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in communication buffer parameters. + // + SmmSpiDevLockHeader->Offset = SpiOffset; + SmmSpiDevLockHeader->Size = Size; + SmmSpiDevLockHeader->Lock = Lock; + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, DataSize); + + return Status; +} + +EFI_STATUS +EFIAPI +SpiSetRange ( + IN UINTN SpiOffset, + IN UINTN Size, + IN BOOLEAN ReadLock, + IN BOOLEAN WriteLock + ) +{ + EFI_STATUS Status; + UINTN DataSize; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + SMM_SPI_DEV_SET_RANGE_HEADER *SmmSpiDevSetRangeHeader; + + // + // Compute data size required for the transaction. + // + DataSize = sizeof(SMM_SPI_DEV_SET_RANGE_HEADER); + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, (VOID**) &SmmSpiDevSetRangeHeader, DataSize, SPI_DEV_FUNCTION_SET_RANGE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Fill in communication buffer parameters. + // + SmmSpiDevSetRangeHeader->Offset = SpiOffset; + SmmSpiDevSetRangeHeader->Size = Size; + SmmSpiDevSetRangeHeader->ReadLock = ReadLock; + SmmSpiDevSetRangeHeader->WriteLock = WriteLock; + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, DataSize); + + return Status; +} + +EFI_STATUS +EFIAPI +SpiLockRanges ( + ) +{ + EFI_STATUS Status; + EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; + + // + // Create the communication buffer. + // + Status = CreateCommBuffer ((VOID**) &SmmCommunicateHeader, NULL, 0, SPI_DEV_FUNCTION_LOCK_RANGES); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Communicate request to SMM driver and fill in return values. + // + Status = SendCommBuffer (SmmCommunicateHeader, 0); + + return Status; +} + +EFI_STATUS +EFIAPI +InitSpiDevice ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + VOID *SmmSpiDeviceReg; + + // + // Register for a callback when the SMM version of the SPI Device protocol + // is installed. + // + EfiCreateProtocolNotifyEvent ( + &gSmmSpiDeviceProtocolGuid, + TPL_CALLBACK, + SmmSpiDeviceReady, + NULL, + &SmmSpiDeviceReg + ); + + return EFI_SUCCESS; +} + +VOID +EFIAPI +SmmSpiDeviceReady ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_HANDLE Handle; + SPI_DEVICE_PROTOCOL *SmmSpiDevice; + EFI_STATUS Status; + + // + // Locate the protocol first just to make sure it was actually installed. + // + Status = gBS->LocateProtocol ( + &gSmmSpiDeviceProtocolGuid, + NULL, + (VOID **) &SmmSpiDevice + ); + if (EFI_ERROR (Status)) { + return; + } + + // + // SMM Service installed so get communication link to SMM + // + Status = gBS->LocateProtocol ( + &gEfiSmmCommunicationProtocolGuid, + NULL, + (VOID **) &mSmmComm + ); + ASSERT_EFI_ERROR (Status); + + // + // Install DXE protocol so it can be used by drivers. + // + Handle = NULL; + Status = gBS->InstallProtocolInterface ( + &Handle, + &gSpiDeviceProtocolGuid, + EFI_NATIVE_INTERFACE, + &mSpiDevProtocol + ); + ASSERT_EFI_ERROR (Status); +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.inf b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.inf new file mode 100644 index 0000000000..d7effc6668 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiDeviceDxe/SpiDeviceSmmDxe.inf @@ -0,0 +1,51 @@ +## @file +# SMM Based SPI Device Dxe Driver +# +# Adds platform support to configure the SPI controller with the correct values +# to be used when using software sequencing. This driver installs gSpiDeviceProtocolGuid +# protocol based on SMM based SPI device driver. +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = SpiDeviceSmmDxe + FILE_GUID = D7AC2008-CFBE-44A4-AD92-573F1AB9DF45 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InitSpiDevice + +[Sources] + SpiDeviceSmmDxe.c + SpiDevice.h + +[Packages] + ChvRefCodePkg/ChvRefCodePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[LibraryClasses] + DebugLib + DxeServicesTableLib + UefiBootServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gSpiDeviceProtocolGuid ## PRODUCES + gSmmSpiDeviceProtocolGuid ## CONSUMES + gEfiSmmCommunicationProtocolGuid ## CONSUMES + +[Depex] + gEfiSmmCommunicationProtocolGuid + diff --git a/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.c b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.c new file mode 100644 index 0000000000..424dcc3186 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.c @@ -0,0 +1,208 @@ +/** @file + MACRONIX MX25*** family SPI flash support + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include + +// +// Initialization data that can be used to identify SPI flash part +// DeviceId0 Device ID0 of the SPI device +// DeviceId1 Device ID1 of the SPI device +// +typedef struct _SPI_CHIP_ID { + UINT8 DeviceId0; + UINT8 DeviceId1; +} SPI_CHIP_ID; + +// +// Serial Flash VendorId and DeviceId +// +#define SF_VENDOR_ID_MACRONIX 0xC2 +#define SF_DEVICE_ID0_MX25LXX 0x20 +#define SF_DEVICE_ID0_MX25UXX 0x25 +#define SF_DEVICE_ID1_MX25L16 0x15 +#define SF_DEVICE_ID1_MX25L32 0x16 +#define SF_DEVICE_ID1_MX25L64 0x17 +#define SF_DEVICE_ID1_MX25L128 0x18 +#define SF_DEVICE_ID1_MX25U32 0x36 +#define SF_DEVICE_ID1_MX25U64 0x37 + +// +// Generic SPI flash part description +// +CONST FLASH_PART_DESCRIPTION mFlashDescription = { + L"MACRONIX MX25*** family", // Part number + 1, // Number of status bytes + 0x06, // Write enable + 0x50, // Write status enable + 3, // Length of JEDEC ID response + 8, // Number of opcodes in the table + + // Opcode table + { + {33000000, 3, FALSE, 0x9f, 0, SPI_FLASH_PART_OPCODE_JEDEC_ID}, + {50000000, 1, FALSE, 0x05, 0, SPI_FLASH_PART_OPCODE_READ_STATUS}, + {50000000, 1, TRUE, 0x01, 0, SPI_FLASH_PART_OPCODE_WRITE_STATUS}, + {33000000, 0xffffffff, FALSE, 0x03, 3, SPI_FLASH_PART_OPCODE_READ_BYTES}, + {50000000, 1, TRUE, 0x02, 3, SPI_FLASH_PART_OPCODE_WRITE_256_BYTE_PAGE}, + {50000000, 0, TRUE, 0x20, 3, SPI_FLASH_PART_OPCODE_ERASE_4K_BYTE_BLOCK}, + {50000000, 0, TRUE, 0xd8, 3, SPI_FLASH_PART_OPCODE_ERASE_64K_BYTE_BLOCK}, + {50000000, 0, TRUE, 0x5a, 0, SPI_FLASH_PART_OPCODE_WRITE_DISABLE_DISCOVERY} + } +}; + +SPI_CHIP_ID mSpiChipIdTable[] = { + { + SF_DEVICE_ID0_MX25LXX, // DeviceId 0 + SF_DEVICE_ID1_MX25L16 // DeviceId 1 + }, + { + SF_DEVICE_ID0_MX25LXX, // DeviceId 0 + SF_DEVICE_ID1_MX25L32 // DeviceId 1 + }, + { + SF_DEVICE_ID0_MX25LXX, // DeviceId 0 + SF_DEVICE_ID1_MX25L64 // DeviceId 1 + }, + { + SF_DEVICE_ID0_MX25LXX, // DeviceId 0 + SF_DEVICE_ID1_MX25L128 // DeviceId 1 + }, + { + SF_DEVICE_ID0_MX25UXX, // DeviceId 0 + SF_DEVICE_ID1_MX25U32 // DeviceId 1 + }, + { + SF_DEVICE_ID0_MX25UXX, // DeviceId 0 + SF_DEVICE_ID1_MX25U64 // DeviceId 1 + } +}; + +/** + Get the flash part size and opcode table. + + Validate support for this flash part and determine + the flash part size and opcode description table + from the JEDEC ID information provided. + + @param[in] This Pointer to a SPI_FLASH_DATA_PROTOCOL + data structure. + @param[in] JedecId Pointer to a three byte buffer containing + the JEDEC ID returned by the flash part. + If the input value is NULL then a + table containing the description for the + JEDEC ID opcode is returned by this + routine. + @param[out] FlashSize Pointer to receive the size of the flash + part in bytes. Zero (0) is returned when + JedecId is NULL. + @returns When JedecId is not NULL, this routine returns a pointer + to a FLASH_PART_DESCRIPTION data structure which supports + this flash part. The returned value is NULL if the flash + part is not supported. + When JedecId is NULL, this routine returns a pointer to + a FLASH_PART_DESCRIPTION structure which supports the + JEDEC ID command. This opcode description may be used + to determine the manufacture and product data for the + SPI flash part. + +**/ +CONST FLASH_PART_DESCRIPTION * +EFIAPI +GetFlashDescription ( + IN SPI_FLASH_PART_PROTOCOL *This, + IN UINT8 *JedecId OPTIONAL, + OUT UINT64 *FlashSize OPTIONAL + ) +{ + CONST FLASH_PART_DESCRIPTION *FlashDescription; + UINT8 Shift; + UINT64 Size; + UINTN Index; + + // + // Determine if the SPI flash device is supported + // + Size = 0; + FlashDescription = &mFlashDescription; + if (JedecId != NULL) { + FlashDescription = NULL; + if (JedecId [0] != SF_VENDOR_ID_MACRONIX) + return NULL; + + for (Index = 0;Index < (sizeof (mSpiChipIdTable) / sizeof (SPI_CHIP_ID));Index++) { + if ((JedecId [1] == mSpiChipIdTable[Index].DeviceId0) + && (JedecId [2] == mSpiChipIdTable[Index].DeviceId1)) + break; + } + + if (Index >= (sizeof (mSpiChipIdTable) / sizeof (SPI_CHIP_ID))) + return NULL; + + Shift = JedecId[2]; + + if (JedecId [1] == SF_DEVICE_ID0_MX25UXX) + Shift-= 0x20; + + if (Shift < 64) { + Size = LShiftU64 (1, Shift); + FlashDescription = &mFlashDescription; + } + } + + // + // Return the flash size + // + if (FlashSize != NULL) { + *FlashSize = Size; + } + + return FlashDescription; +} + +SPI_FLASH_PART_PROTOCOL mSpiFlashPartProtocol = { + 0xC0000000, /// SPI flash part family priority + GetFlashDescription +}; + +/** + Indicate that all the SPI devices are available + + @retval EFI_SUCCESS SPI flash part protocol installed successfully + +**/ +EFI_STATUS +EFIAPI +SpiFlashPart ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install the SPI flash part protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gImageHandle, + &gSpiFlashPartProtocolGuid, + &mSpiFlashPartProtocol, + NULL + ); + + return Status; +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.inf b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.inf new file mode 100644 index 0000000000..aae1c00e9e --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/MX25/MX25.inf @@ -0,0 +1,41 @@ +## @file +# MACRONIX* MX25*** family SPI flash support +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = MX25XXX + FILE_GUID = FB7900FB-BC92-4a34-BFB6-8CC0E63B52FC + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SpiFlashPart + +[Sources] + MX25.c + +[Packages] + MdePkg/MdePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + UefiBootServicesTableLib + +[Protocols] + gSpiFlashPartProtocolGuid ## PRODUCES + +[Depex] + TRUE + diff --git a/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.c b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.c new file mode 100644 index 0000000000..b23351d23d --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.c @@ -0,0 +1,192 @@ +/** @file + WINBOND W25*** family SPI flash support + + Copyright (c) 2015, Intel Corporation. All rights reserved.
+ + 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 +#include +#include +#include +#include + + +// +// Initialization data that can be used to identify SPI flash part +// DeviceId0 Device ID0 of the SPI device +// DeviceId1 Device ID1 of the SPI device +// +typedef struct _SPI_CHIP_ID { + UINT8 DeviceId0; + UINT8 DeviceId1; +} SPI_CHIP_ID; + +// +// Flash VendorId and DeviceId +// + +#define SF_VENDOR_ID_WINBOND 0xEF +#define SF_DEVICE_ID0_W25XXX 0x30 +#define SF_DEVICE_ID1_W25X32 0x16 +#define SF_DEVICE_ID1_W25X64 0x17 +#define SF_DEVICE_ID0_W25QXX 0x60 +#define SF_DEVICE_ID0_W25QXX2 0x40 +#define SF_DEVICE_ID1_W25Q16 0x15 +#define SF_DEVICE_ID1_W25Q32 0x16 +#define SF_DEVICE_ID1_W25Q64 0x17 +#define SF_DEVICE_ID1_W25Q128 0x18 + +// +// Generic SPI flash part description +// +CONST FLASH_PART_DESCRIPTION mFlashDescription = { + L"WINBOND W25Q*** family", // Part number + 1, // Number of status bytes + 0x06, // Write enable + 0x50, // Write status enable + 3, // Length of JEDEC ID response + 8, // Number of opcodes in the table + + // Opcode table + { + {33000000, 3, FALSE, 0x9f, 0, SPI_FLASH_PART_OPCODE_JEDEC_ID}, + {50000000, 1, FALSE, 0x05, 0, SPI_FLASH_PART_OPCODE_READ_STATUS}, + {50000000, 1, TRUE, 0x01, 0, SPI_FLASH_PART_OPCODE_WRITE_STATUS}, + {33000000, 0xffffffff, FALSE, 0x03, 3, SPI_FLASH_PART_OPCODE_READ_BYTES}, + {50000000, 1, TRUE, 0x02, 3, SPI_FLASH_PART_OPCODE_WRITE_256_BYTE_PAGE}, + {50000000, 0, TRUE, 0x20, 3, SPI_FLASH_PART_OPCODE_ERASE_4K_BYTE_BLOCK}, + {50000000, 0, TRUE, 0xd8, 3, SPI_FLASH_PART_OPCODE_ERASE_64K_BYTE_BLOCK}, + {50000000, 0, TRUE, 0x5a, 0, SPI_FLASH_PART_OPCODE_WRITE_DISABLE_DISCOVERY} + } +}; + +SPI_CHIP_ID mSpiChipIdTable[] = { + { + SF_DEVICE_ID0_W25QXX, // DeviceId 0 + SF_DEVICE_ID1_W25Q64 // DeviceId 1 + }, + { + SF_DEVICE_ID0_W25QXX2, // DeviceId 0 + SF_DEVICE_ID1_W25Q64 // DeviceId 1 + } +}; + +/** + Get the flash part size and opcode table. + + Validate support for this flash part and determine + the flash part size and opcode description table + from the JEDEC ID information provided. + + @param[in] This Pointer to a SPI_FLASH_DATA_PROTOCOL + data structure. + @param[in] JedecId Pointer to a three byte buffer containing + the JEDEC ID returned by the flash part. + If the input value is NULL then a + table containing the description for the + JEDEC ID opcode is returned by this + routine. + @param[out] FlashSize Pointer to receive the size of the flash + part in bytes. Zero (0) is returned when + JedecId is NULL. + @returns When JedecId is not NULL, this routine returns a pointer + to a FLASH_PART_DESCRIPTION data structure which supports + this flash part. The returned value is NULL if the flash + part is not supported. + When JedecId is NULL, this routine returns a pointer to + a FLASH_PART_DESCRIPTION structure which supports the + JEDEC ID command. This opcode description may be used + to determine the manufacture and product data for the + SPI flash part. + +**/ +CONST FLASH_PART_DESCRIPTION * +EFIAPI +GetFlashDescription ( + IN SPI_FLASH_PART_PROTOCOL *This, + IN UINT8 *JedecId OPTIONAL, + OUT UINT64 *FlashSize OPTIONAL + ) +{ + CONST FLASH_PART_DESCRIPTION *FlashDescription; + UINT8 Shift; + UINT64 Size; + UINTN Index; + + // + // Determine if the SPI flash device is supported + // + Size = 0; + FlashDescription = &mFlashDescription; + if (JedecId != NULL) { + FlashDescription = NULL; + if (JedecId [0] != SF_VENDOR_ID_WINBOND) + return NULL; + + for (Index = 0;Index < (sizeof (mSpiChipIdTable) / sizeof (SPI_CHIP_ID));Index++) { + if ((JedecId [1] == mSpiChipIdTable[Index].DeviceId0) + && (JedecId [2] == mSpiChipIdTable[Index].DeviceId1)) + break; + } + + if (Index >= (sizeof (mSpiChipIdTable) / sizeof (SPI_CHIP_ID))) + return NULL; + + Shift = JedecId[2]; + if (Shift < 64) { + Size = LShiftU64 (1, Shift); + FlashDescription = &mFlashDescription; + } + } + + // + // Return the flash size + // + if (FlashSize != NULL) { + *FlashSize = Size; + } + + return FlashDescription; +} + +SPI_FLASH_PART_PROTOCOL mSpiFlashPartProtocol = { + 0xC0000000, /// SPI flash part family priority + GetFlashDescription +}; + +/** + Indicate that all the SPI devices are available + + @retval EFI_SUCCESS SPI flash part protocol installed successfully + +**/ +EFI_STATUS +EFIAPI +SpiFlashPart ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + // + // Install the SPI flash part protocol + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gImageHandle, + &gSpiFlashPartProtocolGuid, + &mSpiFlashPartProtocol, + NULL + ); + + return Status; +} diff --git a/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.inf b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.inf new file mode 100644 index 0000000000..d48ca15a09 --- /dev/null +++ b/BraswellPlatformPkg/Common/Flash/SpiFlashParts/W25/W25.inf @@ -0,0 +1,41 @@ +## @file +# WINBOND W25*** family SPI flash support +# +# Copyright (c) 2015, Intel Corporation. All rights reserved.
+# +# 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 = 0x00010018 + BASE_NAME = W25XXX + FILE_GUID = 1EAFA124-4F73-45B3-B749-8E7F80741CE4 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = SpiFlashPart + +[Sources] + W25.c + +[Packages] + MdePkg/MdePkg.dec + BraswellPlatformPkg/BraswellPlatformPkg.dec + +[LibraryClasses] + UefiDriverEntryPoint + BaseLib + UefiBootServicesTableLib + +[Protocols] + gSpiFlashPartProtocolGuid ## PRODUCES + +[Depex] + TRUE + -- cgit v1.2.3