--- /dev/null
+/*++\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