Implement EDKII ETag protocol to manipulate ETag of HTTP content. Signed-off-by: Nickle Wang <nick...@nvidia.com> Cc: Abner Chang <abner.ch...@amd.com> Cc: Igor Kulchytskyy <ig...@ami.com> --- .../RedfishETagDxe/RedfishETagDxe.inf | 45 + .../Protocol/EdkIIRedfishETagProtocol.h | 76 ++ .../RedfishETagDxe/RedfishETagDxe.h | 70 ++ .../RedfishETagDxe/RedfishETagDxe.c | 772 ++++++++++++++++++ 4 files changed, 963 insertions(+) create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf create mode 100644 RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h create mode 100644 RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c
diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf new file mode 100644 index 00000000..e29a1045 --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.inf @@ -0,0 +1,45 @@ +## @file +# +# (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001000b + BASE_NAME = RedfishETagDxe + FILE_GUID = F7BB0BB2-9796-485F-9F00-C0EB47E9F92B + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = RedfishETagDriverEntryPoint + UNLOAD_IMAGE = RedfishETagDriverUnload + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + RedfishPkg/RedfishPkg.dec + RedfishClientPkg/RedfishClientPkg.dec + +[Sources] + RedfishETagDxe.h + RedfishETagDxe.c + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + MemoryAllocationLib + UefiLib + UefiBootServicesTableLib + UefiRuntimeServicesTableLib + UefiDriverEntryPoint + +[Protocols] + gEdkIIRedfishETagProtocolGuid ## PRODUCED ## + +[Guids] + gEfiEventExitBootServicesGuid ## CONSUMES ## Event + +[Depex] + TRUE diff --git a/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h new file mode 100644 index 00000000..4e10965a --- /dev/null +++ b/RedfishClientPkg/Include/Protocol/EdkIIRedfishETagProtocol.h @@ -0,0 +1,76 @@ +/** @file + This file defines the EDKII_REDFISH_FEATURE_PROTOCOL interface. + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef EDKII_REDFISH_ETAG_PROTOCOL_H_ +#define EDKII_REDFISH_ETAG_PROTOCOL_H_ + +typedef struct _EDKII_REDFISH_ETAG_PROTOCOL EDKII_REDFISH_ETAG_PROTOCOL; + +/** + Get ETag string by given URI + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + @param[in] Uri Target URI to search. + @param[out] ETag The ETag string to corresponding URI. + + @retval EFI_SUCCESS The ETag is found successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter is given. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_GET)( + IN EDKII_REDFISH_ETAG_PROTOCOL *This, + IN CHAR8 *Uri, + OUT CHAR8 **ETag + ); + +/** + Keep ETag string which maps to given Uri. + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + @param[in] Uri The target Uri which related to ETag. + @param[in] ETag The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed. + + @retval EFI_SUCCESS This handler has been stoped successfully. + @retval Others Some error happened. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_SET)( + IN EDKII_REDFISH_ETAG_PROTOCOL *This, + IN CHAR8 *Uri, + IN CHAR8 *ETag + ); + +/** + Refresh the ETag database and save database to variable. + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + + @retval EFI_SUCCESS This handler has been stoped successfully. + @retval Others Some error happened. + +**/ +typedef +EFI_STATUS +(EFIAPI *EDKII_REDFISH_ETAG_PROTOCOL_FLUSH)( + IN EDKII_REDFISH_ETAG_PROTOCOL *This + ); + +struct _EDKII_REDFISH_ETAG_PROTOCOL { + EDKII_REDFISH_ETAG_PROTOCOL_GET Get; + EDKII_REDFISH_ETAG_PROTOCOL_SET Set; + EDKII_REDFISH_ETAG_PROTOCOL_FLUSH Flush; +}; + +extern EFI_GUID gEdkIIRedfishETagProtocolGuid; + +#endif diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h new file mode 100644 index 00000000..6dffa9d7 --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.h @@ -0,0 +1,70 @@ +/** @file + Common header file for RedfishETagDxe driver. + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef REDFISH_ETAG_DXE_H_ +#define REDFISH_ETAG_DXE_H_ + +#include <Uefi.h> + +// +// Libraries +// +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> + +#include <Library/MemoryAllocationLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Library/UefiDriverEntryPoint.h> +#include <Library/UefiLib.h> +#include <Library/UefiRuntimeServicesTableLib.h> + +#include <Protocol/EdkIIRedfishETagProtocol.h> + +#include <Guid/VariableFormat.h> + +#define ETAG_VARIABLE_NAME L"RedfishETag" +#define IS_EMPTY_STRING(a) ((a) == NULL || (a)[0] == '\0') +#define ETAG_DEBUG_ENABLED 0x00 + +// +// Definition of REDFISH_ETAG_RECORD +// +typedef struct { + LIST_ENTRY List; + CHAR8 *Uri; + CHAR8 *ETag; + UINTN Size; +} REDFISH_ETAG_RECORD; + +#define REDFISH_ETAG_RECORD_FROM_LIST(a) BASE_CR (a, REDFISH_ETAG_RECORD, List) + +// +// Definition of REDFISH_ETAG_LIST +// +typedef struct { + LIST_ENTRY Listheader; + UINTN TotalSize; + UINTN Count; +} REDFISH_ETAG_LIST; + +// +// Definition of REDFISH_ETAG_PRIVATE_DATA +// +typedef struct { + EFI_HANDLE ImageHandle; + REDFISH_ETAG_LIST ETagList; + EDKII_REDFISH_ETAG_PROTOCOL Protocol; + EFI_STRING VariableName; + EFI_EVENT Event; +} REDFISH_ETAG_PRIVATE_DATA; + +#define REDFISH_ETAG_PRIVATE_FROM_THIS(a) BASE_CR (a, REDFISH_ETAG_PRIVATE_DATA, Protocol) + +#endif diff --git a/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c new file mode 100644 index 00000000..af920afc --- /dev/null +++ b/RedfishClientPkg/RedfishETagDxe/RedfishETagDxe.c @@ -0,0 +1,772 @@ +/** @file + + (C) Copyright 2021 Hewlett Packard Enterprise Development LP<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "RedfishETagDxe.h" + +REDFISH_ETAG_PRIVATE_DATA *mRedfishETagPrivate = NULL; + +/** + Release REDFISH_ETAG_RECORD resource + + @param[in] Record Pointer to REDFISH_ETAG_RECORD instance + + @retval EFI_SUCCESS REDFISH_ETAG_RECORD is released successfully. + @retval EFI_INVALID_PARAMETER Record is NULL + +**/ +EFI_STATUS +ReleaseETagRecord ( + IN REDFISH_ETAG_RECORD *Record + ) +{ + if (Record == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Record->Uri != NULL) { + FreePool (Record->Uri); + } + + if (Record->ETag != NULL) { + FreePool (Record->ETag); + } + + FreePool (Record); + + return EFI_SUCCESS; +} + +/** + Create new Etag resource. + + @param[in] Uri The URI string matching to this ETAG. + @param[in] ETag ETAG string. + + @retval REDFISH_ETAG_RECORD * Pointer to newly created ETAG. + @retval NULL No memory available. + +**/ +REDFISH_ETAG_RECORD * +NewETagRecord ( + IN CHAR8 *Uri, + IN CHAR8 *ETag + ) +{ + REDFISH_ETAG_RECORD *NewRecord; + UINTN Size; + + if (IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) { + return NULL; + } + + NewRecord = AllocateZeroPool (sizeof (REDFISH_ETAG_RECORD)); + if (NewRecord == NULL) { + return NULL; + } + + Size = AsciiStrSize (Uri); + NewRecord->Uri = AllocateCopyPool (Size, Uri); + if (NewRecord->Uri == NULL) { + goto ON_ERROR; + } + + NewRecord->Size = Size; + Size = AsciiStrSize (ETag); + NewRecord->ETag = AllocateCopyPool (Size, ETag); + if (NewRecord->ETag == NULL) { + goto ON_ERROR; + } + + NewRecord->Size += Size; + return NewRecord; + +ON_ERROR: + + if (NewRecord != NULL) { + ReleaseETagRecord (NewRecord); + } + + return NULL; +} + +/** + Add new ETAG by given URI and ETAG string to specify List. + + @param[in] List Target ETAG list to add. + @param[in] Uri The URI string matching to this ETAG. + @param[in] ETag ETAG string. + + @retval EFI_SUCCESS ETAG recourd is added. + @retval Others Fail to add ETAG. + +**/ +EFI_STATUS +AddETagRecord ( + IN REDFISH_ETAG_LIST *List, + IN CHAR8 *Uri, + IN CHAR8 *ETag + ) +{ + REDFISH_ETAG_RECORD *NewRecord; + + if ((List == NULL) || IS_EMPTY_STRING (Uri) || IS_EMPTY_STRING (ETag)) { + return EFI_INVALID_PARAMETER; + } + + NewRecord = NewETagRecord (Uri, ETag); + if (NewETagRecord == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InsertTailList (&List->Listheader, &NewRecord->List); + ++List->Count; + List->TotalSize += NewRecord->Size; + + return EFI_SUCCESS; +} + +/** + Delete an ETAG by given ETAG instance. + + @param[in] List Target ETAG list to be removed. + @param[in] Record Pointer to the instance to be deleted. + + @retval EFI_SUCCESS ETAG recourd is removed. + @retval Others Fail to add ETAG. + +**/ +EFI_STATUS +DeleteETagRecord ( + IN REDFISH_ETAG_LIST *List, + IN REDFISH_ETAG_RECORD *Record + ) +{ + if ((List == NULL) || (Record == NULL)) { + return EFI_INVALID_PARAMETER; + } + + RemoveEntryList (&Record->List); + --List->Count; + List->TotalSize -= Record->Size; + + return ReleaseETagRecord (Record); +} + +/** + Search on given ListHeader for given URI string. + + @param[in] ListHeader Target list to search. + @param[in] Uri Target URI to search. + + @retval REDFISH_ETAG_RECORD Target ETAG is found. + @retval NULL No ETAG with given URI is found. + +**/ +REDFISH_ETAG_RECORD * +FindETagRecord ( + IN LIST_ENTRY *ListHeader, + IN CHAR8 *Uri + ) +{ + LIST_ENTRY *List; + REDFISH_ETAG_RECORD *Record; + + if (IsListEmpty (ListHeader)) { + return NULL; + } + + Record = NULL; + List = GetFirstNode (ListHeader); + while (!IsNull (ListHeader, List)) { + Record = REDFISH_ETAG_RECORD_FROM_LIST (List); + + if (AsciiStrCmp (Record->Uri, Uri) == 0) { + return Record; + } + + List = GetNextNode (ListHeader, List); + } + + return NULL; +} + +#if ETAG_DEBUG_ENABLED + +/** + Debug output the ETAG list. + + @param[in] ETagList Target list to dump + @param[in] Msg Debug message string. + + @retval EFI_SUCCESS Debug dump finished. + @retval EFI_INVALID_PARAMETER ETagList is NULL. + +**/ +EFI_STATUS +DumpETagList ( + IN REDFISH_ETAG_LIST *ETagList, + IN EFI_STRING Msg + ) +{ + LIST_ENTRY *List; + REDFISH_ETAG_RECORD *Record; + + if (ETagList == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!IS_EMPTY_STRING (Msg)) { + DEBUG ((DEBUG_ERROR, "%s\n", Msg)); + } + + if (IsListEmpty (&ETagList->Listheader)) { + DEBUG ((DEBUG_INFO, "ETag list is empty\n")); + return EFI_NOT_FOUND; + } + + DEBUG ((DEBUG_INFO, "Count: %d Total Size: %d\n", ETagList->Count, ETagList->TotalSize)); + Record = NULL; + List = GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record = REDFISH_ETAG_RECORD_FROM_LIST (List); + + DEBUG ((DEBUG_INFO, "ETag: %a Uri: %a Size: %d\n", Record->ETag, Record->Uri, Record->Size)); + + List = GetNextNode (&ETagList->Listheader, List); + } + + return EFI_SUCCESS; +} + +/** + Debug output raw data buffer. + + @param[in] Buffer Debug output data buffer. + @param[in] BufferSize The size of Buffer in byte. + + @retval EFI_SUCCESS Debug dump finished. + @retval EFI_INVALID_PARAMETER Buffer is NULL. + +**/ +EFI_STATUS +DumpRawBuffer ( + IN CHAR8 *Buffer, + IN UINTN BufferSize + ) +{ + UINTN Index; + + if (Buffer == NULL) { + return EFI_INVALID_PARAMETER; + } + + Index = 0; + + DEBUG ((DEBUG_ERROR, "Buffer size: %d\n", BufferSize)); + while (Buffer[Index] != '\0') { + DEBUG ((DEBUG_ERROR, "(%d) %c ", (Index + 1), Buffer[Index])); + + ++Index; + } + + DEBUG ((DEBUG_ERROR, "\n")); + + return EFI_SUCCESS; +} + +#endif + +/** + Release all ETag from list. + + @param[in] ETagList The list to be released. + + @retval EFI_SUCCESS All etag is released. + @retval EFI_INVALID_PARAMETER ETagList is NULL. + +**/ +EFI_STATUS +ReleaseETagList ( + IN REDFISH_ETAG_LIST *ETagList + ) +{ + LIST_ENTRY *List; + LIST_ENTRY *Next; + REDFISH_ETAG_RECORD *Record; + + if (ETagList == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (&ETagList->Listheader)) { + return EFI_SUCCESS; + } + + Record = NULL; + Next = NULL; + List = GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record = REDFISH_ETAG_RECORD_FROM_LIST (List); + Next = GetNextNode (&ETagList->Listheader, List); + + DeleteETagRecord (ETagList, Record); + + List = Next; + } + + return EFI_SUCCESS; +} + +/** + Save etag in list to UEFI variable. + + @param[in] ETagList The list to be saved. + @param[in] VariableName The UEFI variable name. + + @retval EFI_SUCCESS All etag is saved. + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL. + +**/ +EFI_STATUS +SaveETagList ( + IN REDFISH_ETAG_LIST *ETagList, + IN EFI_STRING VariableName + ) +{ + LIST_ENTRY *List; + REDFISH_ETAG_RECORD *Record; + CHAR8 *VarData; + VOID *Data; + CHAR8 *Seeker; + UINTN VarSize; + UINTN StrSize; + EFI_STATUS Status; + + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) { + return EFI_INVALID_PARAMETER; + } + + if (IsListEmpty (&ETagList->Listheader)) { + return EFI_SUCCESS; + } + + // + // Caculate the total size we need to keep ETag list. + // + VarSize = ETagList->TotalSize + 1; // terminator character + VarData = AllocateZeroPool (VarSize); + if (VarData == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Seeker = VarData; + Record = NULL; + List = GetFirstNode (&ETagList->Listheader); + while (!IsNull (&ETagList->Listheader, List)) { + Record = REDFISH_ETAG_RECORD_FROM_LIST (List); + + StrSize = AsciiStrSize (Record->Uri); + CopyMem (Seeker, Record->Uri, StrSize); + + Seeker += (StrSize - 1); + *Seeker = '|'; + ++Seeker; + + StrSize = AsciiStrSize (Record->ETag); + CopyMem (Seeker, Record->ETag, StrSize); + + Seeker += (StrSize - 1); + *Seeker = '\n'; + + ++Seeker; + + List = GetNextNode (&ETagList->Listheader, List); + } + + *Seeker = '\0'; + + #if ETAG_DEBUG_ENABLED + DumpRawBuffer (VarData, VarSize); + #endif + + ASSERT (((UINTN)Seeker - (UINTN)VarData + 1) == VarSize); + + // + // Check if variable exists already. If yes, remove it first. + // + Status = GetVariable2 ( + VariableName, + &gEfiCallerIdGuid, + (VOID *)&Data, + NULL + ); + if (!EFI_ERROR (Status)) { + FreePool (Data); + gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, 0, NULL); + } + + return gRT->SetVariable (VariableName, &gEfiCallerIdGuid, VARIABLE_ATTRIBUTE_NV_BS, VarSize, (VOID *)VarData); +} + +/** + Read etag from UEFI variable if it exists. + + @param[in] ETagList The list to be loaded. + @param[in] VariableName The UEFI variable name. + + @retval EFI_SUCCESS All etag is read successfully. + @retval EFI_INVALID_PARAMETER VariableName or ETagList is NULL. + @retval EFI_NOT_FOUND No etag is found on UEFI variable. + +**/ +EFI_STATUS +InitialETagList ( + IN REDFISH_ETAG_LIST *ETagList, + IN EFI_STRING VariableName + ) +{ + CHAR8 *VarData; + CHAR8 *UriPointer; + CHAR8 *ETagPointer; + CHAR8 *Seeker; + UINTN VariableSize; + EFI_STATUS Status; + + if ((ETagList == NULL) || IS_EMPTY_STRING (VariableName)) { + return EFI_INVALID_PARAMETER; + } + + // + // Check if variable exists already. + // + Status = GetVariable2 ( + VariableName, + &gEfiCallerIdGuid, + (VOID *)&VarData, + &VariableSize + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + Seeker = VarData; + UriPointer = VarData; + ETagPointer = VarData; + while (*Seeker != '\0') { + // + // Find URI + // + Seeker = AsciiStrStr (UriPointer, "|"); + if (Seeker == NULL) { + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + goto ON_ERROR; + } + + *Seeker = '\0'; + ETagPointer = ++Seeker; + + // + // Find ETAG + // + Seeker = AsciiStrStr (ETagPointer, "\n"); + if (Seeker == NULL) { + DEBUG ((DEBUG_ERROR, "%a, data corrupted\n", __FUNCTION__)); + Status = EFI_DEVICE_ERROR; + goto ON_ERROR; + } + + *Seeker = '\0'; + + AddETagRecord (ETagList, UriPointer, ETagPointer); + + UriPointer = ++Seeker; + } + + #if ETAG_DEBUG_ENABLED + DumpETagList (ETagList, L"Initial ETag List from Variable"); + #endif + + Status = EFI_SUCCESS; + +ON_ERROR: + + FreePool (VarData); + + return Status; +} + +/** + Get ETag string by given URI + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + @param[in] Uri Target URI to search. + @param[out] ETag The ETag string to corresponding URI. + + @retval EFI_SUCCESS The ETag is found successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter is given. + +**/ +EFI_STATUS +RedfishETagGet ( + IN EDKII_REDFISH_ETAG_PROTOCOL *This, + IN CHAR8 *Uri, + OUT CHAR8 **ETag + ) +{ + REDFISH_ETAG_RECORD *Target; + REDFISH_ETAG_PRIVATE_DATA *Private; + + if ((This == NULL) || IS_EMPTY_STRING (Uri) || (ETag == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + *ETag = NULL; + + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); + if (Target == NULL) { + return EFI_NOT_FOUND; + } + + *ETag = AllocateCopyPool (AsciiStrSize (Target->ETag), Target->ETag); + + return EFI_SUCCESS; +} + +/** + Keep ETag string which maps to given Uri. + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + @param[in] Uri The target Uri which related to ETag. + @param[in] ETag The ETag to add. If ETag is NULL, the record of correspoonding URI will be removed. + + @retval EFI_SUCCESS This handler has been stoped successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +RedfishETagSet ( + IN EDKII_REDFISH_ETAG_PROTOCOL *This, + IN CHAR8 *Uri, + IN CHAR8 *ETag OPTIONAL + ) +{ + REDFISH_ETAG_RECORD *Target; + REDFISH_ETAG_PRIVATE_DATA *Private; + EFI_STATUS Status; + + if ((This == NULL) || IS_EMPTY_STRING (Uri)) { + return EFI_INVALID_PARAMETER; + } + + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + Status = EFI_NOT_FOUND; + Target = FindETagRecord (&Private->ETagList.Listheader, Uri); + if (Target != NULL) { + // + // Remove old one and create new one. + // + Status = DeleteETagRecord (&Private->ETagList, Target); + } + + // + // When ETag is NULL, it means that we want to remov this record. + // + if (ETag == NULL) { + return Status; + } + + return AddETagRecord (&Private->ETagList, Uri, ETag); +} + +/** + Refresh the ETag database and save database to variable. + + @param[in] This Pointer to EDKII_REDFISH_ETAG_PROTOCOL instance. + + @retval EFI_SUCCESS This handler has been stoped successfully. + @retval Others Some error happened. + +**/ +EFI_STATUS +RedfishETagFlush ( + IN EDKII_REDFISH_ETAG_PROTOCOL *This + ) +{ + REDFISH_ETAG_PRIVATE_DATA *Private; + EFI_STATUS Status; + + if (This == NULL) { + return EFI_INVALID_PARAMETER; + } + + Private = REDFISH_ETAG_PRIVATE_FROM_THIS (This); + + Status = SaveETagList (&Private->ETagList, Private->VariableName); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, save ETag list to variable: %s failed: %r\n", __FUNCTION__, Private->VariableName, Status)); + } + + return Status; +} + +/** + Callback function executed when the ExitBootService event group is signaled. + + @param[in] Event Event whose notification function is being invoked. + @param[out] Context Pointer to the Context buffer + +**/ +VOID +EFIAPI +RedfishETagOnExitBootService ( + IN EFI_EVENT Event, + OUT VOID *Context + ) +{ + // + // Memory is about to be released. Keep list into variable. + // + RedfishETagFlush (&mRedfishETagPrivate->Protocol); +} + +/** + Unloads an image. + + @param[in] ImageHandle Handle that identifies the image to be unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. + +**/ +EFI_STATUS +EFIAPI +RedfishETagDriverUnload ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + + if (mRedfishETagPrivate != NULL) { + Status = gBS->UninstallProtocolInterface ( + mRedfishETagPrivate->ImageHandle, + &gEdkIIRedfishETagProtocolGuid, + (VOID *)&mRedfishETagPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not uninstall gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + } + + ReleaseETagList (&mRedfishETagPrivate->ETagList); + + if (mRedfishETagPrivate->VariableName != NULL) { + FreePool (mRedfishETagPrivate->VariableName); + } + + if (mRedfishETagPrivate->Event != NULL) { + gBS->CloseEvent (mRedfishETagPrivate->Event); + } + + FreePool (mRedfishETagPrivate); + mRedfishETagPrivate = NULL; + } + + return EFI_SUCCESS; +} + +// +// EDKII_REDFISH_ETAG_PROTOCOL. +// +EDKII_REDFISH_ETAG_PROTOCOL mRedfishETagProtocol = { + RedfishETagGet, + RedfishETagSet, + RedfishETagFlush +}; + +/** + This is the declaration of an EFI image entry point. This entry point is + the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including + both device drivers and bus drivers. + + @param[in] ImageHandle The firmware allocated handle for the UEFI image. + @param[in] SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The operation completed successfully. + @retval Others An unexpected error occurred. +**/ +EFI_STATUS +EFIAPI +RedfishETagDriverEntryPoint ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + mRedfishETagPrivate = AllocateZeroPool (sizeof (REDFISH_ETAG_PRIVATE_DATA)); + if (mRedfishETagPrivate == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + InitializeListHead (&mRedfishETagPrivate->ETagList.Listheader); + mRedfishETagPrivate->VariableName = AllocateCopyPool (StrSize (ETAG_VARIABLE_NAME), ETAG_VARIABLE_NAME); + if (mRedfishETagPrivate->VariableName == NULL) { + goto ON_ERROR; + } + + mRedfishETagPrivate->ImageHandle = ImageHandle; + CopyMem (&mRedfishETagPrivate->Protocol, &mRedfishETagProtocol, sizeof (EDKII_REDFISH_ETAG_PROTOCOL)); + + Status = gBS->InstallProtocolInterface ( + &ImageHandle, + &gEdkIIRedfishETagProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID *)&mRedfishETagPrivate->Protocol + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a, can not install gEdkIIRedfishETagProtocolGuid: %r\n", __FUNCTION__, Status)); + ASSERT (FALSE); + goto ON_ERROR; + } + + // + // Create Exit Boot Service event. + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + RedfishETagOnExitBootService, + NULL, + &gEfiEventExitBootServicesGuid, + &mRedfishETagPrivate->Event + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Fail to register Exit Boot Service event.", __FUNCTION__)); + goto ON_ERROR; + } + + // + // Read existing record from variable. + // + Status = InitialETagList (&mRedfishETagPrivate->ETagList, mRedfishETagPrivate->VariableName); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a, Initial ETag List: %r\n", __FUNCTION__, Status)); + } + + return EFI_SUCCESS; + +ON_ERROR: + + RedfishETagDriverUnload (ImageHandle); + + return Status; +} -- 2.17.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#104011): https://edk2.groups.io/g/devel/message/104011 Mute This Topic: https://groups.io/mt/98684703/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-