]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/Drivers/NorFlashDxe/NorFlashDxe.c
ArmPlatformPkg/NorFlashDxe: Fixed driver to support UEFI Runtime mode
[mirror_edk2.git] / ArmPlatformPkg / Drivers / NorFlashDxe / NorFlashDxe.c
index d1506c721725a982f5a47f278c0cda8f883c8028..a03bf5749e9fc56893525005684fc2cd75774ed4 100644 (file)
@@ -1,6 +1,6 @@
 /** @file  NorFlashDxe.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
 #include "NorFlashDxe.h"\r
 \r
+STATIC EFI_EVENT mNorFlashVirtualAddrChangeEvent;\r
 \r
 //\r
 // Global variable declarations\r
 //\r
 NOR_FLASH_INSTANCE **mNorFlashInstances;\r
+UINT32               mNorFlashDeviceCount;\r
 \r
 NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {\r
   NOR_FLASH_SIGNATURE, // Signature\r
@@ -72,7 +74,7 @@ NOR_FLASH_INSTANCE  mNorFlashInstanceTemplate = {
     FvbEraseBlocks, // EraseBlocks\r
     NULL, //ParentHandle\r
   }, //  FvbProtoccol;\r
-\r
+  NULL, // FvbBuffer\r
   {\r
     {\r
       {\r
@@ -109,7 +111,7 @@ NorFlashCreateInstance (
 \r
   ASSERT(NorFlashInstance != NULL);\r
 \r
-  Instance = AllocateCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);\r
+  Instance = AllocateRuntimeCopyPool (sizeof(NOR_FLASH_INSTANCE),&mNorFlashInstanceTemplate);\r
   if (Instance == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
@@ -123,11 +125,15 @@ NorFlashCreateInstance (
   Instance->Media.BlockSize = BlockSize;\r
   Instance->Media.LastBlock = (NorFlashSize / BlockSize)-1;\r
 \r
-  CopyGuid (&Instance->DevicePath.Vendor.Guid,NorFlashGuid);\r
+  CopyGuid (&Instance->DevicePath.Vendor.Guid, NorFlashGuid);\r
 \r
   if (SupportFvb) {\r
     Instance->SupportFvb = TRUE;\r
     Instance->Initialize = NorFlashFvbInitialize;\r
+    Instance->FvbBuffer = AllocateRuntimePool (BlockSize);;\r
+    if (Instance->FvbBuffer == NULL) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
 \r
     Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &Instance->Handle,\r
@@ -137,7 +143,7 @@ NorFlashCreateInstance (
                   NULL\r
                   );\r
     if (EFI_ERROR(Status)) {\r
-      FreePool(Instance);\r
+      FreePool (Instance);\r
       return Status;\r
     }\r
   } else {\r
@@ -150,7 +156,7 @@ NorFlashCreateInstance (
                     NULL\r
                     );\r
     if (EFI_ERROR(Status)) {\r
-      FreePool(Instance);\r
+      FreePool (Instance);\r
       return Status;\r
     }\r
   }\r
@@ -340,8 +346,14 @@ NorFlashUnlockAndEraseSingleBlock (
   UINTN           Index;\r
   EFI_TPL         OriginalTPL;\r
 \r
-  // Raise TPL to TPL_HIGH to stop anyone from interrupting us.\r
-  OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  if (!EfiAtRuntime ()) {\r
+    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.\r
+    OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  } else {\r
+    // This initialization is only to prevent the compiler to complain about the\r
+    // use of uninitialized variables\r
+    OriginalTPL = TPL_HIGH_LEVEL;\r
+  }\r
 \r
   Index = 0;\r
   // The block erase might fail a first time (SW bug ?). Retry it ...\r
@@ -358,8 +370,10 @@ NorFlashUnlockAndEraseSingleBlock (
     DEBUG((EFI_D_ERROR,"EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index));\r
   }\r
 \r
-  // Interruptions can resume.\r
-  gBS->RestoreTPL (OriginalTPL);\r
+  if (!EfiAtRuntime ()) {\r
+    // Interruptions can resume.\r
+    gBS->RestoreTPL (OriginalTPL);\r
+  }\r
 \r
   return Status;\r
 }\r
@@ -581,8 +595,14 @@ NorFlashWriteSingleBlock (
   // Start writing from the first address at the start of the block\r
   WordAddress = BlockAddress;\r
 \r
-  // Raise TPL to TPL_HIGH to stop anyone from interrupting us.\r
-  OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  if (!EfiAtRuntime ()) {\r
+    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.\r
+    OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+  } else {\r
+    // This initialization is only to prevent the compiler to complain about the\r
+    // use of uninitialized variables\r
+    OriginalTPL = TPL_HIGH_LEVEL;\r
+  }\r
 \r
   Status = NorFlashUnlockAndEraseSingleBlock (Instance, BlockAddress);\r
   if (EFI_ERROR(Status)) {\r
@@ -596,7 +616,7 @@ NorFlashWriteSingleBlock (
   if ((WordAddress & BOUNDARY_OF_32_WORDS) == 0x00) {\r
 \r
     // First, break the entire block into buffer-sized chunks.\r
-    BuffersInBlock = (UINTN)BlockSizeInWords / P30_MAX_BUFFER_SIZE_IN_BYTES;\r
+    BuffersInBlock = (UINTN)(BlockSizeInWords * 4) / P30_MAX_BUFFER_SIZE_IN_BYTES;\r
 \r
     // Then feed each buffer chunk to the NOR Flash\r
     for(BufferIndex=0;\r
@@ -632,8 +652,10 @@ NorFlashWriteSingleBlock (
   }\r
 \r
 EXIT:\r
-  // Interruptions can resume.\r
-  gBS->RestoreTPL (OriginalTPL);\r
+  if (!EfiAtRuntime ()) {\r
+    // Interruptions can resume.\r
+    gBS->RestoreTPL (OriginalTPL);\r
+  }\r
 \r
   if (EFI_ERROR(Status)) {\r
     DEBUG((EFI_D_ERROR, "NOR FLASH Programming [WriteSingleBlock] failed at address 0x%08x. Exit Status = \"%r\".\n", WordAddress, Status));\r
@@ -721,19 +743,20 @@ NorFlashReadBlocks (
   UINT32              NumBlocks;\r
   UINTN               StartAddress;\r
 \r
+  DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%xB BlockSize=0x%xB LastBlock=%ld, Lba=%ld.\n",\r
+      BufferSizeInBytes, Instance->Media.BlockSize, Instance->Media.LastBlock, Lba));\r
+\r
   // The buffer must be valid\r
   if (Buffer == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  // We must have some bytes to read\r
-  DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BufferSize=0x%x bytes.\n", BufferSizeInBytes));\r
-  if(BufferSizeInBytes == 0) {\r
-    return EFI_BAD_BUFFER_SIZE;\r
+  // Return if we have not any byte to read \r
+  if (BufferSizeInBytes == 0) {\r
+    return EFI_SUCCESS;\r
   }\r
 \r
   // The size of the buffer must be a multiple of the block size\r
-  DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: BlockSize=0x%x bytes.\n", Instance->Media.BlockSize));\r
   if ((BufferSizeInBytes % Instance->Media.BlockSize) != 0) {\r
     return EFI_BAD_BUFFER_SIZE;\r
   }\r
@@ -741,8 +764,6 @@ NorFlashReadBlocks (
   // All blocks must be within the device\r
   NumBlocks = ((UINT32)BufferSizeInBytes) / Instance->Media.BlockSize ;\r
 \r
-  DEBUG((DEBUG_BLKIO, "NorFlashReadBlocks: NumBlocks=%d, LastBlock=%ld, Lba=%ld\n", NumBlocks, Instance->Media.LastBlock, Lba));\r
-\r
   if ((Lba + NumBlocks) > (Instance->Media.LastBlock + 1)) {\r
     DEBUG((EFI_D_ERROR, "NorFlashReadBlocks: ERROR - Read will exceed last block\n"));\r
     return EFI_INVALID_PARAMETER;\r
@@ -773,6 +794,50 @@ NorFlashReset (
   return EFI_SUCCESS;\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
+NorFlashVirtualNotifyEvent (\r
+  IN EFI_EVENT        Event,\r
+  IN VOID             *Context\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->DeviceBaseAddress);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->RegionBaseAddress);\r
+\r
+    // Convert BlockIo protocol\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.FlushBlocks);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.ReadBlocks);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.Reset);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->BlockIoProtocol.WriteBlocks);\r
+\r
+    // Convert Fvb\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.EraseBlocks);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetAttributes);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetBlockSize);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.GetPhysicalAddress);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Read);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.SetAttributes);\r
+    EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbProtocol.Write);\r
+\r
+    if (mNorFlashInstances[Index]->FvbBuffer != NULL) {\r
+      EfiConvertPointer (0x0, (VOID**)&mNorFlashInstances[Index]->FvbBuffer);\r
+    }\r
+  }\r
+\r
+  return;\r
+}\r
+\r
 EFI_STATUS\r
 EFIAPI\r
 NorFlashInitialise (\r
@@ -783,7 +848,6 @@ NorFlashInitialise (
   EFI_STATUS              Status;\r
   UINT32                  Index;\r
   NOR_FLASH_DESCRIPTION*  NorFlashDevices;\r
-  UINT32                  NorFlashDeviceCount;\r
   BOOLEAN                 ContainVariableStorage;\r
 \r
   Status = NorFlashPlatformInitialization ();\r
@@ -792,15 +856,15 @@ NorFlashInitialise (
     return Status;\r
   }\r
 \r
-  Status = NorFlashPlatformGetDevices (&NorFlashDevices,&NorFlashDeviceCount);\r
+  Status = NorFlashPlatformGetDevices (&NorFlashDevices, &mNorFlashDeviceCount);\r
   if (EFI_ERROR(Status)) {\r
     DEBUG((EFI_D_ERROR,"NorFlashInitialise: Fail to get Nor Flash devices\n"));\r
     return Status;\r
   }\r
 \r
-  mNorFlashInstances = AllocatePool (sizeof(NOR_FLASH_INSTANCE*) * NorFlashDeviceCount);\r
+  mNorFlashInstances = AllocateRuntimePool (sizeof(NOR_FLASH_INSTANCE*) * mNorFlashDeviceCount);\r
 \r
-  for (Index = 0; Index < NorFlashDeviceCount; Index++) {\r
+  for (Index = 0; Index < mNorFlashDeviceCount; Index++) {\r
     // Check if this NOR Flash device contain the variable storage region\r
     ContainVariableStorage =\r
         (NorFlashDevices[Index].RegionBaseAddress <= PcdGet32 (PcdFlashNvStorageVariableBase)) &&\r
@@ -821,5 +885,18 @@ NorFlashInitialise (
     }\r
   }\r
 \r
+  //\r
+  // Register for the virtual address change event\r
+  //\r
+  Status = gBS->CreateEventEx (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_NOTIFY,\r
+                  NorFlashVirtualNotifyEvent,\r
+                  NULL,\r
+                  &gEfiEventVirtualAddressChangeGuid,\r
+                  &mNorFlashVirtualAddrChangeEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
   return Status;\r
 }\r