+++ /dev/null
-/** @file NorFlashStandaloneMm.c\r
-\r
- Copyright (c) 2011 - 2021, Arm Limited. All rights reserved.<BR>\r
- Copyright (c) 2020, Linaro, Ltd. All rights reserved.<BR>\r
-\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include <Library/BaseMemoryLib.h>\r
-#include <Library/MemoryAllocationLib.h>\r
-#include <Library/MmServicesTableLib.h>\r
-\r
-#include "NorFlash.h"\r
-\r
-//\r
-// Global variable declarations\r
-//\r
-NOR_FLASH_INSTANCE **mNorFlashInstances;\r
-UINT32 mNorFlashDeviceCount;\r
-UINTN mFlashNvStorageVariableBase;\r
-\r
-NOR_FLASH_INSTANCE mNorFlashInstanceTemplate = {\r
- NOR_FLASH_SIGNATURE, // Signature\r
- NULL, // Handle ... NEED TO BE FILLED\r
-\r
- 0, // DeviceBaseAddress ... NEED TO BE FILLED\r
- 0, // RegionBaseAddress ... NEED TO BE FILLED\r
- 0, // Size ... NEED TO BE FILLED\r
- 0, // StartLba\r
-\r
- {\r
- EFI_BLOCK_IO_PROTOCOL_REVISION2, // Revision\r
- NULL, // Media ... NEED TO BE FILLED\r
- NULL, // Reset;\r
- NULL, // ReadBlocks\r
- NULL, // WriteBlocks\r
- NULL // FlushBlocks\r
- }, // BlockIoProtocol\r
-\r
- {\r
- 0, // MediaId ... NEED TO BE FILLED\r
- FALSE, // RemovableMedia\r
- TRUE, // MediaPresent\r
- FALSE, // LogicalPartition\r
- FALSE, // ReadOnly\r
- FALSE, // WriteCaching;\r
- 0, // BlockSize ... NEED TO BE FILLED\r
- 4, // IoAlign\r
- 0, // LastBlock ... NEED TO BE FILLED\r
- 0, // LowestAlignedLba\r
- 1, // LogicalBlocksPerPhysicalBlock\r
- }, // Media;\r
-\r
- {\r
- EFI_DISK_IO_PROTOCOL_REVISION, // Revision\r
- NULL, // ReadDisk\r
- NULL // WriteDisk\r
- },\r
-\r
- {\r
- FvbGetAttributes, // GetAttributes\r
- FvbSetAttributes, // SetAttributes\r
- FvbGetPhysicalAddress, // GetPhysicalAddress\r
- FvbGetBlockSize, // GetBlockSize\r
- FvbRead, // Read\r
- FvbWrite, // Write\r
- FvbEraseBlocks, // EraseBlocks\r
- NULL, // ParentHandle\r
- }, // FvbProtoccol;\r
- NULL, // ShadowBuffer\r
- {\r
- {\r
- {\r
- HARDWARE_DEVICE_PATH,\r
- HW_VENDOR_DP,\r
- {\r
- (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End)),\r
- (UINT8)(OFFSET_OF (NOR_FLASH_DEVICE_PATH, End) >> 8)\r
- }\r
- },\r
- { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }\r
- }, // GUID ... NEED TO BE FILLED\r
- },\r
- 0, // Index\r
- {\r
- END_DEVICE_PATH_TYPE,\r
- END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
- { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }\r
- }\r
- } // DevicePath\r
-};\r
-\r
-EFI_STATUS\r
-NorFlashCreateInstance (\r
- IN UINTN NorFlashDeviceBase,\r
- IN UINTN NorFlashRegionBase,\r
- IN UINTN NorFlashSize,\r
- IN UINT32 Index,\r
- IN UINT32 BlockSize,\r
- IN BOOLEAN SupportFvb,\r
- OUT NOR_FLASH_INSTANCE **NorFlashInstance\r
- )\r
-{\r
- EFI_STATUS Status;\r
- NOR_FLASH_INSTANCE *Instance;\r
-\r
- ASSERT (NorFlashInstance != NULL);\r
-\r
- Instance = AllocateRuntimeCopyPool (sizeof (NOR_FLASH_INSTANCE), &mNorFlashInstanceTemplate);\r
- if (Instance == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Instance->DeviceBaseAddress = NorFlashDeviceBase;\r
- Instance->RegionBaseAddress = NorFlashRegionBase;\r
- Instance->Size = NorFlashSize;\r
-\r
- Instance->BlockIoProtocol.Media = &Instance->Media;\r
- Instance->Media.MediaId = Index;\r
- Instance->Media.BlockSize = BlockSize;\r
- Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;\r
-\r
- CopyGuid (&Instance->DevicePath.Vendor.Guid, &gEfiCallerIdGuid);\r
- Instance->DevicePath.Index = (UINT8)Index;\r
-\r
- Instance->ShadowBuffer = AllocateRuntimePool (BlockSize);\r
- if (Instance->ShadowBuffer == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- if (SupportFvb) {\r
- NorFlashFvbInitialize (Instance);\r
-\r
- Status = gMmst->MmInstallProtocolInterface (\r
- &Instance->Handle,\r
- &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
- EFI_NATIVE_INTERFACE,\r
- &Instance->FvbProtocol\r
- );\r
- if (EFI_ERROR (Status)) {\r
- FreePool (Instance);\r
- return Status;\r
- }\r
- } else {\r
- DEBUG ((DEBUG_ERROR, "standalone MM NOR Flash driver only support FVB.\n"));\r
- FreePool (Instance);\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- *NorFlashInstance = Instance;\r
- return Status;\r
-}\r
-\r
-/**\r
- * This function unlock and erase an entire NOR Flash block.\r
- **/\r
-EFI_STATUS\r
-NorFlashUnlockAndEraseSingleBlock (\r
- IN NOR_FLASH_INSTANCE *Instance,\r
- IN UINTN BlockAddress\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN Index;\r
-\r
- Index = 0;\r
- // The block erase might fail a first time (SW bug ?). Retry it ...\r
- do {\r
- // Unlock the block if we have to\r
- Status = NorFlashUnlockSingleBlockIfNecessary (Instance, BlockAddress);\r
- if (EFI_ERROR (Status)) {\r
- break;\r
- }\r
-\r
- Status = NorFlashEraseSingleBlock (Instance, BlockAddress);\r
- Index++;\r
- } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));\r
-\r
- if (Index == NOR_FLASH_ERASE_RETRY) {\r
- DEBUG ((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress, Index));\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-NorFlashWriteFullBlock (\r
- IN NOR_FLASH_INSTANCE *Instance,\r
- IN EFI_LBA Lba,\r
- IN UINT32 *DataBuffer,\r
- IN UINT32 BlockSizeInWords\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINTN WordAddress;\r
- UINT32 WordIndex;\r
- UINTN BufferIndex;\r
- UINTN BlockAddress;\r
- UINTN BuffersInBlock;\r
- UINTN RemainingWords;\r
- UINTN Cnt;\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- // Get the physical address of the block\r
- BlockAddress = GET_NOR_BLOCK_ADDRESS (Instance->RegionBaseAddress, Lba, BlockSizeInWords * 4);\r
-\r
- // Start writing from the first address at the start of the block\r
- WordAddress = BlockAddress;\r
-\r
- Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "WriteSingleBlock: ERROR - Failed to Unlock and Erase the single block at 0x%X\n", BlockAddress));\r
- goto EXIT;\r
- }\r
-\r
- // To speed up the programming operation, NOR Flash is programmed using the Buffered Programming method.\r
-\r
- // Check that the address starts at a 32-word boundary, i.e. last 7 bits must be zero\r
- if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {\r
- // First, break the entire block into buffer-sized chunks.\r
- BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;\r
-\r
- // Then feed each buffer chunk to the NOR Flash\r
- // If a buffer does not contain any data, don't write it.\r
- for (BufferIndex = 0;\r
- BufferIndex < BuffersInBlock;\r
- BufferIndex++, WordAddress += P30_MAX_BUFFER_SIZE_IN_BYTES, DataBuffer += P30_MAX_BUFFER_SIZE_IN_WORDS\r
- )\r
- {\r
- // Check the buffer to see if it contains any data (not set all 1s).\r
- for (Cnt = 0; Cnt < P30_MAX_BUFFER_SIZE_IN_WORDS; Cnt++) {\r
- if (~DataBuffer[Cnt] != 0 ) {\r
- // Some data found, write the buffer.\r
- Status = NorFlashWriteBuffer (\r
- Instance,\r
- WordAddress,\r
- P30_MAX_BUFFER_SIZE_IN_BYTES,\r
- DataBuffer\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT;\r
- }\r
-\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // Finally, finish off any remaining words that are less than the maximum size of the buffer\r
- RemainingWords = BlockSizeInWords % P30_MAX_BUFFER_SIZE_IN_WORDS;\r
-\r
- if (RemainingWords != 0) {\r
- Status = NorFlashWriteBuffer (Instance, WordAddress, (RemainingWords * 4), DataBuffer);\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT;\r
- }\r
- }\r
- } else {\r
- // For now, use the single word programming algorithm\r
- // It is unlikely that the NOR Flash will exist in an address which falls within a 32 word boundary range,\r
- // i.e. which ends in the range 0x......01 - 0x......7F.\r
- for (WordIndex = 0; WordIndex < BlockSizeInWords; WordIndex++, DataBuffer++, WordAddress = WordAddress + 4) {\r
- Status = NorFlashWriteSingleWord (Instance, WordAddress, *DataBuffer);\r
- if (EFI_ERROR (Status)) {\r
- goto EXIT;\r
- }\r
- }\r
- }\r
-\r
-EXIT:\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-NorFlashInitialise (\r
- IN EFI_HANDLE ImageHandle,\r
- IN EFI_MM_SYSTEM_TABLE *MmSystemTable\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 Index;\r
- NOR_FLASH_DESCRIPTION *NorFlashDevices;\r
- BOOLEAN ContainVariableStorage;\r
-\r
- Status = NorFlashPlatformInitialization ();\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to initialize Nor Flash devices\n"));\r
- return Status;\r
- }\r
-\r
- Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to get Nor Flash devices\n"));\r
- return Status;\r
- }\r
-\r
- mNorFlashInstances = AllocatePool (sizeof (NOR_FLASH_INSTANCE *) * mNorFlashDeviceCount);\r
-\r
- for (Index = 0; Index < mNorFlashDeviceCount; Index++) {\r
- // Check if this NOR Flash device contain the variable storage region\r
-\r
- if (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) != 0) {\r
- ContainVariableStorage =\r
- (NorFlashDevices[Index].RegionBaseAddress <= FixedPcdGet64 (PcdFlashNvStorageVariableBase64)) &&\r
- (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) + FixedPcdGet32 (PcdFlashNvStorageVariableSize) <=\r
- NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);\r
- } else {\r
- ContainVariableStorage =\r
- (NorFlashDevices[Index].RegionBaseAddress <= FixedPcdGet32 (PcdFlashNvStorageVariableBase)) &&\r
- (FixedPcdGet32 (PcdFlashNvStorageVariableBase) + FixedPcdGet32 (PcdFlashNvStorageVariableSize) <=\r
- NorFlashDevices[Index].RegionBaseAddress + NorFlashDevices[Index].Size);\r
- }\r
-\r
- Status = NorFlashCreateInstance (\r
- NorFlashDevices[Index].DeviceBaseAddress,\r
- NorFlashDevices[Index].RegionBaseAddress,\r
- NorFlashDevices[Index].Size,\r
- Index,\r
- NorFlashDevices[Index].BlockSize,\r
- ContainVariableStorage,\r
- &mNorFlashInstances[Index]\r
- );\r
- if (EFI_ERROR (Status)) {\r
- DEBUG ((DEBUG_ERROR, "NorFlashInitialise: Fail to create instance for NorFlash[%d]\n", Index));\r
- }\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-EFI_STATUS\r
-EFIAPI\r
-NorFlashFvbInitialize (\r
- IN NOR_FLASH_INSTANCE *Instance\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 FvbNumLba;\r
-\r
- ASSERT ((Instance != NULL));\r
-\r
- mFlashNvStorageVariableBase = (FixedPcdGet64 (PcdFlashNvStorageVariableBase64) != 0) ?\r
- FixedPcdGet64 (PcdFlashNvStorageVariableBase64) : FixedPcdGet32 (PcdFlashNvStorageVariableBase);\r
- // Set the index of the first LBA for the FVB\r
- Instance->StartLba = (mFlashNvStorageVariableBase - Instance->RegionBaseAddress) / Instance->Media.BlockSize;\r
-\r
- // Determine if there is a valid header at the beginning of the NorFlash\r
- Status = ValidateFvHeader (Instance);\r
-\r
- // Install the Default FVB header if required\r
- if (EFI_ERROR (Status)) {\r
- // There is no valid header, so time to install one.\r
- DEBUG ((DEBUG_INFO, "%a: The FVB Header is not valid.\n", __FUNCTION__));\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "%a: Installing a correct one for this volume.\n",\r
- __FUNCTION__\r
- ));\r
-\r
- // Erase all the NorFlash that is reserved for variable storage\r
- FvbNumLba = (PcdGet32 (PcdFlashNvStorageVariableSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) + PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / Instance->Media.BlockSize;\r
-\r
- Status = FvbEraseBlocks (&Instance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- // Install all appropriate headers\r
- Status = InitializeFvAndVariableStoreHeaders (Instance);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- return Status;\r
-}\r