]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkUnixPkg/Dxe/PlatformBds/Generic/Capsules.c
Unix version of EFI emulator
[mirror_edk2.git] / EdkUnixPkg / Dxe / PlatformBds / Generic / Capsules.c
diff --git a/EdkUnixPkg/Dxe/PlatformBds/Generic/Capsules.c b/EdkUnixPkg/Dxe/PlatformBds/Generic/Capsules.c
new file mode 100644 (file)
index 0000000..b253166
--- /dev/null
@@ -0,0 +1,213 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  Capsules.c\r
+\r
+Abstract:\r
+\r
+  BDS routines to handle capsules.\r
+\r
+--*/\r
+\r
+\r
+#include <Common/FlashMap.h>\r
+\r
+VOID\r
+BdsLockFv (\r
+  IN EFI_CPU_IO_PROTOCOL          *CpuIo,\r
+  IN EFI_FLASH_SUBAREA_ENTRY      *FlashEntry\r
+  );\r
+\r
+VOID\r
+BdsLockFv (\r
+  IN EFI_CPU_IO_PROTOCOL          *CpuIo,\r
+  IN EFI_FLASH_SUBAREA_ENTRY      *FlashEntry\r
+  )\r
+{\r
+  EFI_FV_BLOCK_MAP_ENTRY      *BlockMap;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
+  UINT64                      BaseAddress;\r
+  UINT8                       Data;\r
+  UINT32                      BlockLength;\r
+  UINTN                       Index;\r
+\r
+  BaseAddress = FlashEntry->Base - 0x400000 + 2;\r
+  FvHeader    = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (FlashEntry->Base));\r
+  BlockMap    = &(FvHeader->FvBlockMap[0]);\r
+\r
+  while ((BlockMap->NumBlocks != 0) && (BlockMap->BlockLength != 0)) {\r
+    BlockLength = BlockMap->BlockLength;\r
+    for (Index = 0; Index < BlockMap->NumBlocks; Index++) {\r
+      CpuIo->Mem.Read (\r
+                  CpuIo,\r
+                  EfiCpuIoWidthUint8,\r
+                  BaseAddress,\r
+                  1,\r
+                  &Data\r
+                  );\r
+      Data = (UINT8) (Data | 0x3);\r
+      CpuIo->Mem.Write (\r
+                  CpuIo,\r
+                  EfiCpuIoWidthUint8,\r
+                  BaseAddress,\r
+                  1,\r
+                  &Data\r
+                  );\r
+      BaseAddress += BlockLength;\r
+    }\r
+\r
+    BlockMap++;\r
+  }\r
+}\r
+\r
+VOID\r
+BdsLockNonUpdatableFlash (\r
+  VOID\r
+  )\r
+{\r
+  EFI_FLASH_MAP_ENTRY_DATA  *FlashMapEntryData;\r
+  EFI_PEI_HOB_POINTERS      GuidHob;\r
+  EFI_STATUS                Status;\r
+  EFI_CPU_IO_PROTOCOL       *CpuIo;\r
+\r
+  Status = gBS->LocateProtocol (&gEfiCpuIoProtocolGuid, NULL, &CpuIo);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
+  GuidHob.Raw = GetHobList ();\r
+  while ((GuidHob.Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, GuidHob.Raw)) != NULL) {\r
+    FlashMapEntryData = (EFI_FLASH_MAP_ENTRY_DATA *) GET_GUID_HOB_DATA (GuidHob.Guid);\r
+\r
+    //\r
+    // Get the variable store area\r
+    //\r
+    if ((FlashMapEntryData->AreaType == EFI_FLASH_AREA_RECOVERY_BIOS) ||\r
+        (FlashMapEntryData->AreaType == EFI_FLASH_AREA_MAIN_BIOS)\r
+        ) {\r
+      BdsLockFv (CpuIo, &(FlashMapEntryData->Entries[0]));\r
+    }\r
+    GuidHob.Raw = GET_NEXT_HOB (GuidHob);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+EFI_STATUS\r
+ProcessCapsules (\r
+  EFI_BOOT_MODE BootMode\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  This routine is called to see if there are any capsules we need to process.\r
+  If the boot mode is not UPDATE, then we do nothing. Otherwise find the\r
+  capsule HOBS and produce firmware volumes for them via the DXE service.\r
+  Then call the dispatcher to dispatch drivers from them. Finally, check\r
+  the status of the updates.\r
+\r
+Arguments:\r
+\r
+  BootMode - the current boot mode\r
+\r
+Returns:\r
+  \r
+  EFI_INVALID_PARAMETER - boot mode is not correct for an update\r
+\r
+Note:\r
\r
+ This function should be called by BDS in case we need to do some\r
+ sort of processing even if there is no capsule to process. We\r
+ need to do this if an earlier update went awry and we need to\r
+ clear the capsule variable so on the next reset PEI does not see it and \r
+ think there is a capsule available.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_HOB_CAPSULE_VOLUME      *CvHob;\r
+  EFI_PHYSICAL_ADDRESS        BaseAddress;\r
+  UINT64                      Length;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;\r
+  EFI_HANDLE                  FvProtocolHandle;\r
+\r
+  //\r
+  // We don't do anything else if the boot mode is not flash-update\r
+  //\r
+  if (BootMode != BOOT_ON_FLASH_UPDATE) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  //\r
+  // Only one capsule HOB allowed.\r
+  //\r
+  CvHob = GetFirstHob (EFI_HOB_TYPE_CV);\r
+  if (CvHob == NULL) {\r
+    //\r
+    // We didn't find a hob, so had no errors.\r
+    //\r
+    BdsLockNonUpdatableFlash ();\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  BaseAddress = CvHob->BaseAddress;\r
+  Length      = CvHob->Length;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  //\r
+  // Now walk the capsule and call the core to process each\r
+  // firmware volume in it.\r
+  //\r
+  while (Length != 0) {\r
+    //\r
+    // Point to the next firmware volume header, and then\r
+    // call the DXE service to process it.\r
+    //\r
+    FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
+    if (FwVolHeader->FvLength > Length) {\r
+      //\r
+      // Notes: need to stuff this status somewhere so that the\r
+      // error can be detected at OS runtime\r
+      //\r
+      Status = EFI_VOLUME_CORRUPTED;\r
+      break;\r
+    }\r
+\r
+    Status = gDS->ProcessFirmwareVolume (\r
+                    (VOID *) (UINTN) BaseAddress,\r
+                    (UINTN) FwVolHeader->FvLength,\r
+                    &FvProtocolHandle\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Call the dispatcher to dispatch any drivers from the produced firmware volume\r
+    //\r
+    gDS->Dispatch ();\r
+    //\r
+    // On to the next FV in the capsule\r
+    //\r
+    Length -= FwVolHeader->FvLength;\r
+    BaseAddress = (EFI_PHYSICAL_ADDRESS) ((UINTN) BaseAddress + FwVolHeader->FvLength);\r
+    //\r
+    // Notes: when capsule spec is finalized, if the requirement is made to\r
+    // have each FV in a capsule aligned, then we will need to align the\r
+    // BaseAddress and Length here.\r
+    //\r
+  }\r
+   \r
+\r
+  BdsLockNonUpdatableFlash ();\r
+\r
+  return Status;\r
+}\r
+\r