/** @file Copyright (c) 2024, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - Platform Security Firmware Update for the A-profile Specification 1.0 (https://developer.arm.com/documentation/den0118/latest) @par Glossary: - FW - Firmware - FWU - Firmware Update - PSA - Platform Security update for the A-profile specification - FMP - Firmware Management Protocol Device. **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "PsaFwuLib.h" STATIC UINT16 mUpdateAgentId; STATIC VOID *mPsaFwuBuffer = NULL; STATIC UINTN mPsaFwuMaxBufferSize; /** * Convert MmCommunication related addresses on VirtualAddress Change Event. * * @param [in] Event Registered VirtualAddress Change Event. * @param [in] Context Additional Data. * */ VOID EFIAPI PsaFwuVirtualAddressChangeEvent ( IN EFI_EVENT Event, IN VOID *Context ) { gRT->ConvertPointer (0x00, (VOID **)&mPsaFwuBuffer); } /** * Get firmware update function request fixed data size. * * @param [in] Command firmware update function id. * * @retval Size of request fixed data. */ STATIC UINTN EFIAPI GetMmFwuReqDataSize ( IN UINT32 Command ) { switch (Command) { case PSA_MM_FWU_COMMAND_BEGIN_STAGING: return sizeof (PSA_MM_FWU_BEGIN_STAGING_REQ); case PSA_MM_FWU_COMMAND_OPEN: return sizeof (PSA_MM_FWU_OPEN_REQ); case PSA_MM_FWU_COMMAND_WRITE_STREAM: return sizeof (PSA_MM_FWU_WRITE_STREAM_REQ); case PSA_MM_FWU_COMMAND_READ_STREAM: return sizeof (PSA_MM_FWU_READ_STREAM_REQ); case PSA_MM_FWU_COMMAND_COMMIT: return sizeof (PSA_MM_FWU_COMMIT_REQ); case PSA_MM_FWU_COMMAND_ACCEPT_IMAGE: return sizeof (PSA_MM_FWU_ACCEPT_IMAGE_REQ); default: return 0; } } /** * Get firmware update function response fixed data size. * * @param [in] Command firmware update function id. * * @retval Size of response fixed data. */ STATIC UINTN EFIAPI GetMmFwuRespDataSize ( IN UINT32 Command ) { switch (Command) { case PSA_MM_FWU_COMMAND_DISCOVER: return sizeof (PSA_MM_FWU_DISCOVER_RESP); case PSA_MM_FWU_COMMAND_OPEN: return sizeof (PSA_MM_FWU_OPEN_RESP); case PSA_MM_FWU_COMMAND_READ_STREAM: return sizeof (PSA_MM_FWU_READ_STREAM_RESP); case PSA_MM_FWU_COMMAND_COMMIT: return sizeof (PSA_MM_FWU_COMMIT_RESP); default: return 0; } } /** * Calculate maximum available data size that can be sent in one MmCommunication. * * @param [in] Command Firmware update function id. * * @retval Maximum available data size could be sent on @Command. */ STATIC UINTN EFIAPI FwuGetAvailableReqDataSize ( IN UINT32 Command ) { return mPsaFwuMaxBufferSize - sizeof (PSA_MM_FWU_PARAMETER_HEADER) - GetMmFwuReqDataSize (Command); } /** * Calculate maximum available data size that can be received in one MmCommunication. * * @param [in] Command Firmware update function id. * * @retval Maximum available data size could be received on @Command. */ STATIC UINTN EFIAPI FwuGetAvailableRespDataSize ( IN UINT32 Command ) { return mPsaFwuMaxBufferSize - sizeof (PSA_MM_FWU_PARAMETER_HEADER) - GetMmFwuRespDataSize (Command); } /** Send a firmware update function request to StMM and Receive response. @param[in] Command Firmware update function id. @param[in] ReqData Request fixed data according to @Command. @param[in] ClientSendData Request variable data according to @Command. @param[in] ClientSendDataSize Size of request variable data. @param[in] ClientRecvDataSize Size of response variable data. @param[out] RespMsg Response including data from StMM. @retval EFI_SUCCESS @retval EFI_INVALID_PARAMETER @retval Others Fail to handle firmware update function. **/ STATIC EFI_STATUS EFIAPI SendFwuRequest ( IN UINT32 Command, IN VOID *ReqData, IN CONST VOID *ClientSendData, IN UINTN ClientSendDataSize, IN UINTN ClientRecvDataSize, OUT PSA_MM_FWU_CMD_DATA **RespMsg ) { EFI_STATUS Status; PSA_MM_FWU_CMD_DATA *CmdData; VOID *Buffer; UINTN ReqDataSize; UINTN RespDataSize; UINTN TotalReqCommBufferSize; UINTN TotalRespCommBufferSize; UINTN TotalBufferSize; DIRECT_MSG_ARGS EmptyArgs; if ((RespMsg == NULL) || (mPsaFwuBuffer == NULL)) { return EFI_INVALID_PARAMETER; } *RespMsg = NULL; ReqDataSize = GetMmFwuReqDataSize (Command); RespDataSize = GetMmFwuRespDataSize (Command); if ((FwuGetAvailableReqDataSize (Command) < ClientSendDataSize) || (FwuGetAvailableRespDataSize (Command) < ClientRecvDataSize)) { return EFI_BUFFER_TOO_SMALL; } TotalReqCommBufferSize = sizeof (PSA_MM_FWU_PARAMETER_HEADER) + ReqDataSize + ClientSendDataSize; TotalRespCommBufferSize = sizeof (PSA_MM_FWU_PARAMETER_HEADER) + RespDataSize + ClientRecvDataSize; TotalBufferSize = MAX (TotalReqCommBufferSize, TotalRespCommBufferSize); ZeroMem (mPsaFwuBuffer, TotalBufferSize); ZeroMem (&EmptyArgs, sizeof (DIRECT_MSG_ARGS)); CmdData = (PSA_MM_FWU_CMD_DATA *)mPsaFwuBuffer; CmdData->Header.Command = Command; Buffer = GET_FWU_DATA_BUFFER (CmdData); CopyMem (Buffer, ReqData, ReqDataSize); if ((ClientSendData != NULL) && (ClientSendDataSize > 0)) { CopyMem (((UINT8 *)Buffer + ReqDataSize), ClientSendData, ClientSendDataSize); } Status = ArmFfaLibMsgSendDirectReq2 ( mUpdateAgentId, &gPsaFwuUpdateAgentGuid, &EmptyArgs ); if (EFI_ERROR (Status)) { return Status; } *RespMsg = (PSA_MM_FWU_CMD_DATA *)mPsaFwuBuffer; return EFI_SUCCESS; } /** * Convert FwuStatus to EFI_STATUS. * * @param [in] FwuStatus Firmware update function return status. * * @retval Matched EFI_STATUS with FwuStatus. * */ STATIC EFI_STATUS EFIAPI FwuStatusToEfiStatus ( IN UINT32 FwuStatus ) { switch (FwuStatus) { case PSA_MM_FWU_SUCCESS: return EFI_SUCCESS; case PSA_MM_FWU_UNKNOWN: return EFI_NOT_FOUND; case PSA_MM_FWU_BUSY: return EFI_NOT_READY; case PSA_MM_FWU_OUT_OF_BOUNDS: return EFI_OUT_OF_RESOURCES; case PSA_MM_FWU_AUTH_FAIL: return EFI_SECURITY_VIOLATION; case PSA_MM_FWU_NO_PERMISSION: case PSA_MM_FWU_DENIED: return EFI_ACCESS_DENIED; case PSA_MM_FWU_RESUME: return EFI_TIMEOUT; case PSA_MM_FWU_NOT_AVAILABLE: return EFI_UNSUPPORTED; } return EFI_DEVICE_ERROR; } /** Send and receive response data for firmware update function request. @param[in] Command Firmware update function id. @param[in] ReqData Request fixed data according to @Command. @param[in] ClientSendData Request variable data according to @Command. @param[in] ClientSendDataSize Size of request variable data. @param[in] ClientRecvDataSize Size of response variable data. @param[out] RespData If successes, Response data correspond to @Command. @retval EFI_SUCCESS @retval Others Failed to @Command request. **/ STATIC EFI_STATUS EFIAPI FwuCommunicate ( IN UINT32 Command, IN VOID *ReqData, IN CONST VOID *ClientSendData, IN UINTN ClientSendDataSize, IN UINTN ClientRecvDataSize, OUT VOID **RespData ) { EFI_STATUS Status; PSA_MM_FWU_CMD_DATA *RespMsg; UINT32 FwuStatus; UINTN RespDataSize; if (RespData != NULL) { *RespData = NULL; } /** * SendFwuRequest calls Smc call. * So, it needs to pass RespBuffer. */ Status = SendFwuRequest ( Command, ReqData, ClientSendData, ClientSendDataSize, ClientRecvDataSize, &RespMsg ); if (EFI_ERROR (Status)) { return Status; } FwuStatus = RespMsg->Header.ResponseStatus; if ((FwuStatus == PSA_MM_FWU_SUCCESS) || (FwuStatus == PSA_MM_FWU_RESUME)) { RespDataSize = GetMmFwuRespDataSize (Command); if ((RespDataSize > 0) && (RespData != NULL)) { *RespData = (VOID *)RespMsg + sizeof (PSA_MM_FWU_CMD_DATA); } } return FwuStatusToEfiStatus (FwuStatus); } /** * Get firmware update agent partition id. * * @param [out] UpdateAgentId Update agent partition id * * @retval EFI_SUCCESS Success to get Update agent id * @retval EFI_UNSUPPORTED Firmware update doesn't support * @retval Others Error for FF-A request. * */ STATIC EFI_STATUS EFIAPI FwuGetUpdateAgentId ( OUT UINT16 *UpdateAgentId ) { EFI_STATUS Status; EFI_FFA_PART_INFO_DESC *PartInfo; EFI_GUID *ServiceGuid; VOID *RxBuffer; UINT64 RxBufferSize; UINT32 Count; UINT32 Size; UINT16 PartId; if (!IsFfaSupported ()) { return EFI_UNSUPPORTED; } Status = ArmFfaLibPartitionIdGet (&PartId); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: Failed to get my partition id. Status:%r\n", __func__, Status )); return Status; } Status = ArmFfaLibGetRxTxBuffers ( NULL, NULL, &RxBuffer, &RxBufferSize ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: Failed to get Rx Buffer. Status:%r\n", __func__, Status )); return Status; } ServiceGuid = &gPsaFwuUpdateAgentGuid; Status = ArmFfaLibPartitionInfoGet ( ServiceGuid, FFA_PART_INFO_FLAG_TYPE_DESC, &Count, &Size ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "%a: (Fallback) Failed to get Update agent partition info. Status:%r\n", __func__, Status )); goto ErrorHandler; } PartInfo = (EFI_FFA_PART_INFO_DESC *)RxBuffer; if ((PartInfo->PartitionProps & FFA_PART_PROP_RECV_DIRECT_REQ2) == 0x00) { DEBUG (( DEBUG_ERROR, "%a: (Fallback) Update agent doesn't support direct msg v2...\n", __func__ )); Status = EFI_UNSUPPORTED; goto ErrorHandler; } *UpdateAgentId = PartInfo->PartitionId; ErrorHandler: ArmFfaLibRxRelease (PartId); return Status; } /** * Send a FWU discovery request to StMM and get the associated response. * * @param [out] Discovery Discovery data related to firmware update. * * @retval EFI_SUCCESS * @retval Others fwu_discovery isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuDiscovery ( OUT PSA_MM_FWU_DISCOVER_RESP **Discovery ) { EFI_STATUS Status; if (Discovery == NULL) { return EFI_INVALID_PARAMETER; } *Discovery = NULL; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_discovery request | * |------------------------------------------------>| * | | * |<------------------------------------------------| * fwu_status with * (fwu discovery info) * (See PSA-FWU spec 3.4.2.1) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_DISCOVER, NULL, NULL, 0, FwuGetAvailableRespDataSize (PSA_MM_FWU_COMMAND_DISCOVER), (VOID **)Discovery ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send a Begin Staging request to StMM and get the associated response thereby * start new staging process for firmware update. * * @param [in] UpdateGuids Image type guids to update (partial update). * If NULL, try to update all. * @param [in] UpdateCount Number of Guids in @UpdateGuids. * @param [in] VendorFlags Vendor Specific flags. * * @retval EFI_SUCCESS * @retval EFI_NOT_READY - Firmware Store in Trial State or * Not boot correctly using active bank. * - Temporarily couldn't enter staging. * @retval EFI_NOT_FOUND Couldn't find one image or more in @UpdateGuid. * @retval Others fwu_begin_staging isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuBeginStaging ( IN CONST EFI_GUID *UpdateGuids, IN UINT32 UpdateCount, IN UINT32 VendorFlags ) { EFI_STATUS Status; PSA_MM_FWU_BEGIN_STAGING_REQ ReqData; if ((UpdateCount > 0) && (UpdateGuids == NULL)) { return EFI_INVALID_PARAMETER; } ReqData.VendorFlags = VendorFlags; ReqData.PartialUpdateCount = UpdateCount; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_begin_staging request | * | (vendor flags, patrial_update_count, updateGuids) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.2) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_BEGIN_STAGING, &ReqData, UpdateGuids, sizeof (EFI_GUID) * UpdateCount, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send a FWU End Staging request to the StMM and get the associated response, * thereby finish staging process for firmware update. * * @retval EFI_SUCCESS * @retval EFI_NOT_READY - Firmware store is not on staging state. * - There're still open image handles. * @retval EFI_SECURITY_VIOLATION Some updated image fail to authenticate. * @retval EFI_UNSUPPORTED Update Agent doesn't support partial updates * or Client has not updated all the images. * @retval Others fwu_end_staging isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuEndStaging ( IN VOID ) { EFI_STATUS Status; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_end_staging request | * |------------------------------------------------>| * | | * |<------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.3) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_END_STAGING, NULL, NULL, 0, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send a FWU Cancel Staging request to StMM and get the associated response * thereby cancel staging process for firmware update. * * @retval EFI_SUCCESS * @retval EFI_NOT_READY Firmware store is not on staging state. * @retval Others fwu_cancel_staging isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuCancelStaging ( IN VOID ) { EFI_STATUS Status; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_cancel_staging request | * |------------------------------------------------>| * | | * |<------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.4) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_CANCEL_STAGING, NULL, NULL, 0, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send a FWU Open request to StMM and get associated response * thereby open image file handle related to @ImageTypeGuid. * * @param [in] ImageTypeGuid Image type guid. * @param [in] OpType FwuOpStreamRead or FwuOpStreamWrite. * @param [out] Handle Image File Handle. * * @retval EFI_SUCCESS * @retval EFI_NOT_FOUND Couldn't find image with @ImageTypeGuid. * @retval EFI_NOT_READY Try to open with write out of staging state. * @retval EFI_UNSUPPORTED @ImageTypeGuid doesn't support open with @OpType. * @retval Others fwu_open isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuOpen ( IN CONST EFI_GUID *ImageTypeGuid, IN FWU_OP_TYPE OpType, OUT UINT32 *Handle ) { EFI_STATUS Status; PSA_MM_FWU_OPEN_REQ ReqData; PSA_MM_FWU_OPEN_RESP *RespData; if ((ImageTypeGuid == NULL) || (Handle == NULL)) { return EFI_INVALID_PARAMETER; } *Handle = FWU_INVALID_HANDLE; CopyGuid (&ReqData.ImageTypeGuid, ImageTypeGuid); ReqData.OperationType = OpType; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_open request | * | (image_type_guid, op_type) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status && handle * (See PSA-FWU spec 3.4.2.5) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_OPEN, &ReqData, NULL, 0, 0, (VOID **)&RespData ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); return Status; } *Handle = RespData->Handle; return EFI_SUCCESS; } /** * Send FWU Write Stream request to StMM and get associated response * thereby write new firmware image to @Handle. * * @param [in] Handle Image file handle. * @param [in] Buffer New firmware image data. * @param [in] BufferSize Size of @Buffer in bytes. * * @retval EFI_SUCCESS * @retval EFI_NOT_FOUND Invalid @Handle. * @retval EFI_OUT_OF_RESOURCE @BufferSize is over maximum image size. * @retval EFI_ACCESS_DENIED Image cannot be write to. * @retval EFI_NOT_READY Firmware store isn't staging state. * @retval Others fwu_write_stream isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuWriteStream ( IN UINT32 Handle, IN CONST VOID *Buffer, IN UINT32 BufferSize ) { EFI_STATUS Status; PSA_MM_FWU_WRITE_STREAM_REQ ReqData; if ((Handle == FWU_INVALID_HANDLE) || (Buffer == NULL) || (BufferSize == 0)) { return EFI_INVALID_PARAMETER; } if (BufferSize > FwuGetAvailableReqDataSize (PSA_MM_FWU_COMMAND_WRITE_STREAM)) { return EFI_BAD_BUFFER_SIZE; } ReqData.Handle = Handle; ReqData.DataLen = BufferSize; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_write_stream request | * | (handle, data_len, payload) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.6) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_WRITE_STREAM, &ReqData, Buffer, BufferSize, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send FWU Read Stream request to StMM and get associated response * thereby read firmware image from @Handle. * * @param [in] Handle Image file handle. * @param [out] Buffer Data Buffer * @param [in] BufferSize Request bytes to read. * @param [out] ReadyBytes Real read bytes. * @param [out] TotalBytes Current image size of @Handle. * * @retval EFI_SUCCESS * @retval EFI_NOT_FOUND Invalid @Handle. * @retval EFI_ACCESS_DENIED Image cannot be read from. * @retval EFI_NOT_READY Image cannot be read temporarily. * @retval Others fwu_read_stream isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuReadStream ( IN UINT32 Handle, OUT VOID *Buffer, IN UINT32 BufferSize, OUT UINT32 *ReadBytes, OUT UINT32 *TotalBytes ) { EFI_STATUS Status; PSA_MM_FWU_READ_STREAM_REQ ReqData; PSA_MM_FWU_READ_STREAM_RESP *RespData; UINTN MaxReadSize; VOID *Payload; if ((Handle == FWU_INVALID_HANDLE) || ((BufferSize != 0) && (Buffer == NULL)) || (ReadBytes == NULL)) { return EFI_INVALID_PARAMETER; } MaxReadSize = FwuGetAvailableRespDataSize (PSA_MM_FWU_COMMAND_READ_STREAM); ReqData.Handle = Handle; *ReadBytes = MIN (BufferSize, MaxReadSize); /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_read_stream request | * | (handle) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status with * (read_bytes, total_bytes, payload) * (See PSA-FWU spec 3.4.2.6) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_READ_STREAM, &ReqData, NULL, 0, *ReadBytes, (VOID **)&RespData ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); return Status; } Payload = (VOID *)GET_FWU_DATA_BUFFER (RespData); if (Buffer != NULL) { CopyMem (Buffer, Payload, RespData->ReadBytes); } *ReadBytes = RespData->ReadBytes; if (TotalBytes != NULL) { *TotalBytes = RespData->TotalBytes; } return EFI_SUCCESS; } /** * Send FWU Commit request to StMM and get associated response * thereby close the Handle and commit the image on firmware storage. * * @param [in] Handle Image file handle. * @param [in] AcceptReq If > 0, Not accept image in commit. * remain as unacceptable status. * otherwise, try to accept image in commit. * @param [in] MaxAtomicTimeNs Maximum time (in ns) executing without * yielding back to client. * @param [out] Progress Unit of work already completed. * @param [out] TotalWork Unit of work must be completed. * * @retval EFI_SUCCESS * @retval EFI_NOT_FOUND Invalid @Handle. * @retval EFI_SECURITY_VIOLATION Handle is closed but fail to authenticate. * @retval EFI_TIMEOUT Update procedure is yielded. * must call again fwu_commit. * @retval EFI_NOT_READY Image can only be accepted after activation. * @AcceptReq should be > 0. * @retval Others fwu_read_stream isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuCommit ( IN UINT32 Handle, IN UINT32 AcceptReq, IN UINT32 MaxAtomicTimeNs, OUT UINT32 *Progress, OUT UINT32 *TotalWork ) { EFI_STATUS Status; PSA_MM_FWU_COMMIT_REQ ReqData; PSA_MM_FWU_COMMIT_RESP *RespData; if ((Handle == FWU_INVALID_HANDLE) || (Progress == NULL) || (TotalWork == NULL)) { return EFI_INVALID_PARAMETER; } ReqData.Handle = Handle; ReqData.AcceptanceReq = AcceptReq; ReqData.MaxAtomicLen = MaxAtomicTimeNs; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_commit request | * | (handle, accept_req, max_atomic_len) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status with * (progress, total_work) * (See PSA-FWU spec 3.4.2.8) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_COMMIT, &ReqData, NULL, 0, 0, (VOID **)&RespData ); if (EFI_ERROR (Status) && (Status != EFI_TIMEOUT)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); return Status; } *Progress = RespData->Progress; *TotalWork = RespData->TotalWork; return Status; } /** * Send FWU Accept Image request to StMM and get associated response * thereby accept updated image. * * Note: * fwu_accept_image only allow when boot correctly (boot with active_index). * That means this call only can accept the image on the active indexed bank. * * @param [in] ImageTypeGuid Image type guid. * * @retval EFI_SUCCESS * @retval EFI_NOT_FOUND Couldn't find image with @ImageTypeGuid * @retval EFI_NOT_READY System boot incorrectly. * @retval Others fwu_accept_image isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuAcceptImage ( IN CONST EFI_GUID *ImageTypeGuid ) { EFI_STATUS Status; PSA_MM_FWU_ACCEPT_IMAGE_REQ ReqData; if (ImageTypeGuid == NULL) { return EFI_INVALID_PARAMETER; } ReqData.Reserved = 0x00000000; CopyGuid (&ReqData.ImageTypeGuid, ImageTypeGuid); /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_accpet_image request | * | (image_type_guid) | * |-------------------------------------------------->| * | | * |<--------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.9) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_ACCEPT_IMAGE, &ReqData, NULL, 0, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** * Send FWU Select Previous request to StMM and get associated response. * When Firmware store is in Trial state or System boot incorrectly, * Rollback active indexed bank's images using previous indexed ones. * * @retval EFI_SUCCESS * @retval EFI_NOT_READY - System isn't in Trial state or boot correctly. * - Previous indexed bank couldn't be booted. * @retval Others fwu_accept_image isn't implemented or * Error while communicating StMM. */ EFI_STATUS EFIAPI FwuSelectPrevious ( IN VOID ) { EFI_STATUS Status; /** * +-----------------------+ +-------------------------------+ * | UEFI (FmpDevicePkg) | | StandaloneMm (FwuStMm Driver) | * +-----------------------+ +-------------------------------+ * | fwu_select_previous request | * |------------------------------------------------>| * | | * |<------------------------------------------------| * fwu_status * (See PSA-FWU spec 3.4.2.10) */ Status = FwuCommunicate ( PSA_MM_FWU_COMMAND_SELECT_PREVIOUS, NULL, NULL, 0, 0, NULL ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to %a. Status: %r\n", __func__, Status)); } return Status; } /** Clear resources when PsaFwuLibInit() is failed. **/ VOID EFIAPI PsaFwuLibExit ( IN VOID ) { mPsaFwuMaxBufferSize = 0; mPsaFwuBuffer = NULL; } /** Platform Flash Access Lib Constructor. **/ EFI_STATUS EFIAPI PsaFwuLibInit ( IN VOID ) { EFI_STATUS Status; if (MM_SHARED_BUFFER_SIZE == 0) { return EFI_OUT_OF_RESOURCES; } Status = FwuGetUpdateAgentId (&mUpdateAgentId); if (EFI_ERROR (Status)) { return Status; } // Buffer used to communicate with update agent. // currently, use Non secure shared buffer. mPsaFwuBuffer = (VOID *)(UINTN)PcdGet64 (PcdMmBufferBase); mPsaFwuMaxBufferSize = MM_SHARED_BUFFER_SIZE; DEBUG ((DEBUG_INFO, "%a: Update agent partition id: 0x%x\n", __func__, mUpdateAgentId)); DEBUG ((DEBUG_INFO, "%a: mPsaFwuMaxBufferSize: %d\n", __func__, mPsaFwuMaxBufferSize)); return EFI_SUCCESS; }