]> git.proxmox.com Git - mirror_edk2.git/blobdiff - IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c
Move BdsDxe and GenericBdsLib to IntelFrameworkModulePkg, these modules need dependen...
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / BdsDxe / Capsules.c
diff --git a/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c b/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c
new file mode 100644 (file)
index 0000000..904a775
--- /dev/null
@@ -0,0 +1,257 @@
+/** @file\r
+  BDS routines to handle capsules.\r
+\r
+Copyright (c) 2004 - 2008, Intel Corporation. <BR>\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
+**/\r
+#include "Bds.h"\r
+\r
+/**\r
+  This function locks the block \r
+\r
+  @param CpuIo           A instance of EFI_CPU_IO_PROTOCOL. \r
+  @param Base            The base address flash region to be locked.\r
+\r
+**/\r
+VOID\r
+BdsLockFv (\r
+  IN EFI_CPU_IO_PROTOCOL          *CpuIo,\r
+  IN EFI_PHYSICAL_ADDRESS         Base\r
+  )\r
+{\r
+  EFI_FV_BLOCK_MAP_ENTRY      *BlockMap;\r
+  EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;\r
+  EFI_PHYSICAL_ADDRESS        BaseAddress;\r
+  UINT8                       Data;\r
+  UINT32                      BlockLength;\r
+  UINTN                       Index;\r
+\r
+  BaseAddress = Base - 0x400000 + 2;\r
+  FvHeader    = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (Base));\r
+  BlockMap    = &(FvHeader->BlockMap[0]);\r
+\r
+  while ((BlockMap->NumBlocks != 0) && (BlockMap->Length != 0)) {\r
+    BlockLength = BlockMap->Length;\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
+/**\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
+  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 away 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
+  @param BootMode                 the current boot mode\r
+\r
+  @retval EFI_INVALID_PARAMETER   boot mode is not correct for an update\r
+  @retval EFI_SUCCESS             There is no error when processing capsule\r
+\r
+**/\r
+EFI_STATUS\r
+ProcessCapsules (\r
+  EFI_BOOT_MODE BootMode\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_PEI_HOB_POINTERS        HobPointer;\r
+  EFI_CAPSULE_HEADER          *CapsuleHeader;\r
+  UINT32                      Size;\r
+  UINT32                      CapsuleNumber;\r
+  UINT32                      CapsuleTotalNumber;\r
+  EFI_CAPSULE_TABLE           *CapsuleTable;\r
+  UINT32                      Index;\r
+  UINT32                      CacheIndex;\r
+  UINT32                      CacheNumber;\r
+  VOID                        **CapsulePtr;\r
+  VOID                        **CapsulePtrCache;\r
+  EFI_GUID                    *CapsuleGuidCache; \r
+  CAPSULE_HOB_INFO            *CapsuleHobInfo;\r
+\r
+  CapsuleNumber = 0;\r
+  CapsuleTotalNumber = 0;\r
+  CacheIndex   = 0;\r
+  CacheNumber  = 0;\r
+  CapsulePtr        = NULL;\r
+  CapsulePtrCache   = NULL;\r
+  CapsuleGuidCache  = NULL;\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
+  Status = EFI_SUCCESS;\r
+  //\r
+  // Find all capsule images from hob\r
+  //\r
+  HobPointer.Raw = GetHobList ();\r
+  while ((HobPointer.Raw = GetNextGuidHob (&gEfiCapsuleVendorGuid, HobPointer.Raw)) != NULL) {\r
+    CapsuleTotalNumber ++;\r
+\r
+    HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
+  }\r
+  \r
+  if (CapsuleTotalNumber == 0) {\r
+    //\r
+    // We didn't find a hob, so had no errors.\r
+    //\r
+    PlatformBdsLockNonUpdatableFlash ();\r
+    return EFI_SUCCESS;\r
+  }\r
+  \r
+  //\r
+  // Init temp Capsule Data table.\r
+  //\r
+  CapsulePtr       = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
+  ASSERT (CapsulePtr != NULL);\r
+  CapsulePtrCache  = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);\r
+  ASSERT (CapsulePtrCache != NULL);\r
+  CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);\r
+  ASSERT (CapsuleGuidCache != NULL);\r
+  \r
+  //\r
+  // Find all capsule images from hob\r
+  //\r
+  HobPointer.Raw = GetHobList ();\r
+  while ((HobPointer.Raw = GetNextGuidHob (&gEfiCapsuleVendorGuid, HobPointer.Raw)) != NULL) {\r
+    CapsuleHobInfo = GET_GUID_HOB_DATA (HobPointer.Guid);\r
+    CapsulePtr [CapsuleNumber++] = (VOID *)(UINTN)(CapsuleHobInfo->BaseAddress);\r
+\r
+    HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
+  }\r
+\r
+  //\r
+  //Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
+  //capsuleTable to configure table with EFI_CAPSULE_GUID\r
+  //\r
+\r
+  //\r
+  // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating\r
+  // System to have information persist across a system reset. EFI System Table must \r
+  // point to an array of capsules that contains the same CapsuleGuid value. And agents\r
+  // searching for this type capsule will look in EFI System Table and search for the \r
+  // capsule's Guid and associated pointer to retrieve the data. Two steps below describes\r
+  // how to sorting the capsules by the unique guid and install the array to EFI System Table. \r
+  // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an \r
+  // array for later sorting capsules by CapsuleGuid.\r
+  //\r
+  for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
+      //\r
+      // For each capsule, we compare it with known CapsuleGuid in the CacheArray.\r
+      // If already has the Guid, skip it. Whereas, record it in the CacheArray as \r
+      // an additional one.\r
+      //\r
+      CacheIndex = 0;\r
+      while (CacheIndex < CacheNumber) {\r
+        if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {\r
+          break;\r
+        }\r
+        CacheIndex++;\r
+      }\r
+      if (CacheIndex == CacheNumber) {\r
+        CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules\r
+  // whose guid is the same as it, and malloc memory for an array which preceding\r
+  // with UINT32. The array fills with entry point of capsules that have the same\r
+  // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install\r
+  // this array into EFI System Table, so that agents searching for this type capsule\r
+  // will look in EFI System Table and search for the capsule's Guid and associated\r
+  // pointer to retrieve the data.\r
+  //\r
+  CacheIndex = 0;\r
+  while (CacheIndex < CacheNumber) {\r
+    CapsuleNumber = 0;  \r
+    for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+      CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+      if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
+        if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
+          //\r
+          // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.\r
+          //\r
+          CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;\r
+        }\r
+      }\r
+    }\r
+    if (CapsuleNumber != 0) {\r
+      Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);  \r
+      CapsuleTable = AllocateRuntimePool (Size);\r
+      ASSERT (CapsuleTable != NULL);\r
+      CapsuleTable->CapsuleArrayNumber =  CapsuleNumber;\r
+      CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));\r
+      Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    CacheIndex++;\r
+  }\r
+\r
+  //\r
+  // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are\r
+  // recognized by platform with CapsuleGuid. For general platform driver, UpdateFlash \r
+  // type is commonly supported, so here only deal with encapsuled FVs capsule. Additional\r
+  // type capsule transaction could be extended. It depends on platform policy.\r
+  //\r
+  for (Index = 0; Index < CapsuleTotalNumber; Index++) {\r
+    CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];\r
+    if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {\r
+      //\r
+      // Call capsule library to process capsule image.\r
+      //\r
+      ProcessCapsuleImage (CapsuleHeader);\r
+    }\r
+  }\r
+\r
+  PlatformBdsLockNonUpdatableFlash ();\r
+  \r
+  //\r
+  // Free the allocated temp memory space.\r
+  //\r
+  FreePool (CapsuleGuidCache);\r
+  FreePool (CapsulePtrCache);\r
+  FreePool (CapsulePtr);\r
+\r
+  return Status;\r
+}\r