| /** @file | |
| Generic Capsule services | |
| Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #include <Common/CapsuleName.h> | |
| // | |
| //Max size capsule services support are platform policy,to populate capsules we just need | |
| //memory to maintain them across reset,it is not a problem. And to special capsules ,for | |
| //example,update flash,it is mostly decided by the platform. Here is a sample size for | |
| //different type capsules. | |
| // | |
| #define MAX_SIZE_POPULATE (0) | |
| #define MAX_SIZE_NON_POPULATE (0) | |
| #define MAX_SUPPORT_CAPSULE_NUM 0x10 | |
| BOOLEAN | |
| EFIAPI | |
| SupportUpdateCapsuleRest ( | |
| VOID | |
| ) | |
| { | |
| // | |
| //If the platform has a way to guarantee the memory integrity across a system reset, return | |
| //TRUE, else FALSE. | |
| // | |
| return FALSE; | |
| } | |
| VOID | |
| EFIAPI | |
| SupportCapsuleSize ( | |
| IN OUT UINT32 *MaxSizePopulate, | |
| IN OUT UINT32 *MaxSizeNonPopulate | |
| ) | |
| { | |
| // | |
| //Here is a sample size, different platforms have different sizes. | |
| // | |
| *MaxSizePopulate = MAX_SIZE_POPULATE; | |
| *MaxSizeNonPopulate = MAX_SIZE_NON_POPULATE; | |
| return; | |
| } | |
| EFI_STATUS | |
| LibUpdateCapsule ( | |
| IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, | |
| IN UINTN CapsuleCount, | |
| IN EFI_PHYSICAL_ADDRESS ScatterGatherList OPTIONAL | |
| ) | |
| /*++ | |
| Routine Description: | |
| This code finds if the capsule needs reset to update, if no, update immediately. | |
| Arguments: | |
| CapsuleHeaderArray A array of pointers to capsule headers passed in | |
| CapsuleCount The number of capsule | |
| ScatterGatherList Physical address of datablock list points to capsule | |
| Returns: | |
| EFI STATUS | |
| EFI_SUCCESS Valid capsule was passed.If CAPSULE_FLAG_PERSIT_ACROSS_RESET is | |
| not set, the capsule has been successfully processed by the firmware. | |
| If it set, the ScattlerGatherList is successfully to be set. | |
| EFI_INVALID_PARAMETER CapsuleCount is less than 1,CapsuleGuid is not supported. | |
| EFI_DEVICE_ERROR Failed to SetVariable or AllocatePool or ProcessFirmwareVolume. | |
| --*/ | |
| { | |
| UINTN CapsuleSize; | |
| UINTN ArrayNumber; | |
| VOID *BufferPtr; | |
| EFI_STATUS Status; | |
| EFI_HANDLE FvHandle; | |
| UEFI_CAPSULE_HEADER *CapsuleHeader; | |
| if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){ | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| BufferPtr = NULL; | |
| CapsuleHeader = NULL; | |
| // | |
| //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET | |
| //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports. | |
| // | |
| for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { | |
| CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; | |
| if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) { | |
| if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } | |
| } | |
| // | |
| //Assume that capsules have the same flags on resetting or not. | |
| // | |
| CapsuleHeader = CapsuleHeaderArray[0]; | |
| if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { | |
| // | |
| //Check if the platform supports update capsule across a system reset | |
| // | |
| if (!SupportUpdateCapsuleRest()) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| if (ScatterGatherList == 0) { | |
| return EFI_INVALID_PARAMETER; | |
| } else { | |
| Status = EfiSetVariable ( | |
| EFI_CAPSULE_VARIABLE_NAME, | |
| &gEfiCapsuleVendorGuid, | |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
| sizeof (UINTN), | |
| (VOID *) &ScatterGatherList | |
| ); | |
| if (Status != EFI_SUCCESS) { | |
| return EFI_DEVICE_ERROR; | |
| } | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| // | |
| //The rest occurs in the condition of non-reset mode | |
| // | |
| if (EfiAtRuntime ()) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| //Here should be in the boot-time | |
| // | |
| for (ArrayNumber = 0; ArrayNumber < CapsuleCount ; ArrayNumber++) { | |
| CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; | |
| CapsuleSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize; | |
| Status = gBS->AllocatePool (EfiBootServicesData, CapsuleSize, &BufferPtr); | |
| if (Status != EFI_SUCCESS) { | |
| goto Done; | |
| } | |
| gBS->CopyMem (BufferPtr, (UINT8*)CapsuleHeader+ CapsuleHeader->HeaderSize, CapsuleSize); | |
| // | |
| //Call DXE service ProcessFirmwareVolume to process immediatelly | |
| // | |
| Status = gDS->ProcessFirmwareVolume (BufferPtr, CapsuleSize, &FvHandle); | |
| if (Status != EFI_SUCCESS) { | |
| gBS->FreePool (BufferPtr); | |
| return EFI_DEVICE_ERROR; | |
| } | |
| gDS->Dispatch (); | |
| gBS->FreePool (BufferPtr); | |
| } | |
| return EFI_SUCCESS; | |
| Done: | |
| if (BufferPtr != NULL) { | |
| gBS->FreePool (BufferPtr); | |
| } | |
| return EFI_DEVICE_ERROR; | |
| } | |
| EFI_STATUS | |
| QueryCapsuleCapabilities ( | |
| IN UEFI_CAPSULE_HEADER **CapsuleHeaderArray, | |
| IN UINTN CapsuleCount, | |
| OUT UINT64 *MaxiumCapsuleSize, | |
| OUT EFI_RESET_TYPE *ResetType | |
| ) | |
| /*++ | |
| Routine Description: | |
| This code is query about capsule capability. | |
| Arguments: | |
| CapsuleHeaderArray A array of pointers to capsule headers passed in | |
| CapsuleCount The number of capsule | |
| MaxiumCapsuleSize Max capsule size is supported | |
| ResetType Reset type the capsule indicates, if reset is not needed,return EfiResetCold. | |
| If reset is needed, return EfiResetWarm. | |
| Returns: | |
| EFI STATUS | |
| EFI_SUCCESS Valid answer returned | |
| EFI_INVALID_PARAMETER MaxiumCapsuleSize is NULL,ResetType is NULL.CapsuleCount is less than 1,CapsuleGuid is not supported. | |
| EFI_UNSUPPORTED The capsule type is not supported. | |
| --*/ | |
| { | |
| UINTN ArrayNumber; | |
| UEFI_CAPSULE_HEADER *CapsuleHeader; | |
| UINT32 MaxSizePopulate; | |
| UINT32 MaxSizeNonPopulate; | |
| if ((CapsuleCount < 1) || (CapsuleCount > MAX_SUPPORT_CAPSULE_NUM)){ | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((MaxiumCapsuleSize == NULL) ||(ResetType == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| CapsuleHeader = NULL; | |
| // | |
| //Compare GUIDs with EFI_CAPSULE_GUID, if capsule header contains CAPSULE_FLAGS_PERSIST_ACROSS_RESET | |
| //and CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flags,whatever the GUID is ,the service supports. | |
| // | |
| for (ArrayNumber = 0; ArrayNumber < CapsuleCount; ArrayNumber++) { | |
| CapsuleHeader = CapsuleHeaderArray[ArrayNumber]; | |
| if ((CapsuleHeader->Flags & (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)) == CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gEfiCapsuleGuid)) { | |
| if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| } | |
| } | |
| SupportCapsuleSize(&MaxSizePopulate,&MaxSizeNonPopulate); | |
| // | |
| //Assume that capsules have the same flags on resetting or not. | |
| // | |
| CapsuleHeader = CapsuleHeaderArray[0]; | |
| if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) { | |
| // | |
| //Check if the platform supports update capsule across a system reset | |
| // | |
| if (!SupportUpdateCapsuleRest()) { | |
| return EFI_UNSUPPORTED; | |
| } | |
| *ResetType = EfiResetWarm; | |
| *MaxiumCapsuleSize = MaxSizePopulate; | |
| } else { | |
| *ResetType = EfiResetCold; | |
| *MaxiumCapsuleSize = MaxSizeNonPopulate; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| VOID | |
| LibCapsuleVirtualAddressChangeEvent ( | |
| VOID | |
| ) | |
| { | |
| } | |
| VOID | |
| LibCapsuleInitialize ( | |
| VOID | |
| ) | |
| { | |
| } |