]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashFvbDxe.c
ArmPlatformPkg/Drivers/NorFlashDxe: Directly implement DiskIO protocol
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashFvbDxe.c
index 0c138a5ab2e7cb15203ed706ea9cbec7de4d11c6..bf420853b0a173d96cbb37a163f11ae2fac2eec2 100644 (file)
@@ -1,6 +1,6 @@
 /*++ @file  NorFlashFvbDxe.c\r
 \r
 /*++ @file  NorFlashFvbDxe.c\r
 \r
- Copyright (c) 2011-2012, ARM Ltd. All rights reserved.<BR>\r
+ Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>\r
 \r
  This program and the accompanying materials\r
  are licensed and made available under the terms and conditions of the BSD License\r
 \r
  This program and the accompanying materials\r
  are licensed and made available under the terms and conditions of the BSD License\r
@@ -20,6 +20,7 @@
 #include <Library/UefiLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Library/BaseMemoryLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
+#include <Library/DxeServicesTableLib.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include <Guid/VariableFormat.h>\r
 #include <Library/UefiBootServicesTableLib.h>\r
 \r
 #include <Guid/VariableFormat.h>\r
@@ -27,6 +28,8 @@
 \r
 #include "NorFlashDxe.h"\r
 \r
 \r
 #include "NorFlashDxe.h"\r
 \r
+STATIC EFI_EVENT mFvbVirtualAddrChangeEvent;\r
+STATIC UINTN     mFlashNvStorageVariableBase;\r
 \r
 ///\r
 /// The Firmware Volume Block Protocol is the low-level interface\r
 \r
 ///\r
 /// The Firmware Volume Block Protocol is the low-level interface\r
@@ -107,7 +110,7 @@ InitializeFvAndVariableStoreHeaders (
   //\r
   // VARIABLE_STORE_HEADER\r
   //\r
   //\r
   // VARIABLE_STORE_HEADER\r
   //\r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINT32)Headers + FirmwareVolumeHeader->HeaderLength);\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);\r
   CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);\r
   VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;\r
   VariableStoreHeader->Format            = VARIABLE_STORE_FORMATTED;\r
   CopyGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid);\r
   VariableStoreHeader->Size = PcdGet32(PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;\r
   VariableStoreHeader->Format            = VARIABLE_STORE_FORMATTED;\r
@@ -172,7 +175,7 @@ ValidateFvHeader (
     return EFI_NOT_FOUND;\r
   }\r
 \r
     return EFI_NOT_FOUND;\r
   }\r
 \r
-  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINT32)FwVolHeader + FwVolHeader->HeaderLength);\r
+  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);\r
 \r
   // Check the Variable Store Guid\r
   if( CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) == FALSE ) {\r
 \r
   // Check the Variable Store Guid\r
   if( CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) == FALSE ) {\r
@@ -301,7 +304,7 @@ FvbGetPhysicalAddress (
 \r
   ASSERT(Address != NULL);\r
 \r
 \r
   ASSERT(Address != NULL);\r
 \r
-  *Address = PcdGet32 (PcdFlashNvStorageVariableBase);\r
+  *Address = mFlashNvStorageVariableBase;\r
   return EFI_SUCCESS;\r
 }\r
 \r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -414,10 +417,8 @@ FvbRead (
   IN OUT    UINT8                                 *Buffer\r
   )\r
 {\r
   IN OUT    UINT8                                 *Buffer\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
   EFI_STATUS    TempStatus;\r
   UINTN         BlockSize;\r
   EFI_STATUS    TempStatus;\r
   UINTN         BlockSize;\r
-  UINT8         *BlockBuffer;\r
   NOR_FLASH_INSTANCE *Instance;\r
 \r
   Instance = INSTANCE_FROM_FVB_THIS(This);\r
   NOR_FLASH_INSTANCE *Instance;\r
 \r
   Instance = INSTANCE_FROM_FVB_THIS(This);\r
@@ -428,8 +429,7 @@ FvbRead (
     Instance->Initialize(Instance);\r
   }\r
 \r
     Instance->Initialize(Instance);\r
   }\r
 \r
-  Status = EFI_SUCCESS;\r
-  TempStatus = Status;\r
+  TempStatus = EFI_SUCCESS;\r
 \r
   // Cache the block size to avoid de-referencing pointers all the time\r
   BlockSize = Instance->Media.BlockSize;\r
 \r
   // Cache the block size to avoid de-referencing pointers all the time\r
   BlockSize = Instance->Media.BlockSize;\r
@@ -450,33 +450,21 @@ FvbRead (
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
 \r
-  // FixMe: Allow an arbitrary number of bytes to be read out, not just a multiple of block size.\r
-\r
-  // Allocate runtime memory to read in the NOR Flash data. Variable Services are runtime.\r
-  BlockBuffer = AllocateRuntimePool (BlockSize);\r
-\r
-  // Check if the memory allocation was successful\r
-  if (BlockBuffer == NULL) {\r
-    DEBUG ((EFI_D_ERROR, "FvbRead: ERROR - Could not allocate BlockBuffer @ 0x%08x.\n", BlockBuffer));\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  // Read NOR Flash data into shadow buffer\r
-  TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer);\r
-  if (EFI_ERROR (TempStatus)) {\r
-    // Return one of the pre-approved error statuses\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto FREE_MEMORY;\r
+  // Decide if we are doing full block reads or not.\r
+  if (*NumBytes % BlockSize != 0) {\r
+    TempStatus = NorFlashRead (Instance, Instance->StartLba + Lba, Offset, *NumBytes, Buffer);\r
+    if (EFI_ERROR (TempStatus)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+  } else {\r
+    // Read NOR Flash data into shadow buffer\r
+    TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, Buffer);\r
+    if (EFI_ERROR (TempStatus)) {\r
+      // Return one of the pre-approved error statuses\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
   }\r
   }\r
-\r
-  // Put the data at the appropriate location inside the buffer area\r
-  DEBUG ((DEBUG_BLKIO, "FvbRead: CopyMem( Dst=0x%08x, Src=0x%08x, Size=0x%x ).\n", Buffer, BlockBuffer + Offset, *NumBytes));\r
-\r
-  CopyMem(Buffer, BlockBuffer + Offset, *NumBytes);\r
-\r
-FREE_MEMORY:\r
-  FreePool(BlockBuffer);\r
-  return Status;\r
+  return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -543,81 +531,11 @@ FvbWrite (
   IN        UINT8                                 *Buffer\r
   )\r
 {\r
   IN        UINT8                                 *Buffer\r
   )\r
 {\r
-  EFI_STATUS  Status;\r
-  EFI_STATUS  TempStatus;\r
-  UINTN       BlockSize;\r
-  UINT8       *BlockBuffer;\r
   NOR_FLASH_INSTANCE *Instance;\r
 \r
   NOR_FLASH_INSTANCE *Instance;\r
 \r
-  Instance = INSTANCE_FROM_FVB_THIS(This);\r
-\r
-  if (!Instance->Initialized && Instance->Initialize) {\r
-    Instance->Initialize(Instance);\r
-  }\r
-\r
-  DEBUG ((DEBUG_BLKIO, "FvbWrite(Parameters: Lba=%ld, Offset=0x%x, *NumBytes=0x%x, Buffer @ 0x%08x)\n", Instance->StartLba + Lba, Offset, *NumBytes, Buffer));\r
-\r
-  Status = EFI_SUCCESS;\r
-  TempStatus = Status;\r
-\r
-  // Detect WriteDisabled state\r
-  if (Instance->Media.ReadOnly == TRUE) {\r
-    DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Can not write: Device is in WriteDisabled state.\n"));\r
-    // It is in WriteDisabled state, return an error right away\r
-    return EFI_ACCESS_DENIED;\r
-  }\r
-\r
-  // Cache the block size to avoid de-referencing pointers all the time\r
-  BlockSize = Instance->Media.BlockSize;\r
-\r
-  // The write must not span block boundaries.\r
-  // We need to check each variable individually because adding two large values together overflows.\r
-  if ( ( Offset               >= BlockSize ) ||\r
-       ( *NumBytes            >  BlockSize ) ||\r
-       ( (Offset + *NumBytes) >  BlockSize )    ) {\r
-    DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\r
-\r
-  // We must have some bytes to write\r
-  if (*NumBytes == 0) {\r
-    DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, *NumBytes, BlockSize ));\r
-    return EFI_BAD_BUFFER_SIZE;\r
-  }\r
+  Instance = INSTANCE_FROM_FVB_THIS (This);\r
 \r
 \r
-  // Allocate runtime memory to read in the NOR Flash data.\r
-  // Since the intention is to use this with Variable Services and since these are runtime,\r
-  // allocate the memory from the runtime pool.\r
-  BlockBuffer = AllocateRuntimePool (BlockSize);\r
-\r
-  // Check we did get some memory\r
-  if( BlockBuffer == NULL ) {\r
-    DEBUG ((EFI_D_ERROR, "FvbWrite: ERROR - Can not allocate BlockBuffer @ 0x%08x.\n", BlockBuffer));\r
-    return EFI_DEVICE_ERROR;\r
-  }\r
-\r
-  // Read NOR Flash data into shadow buffer\r
-  TempStatus = NorFlashReadBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer);\r
-  if (EFI_ERROR (TempStatus)) {\r
-    // Return one of the pre-approved error statuses\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto FREE_MEMORY;\r
-  }\r
-\r
-  // Put the data at the appropriate location inside the buffer area\r
-  CopyMem((BlockBuffer + Offset), Buffer, *NumBytes);\r
-\r
-  // Write the modified buffer back to the NorFlash\r
-  Status = NorFlashWriteBlocks (Instance, Instance->StartLba + Lba, BlockSize, BlockBuffer);\r
-  if (EFI_ERROR (TempStatus)) {\r
-    // Return one of the pre-approved error statuses\r
-    Status = EFI_DEVICE_ERROR;\r
-    goto FREE_MEMORY;\r
-  }\r
-\r
-FREE_MEMORY:\r
-  FreePool(BlockBuffer);\r
-  return Status;\r
+  return NorFlashWriteSingleBlock (Instance, Lba, Offset, NumBytes, Buffer);\r
 }\r
 \r
 /**\r
 }\r
 \r
 /**\r
@@ -764,6 +682,25 @@ EXIT:
   return Status;\r
 }\r
 \r
   return Status;\r
 }\r
 \r
+/**\r
+  Fixup internal data so that EFI can be call in virtual mode.\r
+  Call the passed in Child Notify event and convert any pointers in\r
+  lib to virtual mode.\r
+\r
+  @param[in]    Event   The Event that is being processed\r
+  @param[in]    Context Event Context\r
+**/\r
+VOID\r
+EFIAPI\r
+FvbVirtualNotifyEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);\r
+  return;\r
+}\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 NorFlashFvbInitialize (\r
 EFI_STATUS\r
 EFIAPI\r
 NorFlashFvbInitialize (\r
@@ -773,10 +710,12 @@ NorFlashFvbInitialize (
   EFI_STATUS  Status;\r
   UINT32      FvbNumLba;\r
   EFI_BOOT_MODE BootMode;\r
   EFI_STATUS  Status;\r
   UINT32      FvbNumLba;\r
   EFI_BOOT_MODE BootMode;\r
+  UINTN       RuntimeMmioRegionSize;\r
 \r
   DEBUG((DEBUG_BLKIO,"NorFlashFvbInitialize\n"));\r
 \r
   Instance->Initialized = TRUE;\r
 \r
   DEBUG((DEBUG_BLKIO,"NorFlashFvbInitialize\n"));\r
 \r
   Instance->Initialized = TRUE;\r
+  mFlashNvStorageVariableBase = FixedPcdGet32 (PcdFlashNvStorageVariableBase);\r
 \r
   // Set the index of the first LBA for the FVB\r
   Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;\r
 \r
   // Set the index of the first LBA for the FVB\r
   Instance->StartLba = (PcdGet32 (PcdFlashNvStorageVariableBase) - Instance->RegionBaseAddress) / Instance->Media.BlockSize;\r
@@ -808,5 +747,41 @@ NorFlashFvbInitialize (
       return Status;\r
     }\r
   }\r
       return Status;\r
     }\r
   }\r
+\r
+  //\r
+  // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME\r
+  //\r
+\r
+  // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory;\r
+  //       even if we only use the small block region at the top of the NOR Flash.\r
+  //       The reason is when the NOR Flash memory is set into program mode, the command\r
+  //       is written as the base of the flash region (ie: Instance->DeviceBaseAddress)\r
+  RuntimeMmioRegionSize = (Instance->RegionBaseAddress - Instance->DeviceBaseAddress) + Instance->Size;\r
+\r
+  Status = gDS->AddMemorySpace (\r
+      EfiGcdMemoryTypeMemoryMappedIo,\r
+      Instance->DeviceBaseAddress, RuntimeMmioRegionSize,\r
+      EFI_MEMORY_UC | EFI_MEMORY_RUNTIME\r
+      );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gDS->SetMemorySpaceAttributes (\r
+      Instance->DeviceBaseAddress, RuntimeMmioRegionSize,\r
+      EFI_MEMORY_UC | EFI_MEMORY_RUNTIME);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register for the virtual address change event\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  FvbVirtualNotifyEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mFvbVirtualAddrChangeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r
   return Status;\r
 }\r