/** This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber. **/ VOID InitCapsulePtr ( VOID ) { EFI_PEI_HOB_POINTERS HobPointer; UINTN Index; // // Find all capsule images from hob // HobPointer.Raw = GetHobList (); while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) { HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid } else { mCapsuleTotalNumber++; } HobPointer.Raw = GET_NEXT_HOB (HobPointer); } DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber)); if (mCapsuleTotalNumber == 0) { return ; } // // Init temp Capsule Data table. // mCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber); if (mCapsulePtr == NULL) { DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n")); mCapsuleTotalNumber = 0; return ; } mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber); if (mCapsuleStatusArray == NULL) { DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n")); FreePool (mCapsulePtr); mCapsulePtr = NULL; mCapsuleTotalNumber = 0; return ; } SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY); // // Find all capsule images from hob // HobPointer.Raw = GetHobList (); Index = 0; while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) { mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress; HobPointer.Raw = GET_NEXT_HOB (HobPointer); } }
/** Dump capsule information @param[in] CapsuleName The name of the capsule image. @retval EFI_SUCCESS The capsule information is dumped. @retval EFI_UNSUPPORTED Input parameter is not valid. **/ EFI_STATUS DumpCapsule ( IN CHAR16 *CapsuleName ) { VOID *Buffer; UINTN FileSize; EFI_CAPSULE_HEADER *CapsuleHeader; EFI_STATUS Status; Buffer = NULL; Status = ReadFileToBuffer(CapsuleName, &FileSize, &Buffer); if (EFI_ERROR(Status)) { Print(L"CapsuleApp: Capsule (%s) is not found.\n", CapsuleName); goto Done; } if (!IsValidCapsuleHeader (Buffer, FileSize)) { Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); Status = EFI_INVALID_PARAMETER; goto Done; } CapsuleHeader = Buffer; if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) { DumpUxCapsule(CapsuleHeader); Status = EFI_SUCCESS; goto Done; } if (CompareGuid(&CapsuleHeader->CapsuleGuid, &gEfiFmpCapsuleGuid)) { DumpFmpCapsule(CapsuleHeader); } if (IsNestedFmpCapsule(CapsuleHeader)) { Print(L"[NestedCapusule]\n"); Print(L"CapsuleHeader:\n"); Print(L" CapsuleGuid - %g\n", &CapsuleHeader->CapsuleGuid); Print(L" HeaderSize - 0x%x\n", CapsuleHeader->HeaderSize); Print(L" Flags - 0x%x\n", CapsuleHeader->Flags); Print(L" CapsuleImageSize - 0x%x\n", CapsuleHeader->CapsuleImageSize); DumpFmpCapsule((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize)); } Done: if (Buffer != NULL) { FreePool(Buffer); } return Status; }
/** Update Capsule image. @param[in] ImageHandle The image handle. @param[in] SystemTable The system table. @retval EFI_SUCCESS Command completed successfully. @retval EFI_UNSUPPORTED Command usage unsupported. @retval EFI_INVALID_PARAMETER Command usage invalid. @retval EFI_NOT_FOUND The input file can't be found. **/ EFI_STATUS EFIAPI UefiMain ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; RETURN_STATUS RStatus; UINTN FileSize[MAX_CAPSULE_NUM]; VOID *CapsuleBuffer[MAX_CAPSULE_NUM]; EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors; EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1]; UINT64 MaxCapsuleSize; EFI_RESET_TYPE ResetType; BOOLEAN NeedReset; BOOLEAN NoReset; CHAR16 *CapsuleName; UINTN CapsuleNum; UINTN Index; Status = GetArg(); if (EFI_ERROR(Status)) { Print(L"Please use UEFI SHELL to run this application!\n", Status); return Status; } if (Argc < 2) { PrintUsage(); return EFI_UNSUPPORTED; } if (StrCmp(Argv[1], L"-D") == 0) { if (Argc != 3) { Print(L"CapsuleApp: Incorrect parameter count.\n"); return EFI_UNSUPPORTED; } Status = DumpCapsule(Argv[2]); return Status; } if (StrCmp(Argv[1], L"-G") == 0) { Status = CreateBmpFmp(); return Status; } if (StrCmp(Argv[1], L"-N") == 0) { Status = CreateNestedFmp(); return Status; } if (StrCmp(Argv[1], L"-S") == 0) { Status = DmpCapsuleStatusVariable(); return EFI_SUCCESS; } if (StrCmp(Argv[1], L"-C") == 0) { Status = ClearCapsuleStatusVariable(); return Status; } if (StrCmp(Argv[1], L"-P") == 0) { if (Argc == 2) { DumpFmpData(); } if (Argc >= 3) { if (StrCmp(Argv[2], L"GET") != 0) { Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]); return EFI_UNSUPPORTED; } else { if (Argc != 7) { Print(L"CapsuleApp: Incorrect parameter count.\n"); return EFI_UNSUPPORTED; } EFI_GUID ImageTypeId; UINTN ImageIndex; // // FMP->GetImage() // RStatus = StrToGuid (Argv[3], &ImageTypeId); if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) { Print (L"Invalid ImageTypeId - %s\n", Argv[3]); return EFI_INVALID_PARAMETER; } ImageIndex = StrDecimalToUintn(Argv[4]); if (StrCmp(Argv[5], L"-O") != 0) { Print(L"CapsuleApp: NO output file name.\n"); return EFI_UNSUPPORTED; } DumpFmpImage(&ImageTypeId, ImageIndex, Argv[6]); } } return EFI_SUCCESS; } if (StrCmp(Argv[1], L"-E") == 0) { DumpEsrtData(); return EFI_SUCCESS; } if (Argv[1][0] == L'-') { Print(L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]); return EFI_UNSUPPORTED; } CapsuleFirstIndex = 1; NoReset = FALSE; if ((Argc > 1) && (StrCmp(Argv[Argc - 1], L"-NR") == 0)) { NoReset = TRUE; CapsuleLastIndex = Argc - 2; } else { CapsuleLastIndex = Argc - 1; } CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1; if (CapsuleFirstIndex > CapsuleLastIndex) { Print(L"CapsuleApp: NO capsule image.\n"); return EFI_UNSUPPORTED; } if (CapsuleNum > MAX_CAPSULE_NUM) { Print(L"CapsuleApp: Too many capsule images.\n"); return EFI_UNSUPPORTED; } ZeroMem(&CapsuleBuffer, sizeof(CapsuleBuffer)); ZeroMem(&FileSize, sizeof(FileSize)); BlockDescriptors = NULL; for (Index = 0; Index < CapsuleNum; Index++) { CapsuleName = Argv[CapsuleFirstIndex + Index]; Status = ReadFileToBuffer(CapsuleName, &FileSize[Index], &CapsuleBuffer[Index]); if (EFI_ERROR(Status)) { Print(L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName); goto Done; } if (!IsValidCapsuleHeader (CapsuleBuffer[Index], FileSize[Index])) { Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); return EFI_INVALID_PARAMETER; } } // // Every capsule use 2 descriptor 1 for data 1 for end // Status = BuildGatherList(CapsuleBuffer, FileSize, CapsuleNum, &BlockDescriptors); if (EFI_ERROR(Status)) { goto Done; } // // Call the runtime service capsule. // NeedReset = FALSE; for (Index = 0; Index < CapsuleNum; Index++) { CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *) CapsuleBuffer[Index]; if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { NeedReset = TRUE; } } CapsuleHeaderArray[CapsuleNum] = NULL; // // Inquire platform capability of UpdateCapsule. // Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType); if (EFI_ERROR(Status)) { Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status); goto Done; } for (Index = 0; Index < CapsuleNum; Index++) { if (FileSize[Index] > MaxCapsuleSize) { Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize); Status = EFI_UNSUPPORTED; goto Done; } } // // Check whether the input capsule image has the flag of persist across system reset. // if (NeedReset) { Status = gRT->UpdateCapsule(CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors); if (Status != EFI_SUCCESS) { Print (L"CapsuleApp: failed to update capsule - %r\n", Status); goto Done; } // // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET, // a system reset should have been triggered by gRT->UpdateCapsule() calling above. // // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET, // check if -NR (no-reset) has been specified or not. // if (!NoReset) { // // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service, // trigger a system reset to process capsule persist across a system reset. // gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL); } } else { // // For capsule who has no reset flag, only call UpdateCapsule Service without a // system reset. The service will process the capsule immediately. // Status = gRT->UpdateCapsule (CapsuleHeaderArray,CapsuleNum,(UINTN) BlockDescriptors); if (Status != EFI_SUCCESS) { Print (L"CapsuleApp: failed to update capsule - %r\n", Status); } } Status = EFI_SUCCESS; Done: for (Index = 0; Index < CapsuleNum; Index++) { if (CapsuleBuffer[Index] != NULL) { FreePool (CapsuleBuffer[Index]); } } CleanGatherList(BlockDescriptors, CapsuleNum); return Status; }
/** Append a capsule header on top of current image. This function follows Windows UEFI Firmware Update Platform document. @retval EFI_SUCCESS The capsule header is appended. @retval EFI_UNSUPPORTED Input parameter is not valid. @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header. **/ EFI_STATUS CreateNestedFmp ( VOID ) { CHAR16 *OutputCapsuleName; VOID *CapsuleBuffer; UINTN FileSize; CHAR16 *CapsuleName; UINT8 *FullCapsuleBuffer; UINTN FullCapsuleBufferSize; EFI_CAPSULE_HEADER *NestedCapsuleHeader; EFI_GUID *ImageTypeId; UINT32 FwType; EFI_STATUS Status; if (Argc != 5) { Print(L"CapsuleApp: Incorrect parameter count.\n"); return EFI_UNSUPPORTED; } if (StrCmp(Argv[3], L"-O") != 0) { Print(L"CapsuleApp: NO output capsule name.\n"); return EFI_UNSUPPORTED; } OutputCapsuleName = Argv[4]; CapsuleBuffer = NULL; FileSize = 0; FullCapsuleBuffer = NULL; CapsuleName = Argv[2]; Status = ReadFileToBuffer(CapsuleName, &FileSize, &CapsuleBuffer); if (EFI_ERROR(Status)) { Print(L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName); goto Done; } if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) { Print(L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName); Status = EFI_INVALID_PARAMETER; goto Done; } if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *) CapsuleBuffer)->CapsuleGuid)) { Print(L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName); Status = EFI_INVALID_PARAMETER; goto Done; } ImageTypeId = GetCapsuleImageTypeId(CapsuleBuffer); if (ImageTypeId == NULL) { Print(L"CapsuleApp: Capsule ImageTypeId is not found.\n"); Status = EFI_INVALID_PARAMETER; goto Done; } FwType = GetEsrtFwType(ImageTypeId); if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) { Print(L"CapsuleApp: Capsule FwType is invalid.\n"); Status = EFI_INVALID_PARAMETER; goto Done; } FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize; FullCapsuleBuffer = AllocatePool(FullCapsuleBufferSize); if (FullCapsuleBuffer == NULL) { Print(L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize); Status = EFI_OUT_OF_RESOURCES; goto Done; } NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer; ZeroMem(NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE); CopyGuid(&NestedCapsuleHeader->CapsuleGuid, ImageTypeId); NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE; NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG; NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize; CopyMem((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize); Status = WriteFileFromBuffer(OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer); Print(L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status); Done: if (CapsuleBuffer != NULL) { FreePool(CapsuleBuffer); } if (FullCapsuleBuffer != NULL) { FreePool(FullCapsuleBuffer); } return Status; }