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