/** @file Implementation for EFI_HII_DATABASE_PROTOCOL. Copyright (c) 2007 - 2020, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "HiiDatabase.h" #define BASE_NUMBER 10 EFI_HII_PACKAGE_LIST_HEADER *gRTDatabaseInfoBuffer = NULL; EFI_STRING gRTConfigRespBuffer = NULL; UINTN gDatabaseInfoSize = 0; UINTN gConfigRespSize = 0; BOOLEAN gExportConfigResp = FALSE; UINTN gNvDefaultStoreSize = 0; SKU_ID gSkuId = 0xFFFFFFFFFFFFFFFF; LIST_ENTRY gVarStorageList = INITIALIZE_LIST_HEAD_VARIABLE (gVarStorageList); // // HII database lock. // EFI_LOCK mHiiDatabaseLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_NOTIFY); /** This function generates a HII_DATABASE_RECORD node and adds into hii database. This is a internal function. @param Private hii database private structure @param DatabaseNode HII_DATABASE_RECORD node which is used to store a package list @retval EFI_SUCCESS A database record is generated successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new database contents. @retval EFI_INVALID_PARAMETER Private is NULL or DatabaseRecord is NULL. **/ EFI_STATUS GenerateHiiDatabaseRecord ( IN HII_DATABASE_PRIVATE_DATA *Private, OUT HII_DATABASE_RECORD **DatabaseNode ) { HII_DATABASE_RECORD *DatabaseRecord; HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; HII_HANDLE *HiiHandle; if (Private == NULL || DatabaseNode == NULL) { return EFI_INVALID_PARAMETER; } DatabaseRecord = (HII_DATABASE_RECORD *) AllocateZeroPool (sizeof (HII_DATABASE_RECORD)); if (DatabaseRecord == NULL) { return EFI_OUT_OF_RESOURCES; } DatabaseRecord->Signature = HII_DATABASE_RECORD_SIGNATURE; DatabaseRecord->PackageList = AllocateZeroPool (sizeof (HII_DATABASE_PACKAGE_LIST_INSTANCE)); if (DatabaseRecord->PackageList == NULL) { FreePool (DatabaseRecord); return EFI_OUT_OF_RESOURCES; } PackageList = DatabaseRecord->PackageList; InitializeListHead (&PackageList->GuidPkgHdr); InitializeListHead (&PackageList->FormPkgHdr); InitializeListHead (&PackageList->KeyboardLayoutHdr); InitializeListHead (&PackageList->StringPkgHdr); InitializeListHead (&PackageList->FontPkgHdr); InitializeListHead (&PackageList->SimpleFontPkgHdr); PackageList->ImagePkg = NULL; PackageList->DevicePathPkg = NULL; // // Create a new hii handle // HiiHandle = (HII_HANDLE *) AllocateZeroPool (sizeof (HII_HANDLE)); if (HiiHandle == NULL) { FreePool (DatabaseRecord->PackageList); FreePool (DatabaseRecord); return EFI_OUT_OF_RESOURCES; } HiiHandle->Signature = HII_HANDLE_SIGNATURE; // // Backup the number of Hii handles // Private->HiiHandleCount++; HiiHandle->Key = (UINTN) Private->HiiHandleCount; // // Insert the handle to hii handle list of the whole database. // InsertTailList (&Private->HiiHandleList, &HiiHandle->Handle); DatabaseRecord->Handle = (EFI_HII_HANDLE) HiiHandle; // // Insert the Package List node to Package List link of the whole database. // InsertTailList (&Private->DatabaseList, &DatabaseRecord->DatabaseEntry); *DatabaseNode = DatabaseRecord; return EFI_SUCCESS; } /** This function checks whether a handle is a valid EFI_HII_HANDLE This is a internal function. @param Handle Pointer to a EFI_HII_HANDLE @retval TRUE Valid @retval FALSE Invalid **/ BOOLEAN IsHiiHandleValid ( EFI_HII_HANDLE Handle ) { HII_HANDLE *HiiHandle; HiiHandle = (HII_HANDLE *) Handle; if (HiiHandle == NULL) { return FALSE; } if (HiiHandle->Signature != HII_HANDLE_SIGNATURE) { return FALSE; } return TRUE; } /** This function invokes the matching registered function. This is a internal function. @param Private HII Database driver private structure. @param NotifyType The type of change concerning the database. @param PackageInstance Points to the package referred to by the notification. @param PackageType Package type @param Handle The handle of the package list which contains the specified package. @retval EFI_SUCCESS Already checked all registered function and invoked if matched. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS InvokeRegisteredFunction ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN VOID *PackageInstance, IN UINT8 PackageType, IN EFI_HII_HANDLE Handle ) { HII_DATABASE_NOTIFY *Notify; LIST_ENTRY *Link; EFI_HII_PACKAGE_HEADER *Package; UINT8 *Buffer; UINT32 BufferSize; UINT32 HeaderSize; UINT32 ImageBlockSize; UINT32 PaletteInfoSize; if (Private == NULL || (NotifyType & 0xF) == 0 || PackageInstance == NULL) { return EFI_INVALID_PARAMETER; } if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) { return EFI_INVALID_PARAMETER; } if (!IsHiiHandleValid (Handle)) { return EFI_INVALID_PARAMETER; } Buffer = NULL; Package = NULL; // // Convert the incoming package from hii database storage format to UEFI // storage format. e.g. HII_GUID_PACKAGE_INSTANCE to EFI_HII_GUID_PACKAGE_HDR. // switch (PackageType) { case EFI_HII_PACKAGE_TYPE_GUID: Package = (EFI_HII_PACKAGE_HEADER *) (((HII_GUID_PACKAGE_INSTANCE *) PackageInstance)->GuidPkg); break; case EFI_HII_PACKAGE_FORMS: BufferSize = ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr.Length; Buffer = (UINT8 *) AllocateZeroPool (BufferSize); ASSERT (Buffer != NULL); CopyMem ( Buffer, &((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->FormPkgHdr, sizeof (EFI_HII_PACKAGE_HEADER) ); CopyMem ( Buffer + sizeof (EFI_HII_PACKAGE_HEADER), ((HII_IFR_PACKAGE_INSTANCE *) PackageInstance)->IfrData, BufferSize - sizeof (EFI_HII_PACKAGE_HEADER) ); Package = (EFI_HII_PACKAGE_HEADER *) Buffer; break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: Package = (EFI_HII_PACKAGE_HEADER *) (((HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *) PackageInstance)->KeyboardPkg); break; case EFI_HII_PACKAGE_STRINGS: BufferSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->Header.Length; HeaderSize = ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr->HdrSize; Buffer = (UINT8 *) AllocateZeroPool (BufferSize); ASSERT (Buffer != NULL); CopyMem ( Buffer, ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringPkgHdr, HeaderSize ); CopyMem ( Buffer + HeaderSize, ((HII_STRING_PACKAGE_INSTANCE *) PackageInstance)->StringBlock, BufferSize - HeaderSize ); Package = (EFI_HII_PACKAGE_HEADER *) Buffer; break; case EFI_HII_PACKAGE_FONTS: BufferSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->Header.Length; HeaderSize = ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr->HdrSize; Buffer = (UINT8 *) AllocateZeroPool (BufferSize); ASSERT (Buffer != NULL); CopyMem ( Buffer, ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->FontPkgHdr, HeaderSize ); CopyMem ( Buffer + HeaderSize, ((HII_FONT_PACKAGE_INSTANCE *) PackageInstance)->GlyphBlock, BufferSize - HeaderSize ); Package = (EFI_HII_PACKAGE_HEADER *) Buffer; break; case EFI_HII_PACKAGE_IMAGES: BufferSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr.Header.Length; HeaderSize = sizeof (EFI_HII_IMAGE_PACKAGE_HDR); Buffer = (UINT8 *) AllocateZeroPool (BufferSize); ASSERT (Buffer != NULL); CopyMem ( Buffer, &((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImagePkgHdr, HeaderSize ); CopyMem ( Buffer + sizeof (EFI_HII_PACKAGE_HEADER), &HeaderSize, sizeof (UINT32) ); ImageBlockSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlockSize; if (ImageBlockSize != 0) { CopyMem ( Buffer + HeaderSize, ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->ImageBlock, ImageBlockSize ); } PaletteInfoSize = ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteInfoSize; if (PaletteInfoSize != 0) { CopyMem ( Buffer + HeaderSize + ImageBlockSize, ((HII_IMAGE_PACKAGE_INSTANCE *) PackageInstance)->PaletteBlock, PaletteInfoSize ); HeaderSize += ImageBlockSize; CopyMem ( Buffer + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT32), &HeaderSize, sizeof (UINT32) ); } Package = (EFI_HII_PACKAGE_HEADER *) Buffer; break; case EFI_HII_PACKAGE_SIMPLE_FONTS: BufferSize = ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr->Header.Length; Buffer = (UINT8 *) AllocateZeroPool (BufferSize); ASSERT (Buffer != NULL); CopyMem ( Buffer, ((HII_SIMPLE_FONT_PACKAGE_INSTANCE *) PackageInstance)->SimpleFontPkgHdr, BufferSize ); Package = (EFI_HII_PACKAGE_HEADER *) Buffer; break; case EFI_HII_PACKAGE_DEVICE_PATH: Package = (EFI_HII_PACKAGE_HEADER *) PackageInstance; break; default: return EFI_INVALID_PARAMETER; } for (Link = Private->DatabaseNotifyList.ForwardLink; Link != &Private->DatabaseNotifyList; Link = Link->ForwardLink ) { Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE); if (Notify->NotifyType == NotifyType && Notify->PackageType == PackageType) { // // Check in case PackageGuid is not NULL when Package is GUID package // if (PackageType != EFI_HII_PACKAGE_TYPE_GUID) { Notify->PackageGuid = NULL; } // // Status of Registered Function is unknown so did not check it // Notify->PackageNotifyFn ( Notify->PackageType, Notify->PackageGuid, Package, Handle, NotifyType ); } } if (Buffer != NULL) { FreePool (Buffer); } return EFI_SUCCESS; } /** This function insert a GUID package to a package list node. This is a internal function. @param PackageHdr Pointer to a buffer stored with GUID package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created GUID package @retval EFI_SUCCESS Guid Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Guid package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. **/ EFI_STATUS InsertGuidPackage ( IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_GUID_PACKAGE_INSTANCE **Package ) { HII_GUID_PACKAGE_INSTANCE *GuidPackage; EFI_HII_PACKAGE_HEADER PackageHeader; if (PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); // // Create a GUID package node // GuidPackage = (HII_GUID_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_GUID_PACKAGE_INSTANCE)); if (GuidPackage == NULL) { return EFI_OUT_OF_RESOURCES; } GuidPackage->GuidPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length); if (GuidPackage->GuidPkg == NULL) { FreePool (GuidPackage); return EFI_OUT_OF_RESOURCES; } GuidPackage->Signature = HII_GUID_PACKAGE_SIGNATURE; CopyMem (GuidPackage->GuidPkg, PackageHdr, PackageHeader.Length); InsertTailList (&PackageList->GuidPkgHdr, &GuidPackage->GuidEntry); *Package = GuidPackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += PackageHeader.Length; } return EFI_SUCCESS; } /** This function exports GUID packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Guid Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportGuidPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { HII_GUID_PACKAGE_INSTANCE *GuidPackage; LIST_ENTRY *Link; UINTN PackageLength; EFI_HII_PACKAGE_HEADER PackageHeader; EFI_STATUS Status; if (PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; for (Link = PackageList->GuidPkgHdr.ForwardLink; Link != &PackageList->GuidPkgHdr; Link = Link->ForwardLink) { GuidPackage = CR (Link, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE); CopyMem (&PackageHeader, GuidPackage->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER)); PackageLength += PackageHeader.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) GuidPackage, EFI_HII_PACKAGE_TYPE_GUID, Handle ); ASSERT_EFI_ERROR (Status); CopyMem (Buffer, GuidPackage->GuidPkg, PackageHeader.Length); Buffer = (UINT8 *) Buffer + PackageHeader.Length; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all GUID packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed GUID packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS GUID Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveGuidPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_GUID_PACKAGE_INSTANCE *Package; EFI_STATUS Status; EFI_HII_PACKAGE_HEADER PackageHeader; ListHead = &PackageList->GuidPkgHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_TYPE_GUID, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->GuidEntry); CopyMem (&PackageHeader, Package->GuidPkg, sizeof (EFI_HII_PACKAGE_HEADER)); PackageList->PackageListHdr.PackageLength -= PackageHeader.Length; FreePool (Package->GuidPkg); FreePool (Package); } return EFI_SUCCESS; } /** Check the input question related to EFI variable @param IfrQuestionHdr Point to Question header @param EfiVarStoreList Point to EFI VarStore List @param EfiVarStoreNumber The number of EFI VarStore @retval Index The index of the found EFI varstore in EFI varstore list EfiVarStoreNumber will return if no EFI varstore is found. **/ UINTN IsEfiVarStoreQuestion ( EFI_IFR_QUESTION_HEADER *IfrQuestionHdr, EFI_IFR_VARSTORE_EFI **EfiVarStoreList, UINTN EfiVarStoreNumber ) { UINTN Index; for (Index = 0; Index < EfiVarStoreNumber; Index ++) { if (IfrQuestionHdr->VarStoreId == EfiVarStoreList[Index]->VarStoreId) { return Index; } } return EfiVarStoreNumber; } /** Find the matched variable from the input variable storage. @param[in] VariableStorage Point to the variable storage header. @param[in] VarGuid A unique identifier for the variable. @param[in] VarAttribute The attributes bitmask for the variable. @param[in] VarName A Null-terminated ascii string that is the name of the variable. @return Pointer to the matched variable header or NULL if not found. **/ VARIABLE_HEADER * FindVariableData ( IN VARIABLE_STORE_HEADER *VariableStorage, IN EFI_GUID *VarGuid, IN UINT32 VarAttribute, IN CHAR16 *VarName ) { VARIABLE_HEADER *VariableHeader; VARIABLE_HEADER *VariableEnd; VariableEnd = (VARIABLE_HEADER *) ((UINT8 *) VariableStorage + VariableStorage->Size); VariableHeader = (VARIABLE_HEADER *) (VariableStorage + 1); VariableHeader = (VARIABLE_HEADER *) HEADER_ALIGN (VariableHeader); while (VariableHeader < VariableEnd) { if (CompareGuid (&VariableHeader->VendorGuid, VarGuid) && VariableHeader->Attributes == VarAttribute && StrCmp (VarName, (CHAR16 *) (VariableHeader + 1)) == 0) { return VariableHeader; } VariableHeader = (VARIABLE_HEADER *) ((UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + VariableHeader->DataSize); VariableHeader = (VARIABLE_HEADER *) HEADER_ALIGN (VariableHeader); } return NULL; } /** Find question default value from PcdNvStoreDefaultValueBuffer @param DefaultId Default store ID @param EfiVarStore Point to EFI VarStore header @param IfrQuestionHdr Point to Question header @param ValueBuffer Point to Buffer includes the found default setting @param Width Width of the default value @param BitFieldQuestion Whether the Question is stored in Bit field. @retval EFI_SUCCESS Question default value is found. @retval EFI_NOT_FOUND Question default value is not found. **/ EFI_STATUS FindQuestionDefaultSetting ( IN UINT16 DefaultId, IN EFI_IFR_VARSTORE_EFI *EfiVarStore, IN EFI_IFR_QUESTION_HEADER *IfrQuestionHdr, OUT VOID *ValueBuffer, IN UINTN Width, IN BOOLEAN BitFieldQuestion ) { VARIABLE_HEADER *VariableHeader; VARIABLE_STORE_HEADER *VariableStorage; LIST_ENTRY *Link; VARSTORAGE_DEFAULT_DATA *Entry; VARIABLE_STORE_HEADER *NvStoreBuffer; UINT8 *DataBuffer; UINT8 *BufferEnd; BOOLEAN IsFound; UINTN Index; UINT32 BufferValue; UINT32 BitFieldVal; UINTN BitOffset; UINTN ByteOffset; UINTN BitWidth; UINTN StartBit; UINTN EndBit; PCD_DEFAULT_DATA *DataHeader; PCD_DEFAULT_INFO *DefaultInfo; PCD_DATA_DELTA *DeltaData; if (gSkuId == 0xFFFFFFFFFFFFFFFF) { gSkuId = LibPcdGetSku (); } // // Find the DefaultId setting from the full DefaultSetting // VariableStorage = NULL; Link = gVarStorageList.ForwardLink; while (Link != &gVarStorageList) { Entry = BASE_CR (Link, VARSTORAGE_DEFAULT_DATA, Entry); if (Entry->DefaultId == DefaultId) { VariableStorage = Entry->VariableStorage; break; } Link = Link->ForwardLink; } if (Link == &gVarStorageList) { DataBuffer = (UINT8 *) PcdGetPtr (PcdNvStoreDefaultValueBuffer); gNvDefaultStoreSize = ((PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)DataBuffer)->Length; // // The first section data includes NV storage default setting. // DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)); NvStoreBuffer = (VARIABLE_STORE_HEADER *) ((UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize); VariableStorage = AllocatePool (NvStoreBuffer->Size); ASSERT (VariableStorage != NULL); CopyMem (VariableStorage, NvStoreBuffer, NvStoreBuffer->Size); // // Find the matched SkuId and DefaultId in the first section // IsFound = FALSE; DefaultInfo = &(DataHeader->DefaultInfo[0]); BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize; while ((UINT8 *) DefaultInfo < BufferEnd) { if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == gSkuId) { IsFound = TRUE; break; } DefaultInfo ++; } // // Find the matched SkuId and DefaultId in the remaining section // Index = sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER) + ((DataHeader->DataSize + 7) & (~7)); DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index); while (!IsFound && Index < gNvDefaultStoreSize && DataHeader->DataSize != 0xFFFF) { DefaultInfo = &(DataHeader->DefaultInfo[0]); BufferEnd = (UINT8 *) DataHeader + sizeof (DataHeader->DataSize) + DataHeader->HeaderSize; while ((UINT8 *) DefaultInfo < BufferEnd) { if (DefaultInfo->DefaultId == DefaultId && DefaultInfo->SkuId == gSkuId) { IsFound = TRUE; break; } DefaultInfo ++; } if (IsFound) { DeltaData = (PCD_DATA_DELTA *) BufferEnd; BufferEnd = (UINT8 *) DataHeader + DataHeader->DataSize; while ((UINT8 *) DeltaData < BufferEnd) { *((UINT8 *) VariableStorage + DeltaData->Offset) = (UINT8) DeltaData->Value; DeltaData ++; } break; } Index = (Index + DataHeader->DataSize + 7) & (~7); DataHeader = (PCD_DEFAULT_DATA *) (DataBuffer + Index); } // // Cache the found result in VarStorageList // if (!IsFound) { FreePool (VariableStorage); VariableStorage = NULL; } Entry = AllocatePool (sizeof (VARSTORAGE_DEFAULT_DATA)); if (Entry != NULL) { Entry->DefaultId = DefaultId; Entry->VariableStorage = VariableStorage; InsertTailList (&gVarStorageList, &Entry->Entry); } else if (VariableStorage != NULL) { FreePool (VariableStorage); VariableStorage = NULL; } } // // The matched variable storage is not found. // if (VariableStorage == NULL) { return EFI_NOT_FOUND; } // // Find the question default value from the variable storage // VariableHeader = FindVariableData (VariableStorage, &EfiVarStore->Guid, EfiVarStore->Attributes, (CHAR16 *) EfiVarStore->Name); if (VariableHeader == NULL) { return EFI_NOT_FOUND; } StartBit = 0; EndBit = 0; ByteOffset = IfrQuestionHdr->VarStoreInfo.VarOffset; if (BitFieldQuestion) { BitOffset = IfrQuestionHdr->VarStoreInfo.VarOffset; ByteOffset = BitOffset / 8; BitWidth = Width; StartBit = BitOffset % 8; EndBit = StartBit + BitWidth - 1; Width = EndBit / 8 + 1; } if (VariableHeader->DataSize < ByteOffset + Width) { return EFI_INVALID_PARAMETER; } // // Copy the question value // if (ValueBuffer != NULL) { if (BitFieldQuestion) { CopyMem (&BufferValue, (UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + ByteOffset, Width); BitFieldVal = BitFieldRead32 (BufferValue, StartBit, EndBit); CopyMem (ValueBuffer, &BitFieldVal, Width); } else { CopyMem (ValueBuffer, (UINT8 *) VariableHeader + sizeof (VARIABLE_HEADER) + VariableHeader->NameSize + IfrQuestionHdr->VarStoreInfo.VarOffset, Width); } } return EFI_SUCCESS; } /** Update IFR default setting in Form Package. @param FormPackage Form Package to be updated **/ VOID UpdateDefaultSettingInFormPackage ( HII_IFR_PACKAGE_INSTANCE *FormPackage ) { UINTN IfrOffset; UINTN PackageLength; EFI_IFR_VARSTORE_EFI *IfrEfiVarStore; EFI_IFR_OP_HEADER *IfrOpHdr; EFI_IFR_ONE_OF_OPTION *IfrOneOfOption; UINT8 IfrQuestionType; UINT8 IfrScope; EFI_IFR_QUESTION_HEADER *IfrQuestionHdr; EFI_IFR_VARSTORE_EFI **EfiVarStoreList; UINTN EfiVarStoreMaxNum; UINTN EfiVarStoreNumber; UINT16 *DefaultIdList; UINTN DefaultIdNumber; UINTN DefaultIdMaxNum; UINTN Index; UINTN EfiVarStoreIndex; EFI_IFR_TYPE_VALUE IfrValue; EFI_IFR_TYPE_VALUE IfrManufactValue; BOOLEAN StandardDefaultIsSet; BOOLEAN ManufactDefaultIsSet; EFI_IFR_CHECKBOX *IfrCheckBox; EFI_STATUS Status; EFI_IFR_DEFAULT *IfrDefault; UINTN Width; EFI_IFR_QUESTION_HEADER VarStoreQuestionHeader; BOOLEAN QuestionReferBitField; // // If no default setting, do nothing // if (gNvDefaultStoreSize == 0) { gNvDefaultStoreSize = PcdGetSize (PcdNvStoreDefaultValueBuffer); } if (gNvDefaultStoreSize < sizeof (PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) { return; } ZeroMem (&VarStoreQuestionHeader, sizeof (VarStoreQuestionHeader)); PackageLength = FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER); Width = 0; IfrOffset = 0; IfrScope = 0; IfrOpHdr = (EFI_IFR_OP_HEADER *) FormPackage->IfrData; IfrQuestionHdr = NULL; IfrQuestionType = 0; EfiVarStoreMaxNum = 0; EfiVarStoreNumber = 0; DefaultIdMaxNum = 0; DefaultIdNumber = 0; EfiVarStoreList = NULL; DefaultIdList = NULL; StandardDefaultIsSet = FALSE; ManufactDefaultIsSet = FALSE; QuestionReferBitField = FALSE; while (IfrOffset < PackageLength) { switch (IfrOpHdr->OpCode) { case EFI_IFR_VARSTORE_EFI_OP: if (EfiVarStoreNumber >= EfiVarStoreMaxNum) { // // Reallocate EFI VarStore Buffer // EfiVarStoreList = ReallocatePool (EfiVarStoreMaxNum * sizeof (UINTN), (EfiVarStoreMaxNum + BASE_NUMBER) * sizeof (UINTN), EfiVarStoreList); if (EfiVarStoreList == NULL) { goto Done; } EfiVarStoreMaxNum = EfiVarStoreMaxNum + BASE_NUMBER; } IfrEfiVarStore = (EFI_IFR_VARSTORE_EFI *) IfrOpHdr; // // Convert VarStore Name from ASCII string to Unicode string. // EfiVarStoreList [EfiVarStoreNumber] = AllocatePool (IfrEfiVarStore->Header.Length + AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name)); if (EfiVarStoreList [EfiVarStoreNumber] == NULL) { break; } CopyMem (EfiVarStoreList [EfiVarStoreNumber], IfrEfiVarStore, IfrEfiVarStore->Header.Length); AsciiStrToUnicodeStrS ((CHAR8 *)IfrEfiVarStore->Name, (CHAR16 *) &(EfiVarStoreList [EfiVarStoreNumber]->Name[0]), AsciiStrSize ((CHAR8 *)IfrEfiVarStore->Name) * sizeof (CHAR16)); Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_STANDARD, EfiVarStoreList[EfiVarStoreNumber], &VarStoreQuestionHeader, NULL, IfrEfiVarStore->Size, FALSE); if (!EFI_ERROR (Status)) { EfiVarStoreNumber ++; } else { FreePool (EfiVarStoreList [EfiVarStoreNumber]); EfiVarStoreList [EfiVarStoreNumber] = NULL; } break; case EFI_IFR_DEFAULTSTORE_OP: if (DefaultIdNumber >= DefaultIdMaxNum) { // // Reallocate DefaultIdNumber // DefaultIdList = ReallocatePool (DefaultIdMaxNum * sizeof (UINT16), (DefaultIdMaxNum + BASE_NUMBER) * sizeof (UINT16), DefaultIdList); if (DefaultIdList == NULL) { goto Done; } DefaultIdMaxNum = DefaultIdMaxNum + BASE_NUMBER; } DefaultIdList[DefaultIdNumber ++] = ((EFI_IFR_DEFAULTSTORE *) IfrOpHdr)->DefaultId; break; case EFI_IFR_FORM_OP: case EFI_IFR_FORM_MAP_OP: // // No EFI varstore is found and directly return. // if (EfiVarStoreNumber == 0 || DefaultIdNumber == 0) { goto Done; } break; case EFI_IFR_CHECKBOX_OP: IfrScope = IfrOpHdr->Scope; IfrQuestionType = IfrOpHdr->OpCode; IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1); IfrCheckBox = (EFI_IFR_CHECKBOX *) IfrOpHdr; EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber); Width = sizeof (BOOLEAN); if (EfiVarStoreIndex < EfiVarStoreNumber) { for (Index = 0; Index < DefaultIdNumber; Index ++) { if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_STANDARD) { Status = FindQuestionDefaultSetting (DefaultIdList[Index], EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, sizeof (BOOLEAN), QuestionReferBitField); if (!EFI_ERROR (Status)) { if (IfrValue.b) { IfrCheckBox->Flags = IfrCheckBox->Flags | EFI_IFR_CHECKBOX_DEFAULT; } else { IfrCheckBox->Flags = IfrCheckBox->Flags & (~EFI_IFR_CHECKBOX_DEFAULT); } } } else if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { Status = FindQuestionDefaultSetting (DefaultIdList[Index], EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, sizeof (BOOLEAN), QuestionReferBitField); if (!EFI_ERROR (Status)) { if (IfrValue.b) { IfrCheckBox->Flags = IfrCheckBox->Flags | EFI_IFR_CHECKBOX_DEFAULT_MFG; } else { IfrCheckBox->Flags = IfrCheckBox->Flags & (~EFI_IFR_CHECKBOX_DEFAULT_MFG); } } } } } break; case EFI_IFR_NUMERIC_OP: IfrScope = IfrOpHdr->Scope; IfrQuestionType = IfrOpHdr->OpCode; IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1); if (QuestionReferBitField) { Width = (UINTN) (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EDKII_IFR_NUMERIC_SIZE_BIT); } else { Width = (UINTN) ((UINT32) 1 << (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EFI_IFR_NUMERIC_SIZE)); } break; case EFI_IFR_ONE_OF_OP: IfrScope = IfrOpHdr->Scope; IfrQuestionType = IfrOpHdr->OpCode; IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1); if (QuestionReferBitField) { Width = (UINTN) (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EDKII_IFR_NUMERIC_SIZE_BIT); } else { Width = (UINTN) ((UINT32) 1 << (((EFI_IFR_ONE_OF *) IfrOpHdr)->Flags & EFI_IFR_NUMERIC_SIZE)); } EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber); StandardDefaultIsSet = FALSE; ManufactDefaultIsSet = FALSE; // // Find Default and Manufacturing default for OneOf question // if (EfiVarStoreIndex < EfiVarStoreNumber) { for (Index = 0; Index < DefaultIdNumber; Index ++) { if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_STANDARD) { Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_STANDARD, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrValue, Width, QuestionReferBitField); if (!EFI_ERROR (Status)) { StandardDefaultIsSet = TRUE; } } else if (DefaultIdList[Index] == EFI_HII_DEFAULT_CLASS_MANUFACTURING) { Status = FindQuestionDefaultSetting (EFI_HII_DEFAULT_CLASS_MANUFACTURING, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrManufactValue, Width, QuestionReferBitField); if (!EFI_ERROR (Status)) { ManufactDefaultIsSet = TRUE; } } } } break; case EFI_IFR_ORDERED_LIST_OP: IfrScope = IfrOpHdr->Scope; IfrQuestionType = IfrOpHdr->OpCode; IfrQuestionHdr = (EFI_IFR_QUESTION_HEADER *) (IfrOpHdr + 1); break; case EFI_IFR_ONE_OF_OPTION_OP: if (IfrQuestionHdr != NULL && IfrScope > 0) { IfrOneOfOption = (EFI_IFR_ONE_OF_OPTION *) IfrOpHdr; if (IfrQuestionType == EFI_IFR_ONE_OF_OP) { Width = (UINTN) ((UINT32) 1 << (IfrOneOfOption->Flags & EFI_IFR_NUMERIC_SIZE)); if (StandardDefaultIsSet) { if (CompareMem (&IfrOneOfOption->Value, &IfrValue, Width) == 0) { IfrOneOfOption->Flags |= EFI_IFR_OPTION_DEFAULT; } else { IfrOneOfOption->Flags &= ~EFI_IFR_OPTION_DEFAULT; } } if (ManufactDefaultIsSet) { if (CompareMem (&IfrOneOfOption->Value, &IfrManufactValue, Width) == 0) { IfrOneOfOption->Flags |= EFI_IFR_OPTION_DEFAULT_MFG; } else { IfrOneOfOption->Flags &= ~EFI_IFR_OPTION_DEFAULT_MFG; } } } } break; case EFI_IFR_DEFAULT_OP: if (IfrQuestionHdr != NULL && IfrScope > 0) { IfrDefault = (EFI_IFR_DEFAULT *) IfrOpHdr; // // Collect default value width // if (!QuestionReferBitField) { Width = 0; if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_8 || IfrDefault->Type == EFI_IFR_TYPE_BOOLEAN) { Width = 1; } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_16) { Width = 2; } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_32) { Width = 4; } else if (IfrDefault->Type == EFI_IFR_TYPE_NUM_SIZE_64) { Width = 8; } else if (IfrDefault->Type == EFI_IFR_TYPE_BUFFER) { Width = IfrDefault->Header.Length - OFFSET_OF (EFI_IFR_DEFAULT, Value); } } // // Update the default value // if (Width > 0) { EfiVarStoreIndex = IsEfiVarStoreQuestion (IfrQuestionHdr, EfiVarStoreList, EfiVarStoreNumber); if (EfiVarStoreIndex < EfiVarStoreNumber) { Status = FindQuestionDefaultSetting (IfrDefault->DefaultId, EfiVarStoreList[EfiVarStoreIndex], IfrQuestionHdr, &IfrDefault->Value, Width, QuestionReferBitField); } } } break; case EFI_IFR_END_OP: if (IfrQuestionHdr != NULL) { if (IfrScope > 0) { IfrScope --; } if (IfrScope == 0) { IfrQuestionHdr = NULL; QuestionReferBitField = FALSE; } } break; case EFI_IFR_GUID_OP: if (CompareGuid ((EFI_GUID *)((UINT8 *)IfrOpHdr + sizeof (EFI_IFR_OP_HEADER)), &gEdkiiIfrBitVarstoreGuid)) { QuestionReferBitField = TRUE; } break; default: break; } IfrOffset = IfrOffset + IfrOpHdr->Length; IfrOpHdr = (EFI_IFR_OP_HEADER *) ((UINT8 *) IfrOpHdr + IfrOpHdr->Length); if (IfrScope > 0) { IfrScope += IfrOpHdr->Scope; } } Done: if (EfiVarStoreList != NULL) { for (Index = 0; Index < EfiVarStoreNumber; Index ++) { FreePool (EfiVarStoreList [Index]); } } return; } /** This function insert a Form package to a package list node. This is a internal function. @param PackageHdr Pointer to a buffer stored with Form package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created Form package @retval EFI_SUCCESS Form Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Form package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. **/ EFI_STATUS InsertFormPackage ( IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_IFR_PACKAGE_INSTANCE **Package ) { HII_IFR_PACKAGE_INSTANCE *FormPackage; EFI_HII_PACKAGE_HEADER PackageHeader; if (PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } // // Get the length of the package, including package header itself // CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); // // Create a Form package node // FormPackage = (HII_IFR_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IFR_PACKAGE_INSTANCE)); if (FormPackage == NULL) { return EFI_OUT_OF_RESOURCES; } FormPackage->IfrData = (UINT8 *) AllocateZeroPool (PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER)); if (FormPackage->IfrData == NULL) { FreePool (FormPackage); return EFI_OUT_OF_RESOURCES; } FormPackage->Signature = HII_IFR_PACKAGE_SIGNATURE; // // Copy Package Header // CopyMem (&FormPackage->FormPkgHdr, &PackageHeader, sizeof (EFI_HII_PACKAGE_HEADER)); // // Copy Ifr contents // CopyMem ( FormPackage->IfrData, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), PackageHeader.Length - sizeof (EFI_HII_PACKAGE_HEADER) ); InsertTailList (&PackageList->FormPkgHdr, &FormPackage->IfrEntry); *Package = FormPackage; // // Update FormPackage with the default setting // UpdateDefaultSettingInFormPackage (FormPackage); if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += FormPackage->FormPkgHdr.Length; } return EFI_SUCCESS; } /** This function exports Form packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Form Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportFormPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { HII_IFR_PACKAGE_INSTANCE *FormPackage; UINTN PackageLength; LIST_ENTRY *Link; EFI_STATUS Status; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; // // Export Form packages. // for (Link = PackageList->FormPkgHdr.ForwardLink; Link != &PackageList->FormPkgHdr; Link = Link->ForwardLink) { FormPackage = CR (Link, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE); PackageLength += FormPackage->FormPkgHdr.Length; if ((Buffer != NULL) && (PackageLength + *ResultSize + UsedSize <= BufferSize)) { // // Invoke registered notification if exists // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) FormPackage, EFI_HII_PACKAGE_FORMS, Handle ); ASSERT_EFI_ERROR (Status); // // Copy the Form package content. // CopyMem (Buffer, (VOID *) (&FormPackage->FormPkgHdr), sizeof (EFI_HII_PACKAGE_HEADER)); Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_PACKAGE_HEADER); CopyMem ( Buffer, (VOID *) FormPackage->IfrData, FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER) ); Buffer = (UINT8 *) Buffer + FormPackage->FormPkgHdr.Length - sizeof (EFI_HII_PACKAGE_HEADER); } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all Form packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed Form packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS Form Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveFormPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_IFR_PACKAGE_INSTANCE *Package; EFI_STATUS Status; ListHead = &PackageList->FormPkgHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_IFR_PACKAGE_INSTANCE, IfrEntry, HII_IFR_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_FORMS, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->IfrEntry); PackageList->PackageListHdr.PackageLength -= Package->FormPkgHdr.Length; FreePool (Package->IfrData); FreePool (Package); // // If Hii runtime support feature is enabled, // will export Hii info for runtime use after ReadyToBoot event triggered. // If some driver add/update/remove packages from HiiDatabase after ReadyToBoot, // will need to export the content of HiiDatabase. // But if form packages removed, also need to export the ConfigResp string // if (gExportAfterReadyToBoot) { gExportConfigResp = TRUE; } } return EFI_SUCCESS; } /** This function insert a String package to a package list node. This is a internal function. @param Private Hii database private structure. @param PackageHdr Pointer to a buffer stored with String package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created String package @retval EFI_SUCCESS String Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new String package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. @retval EFI_UNSUPPORTED A string package with the same language already exists in current package list. **/ EFI_STATUS InsertStringPackage ( IN HII_DATABASE_PRIVATE_DATA *Private, IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_STRING_PACKAGE_INSTANCE **Package ) { HII_STRING_PACKAGE_INSTANCE *StringPackage; UINT32 HeaderSize; EFI_STATUS Status; EFI_HII_PACKAGE_HEADER PackageHeader; CHAR8 *Language; UINT32 LanguageSize; LIST_ENTRY *Link; if (Private == NULL || PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } if (Private->Signature != HII_DATABASE_PRIVATE_DATA_SIGNATURE) { return EFI_INVALID_PARAMETER; } CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32)); // // It is illegal to have two string packages with same language within one packagelist // since the stringid will be duplicate if so. Check it to avoid this potential issue. // LanguageSize = HeaderSize - sizeof (EFI_HII_STRING_PACKAGE_HDR) + sizeof (CHAR8); Language = (CHAR8 *) AllocateZeroPool (LanguageSize); if (Language == NULL) { return EFI_OUT_OF_RESOURCES; } AsciiStrCpyS (Language, LanguageSize / sizeof (CHAR8), (CHAR8 *) PackageHdr + HeaderSize - LanguageSize); for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) { StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); if (HiiCompareLanguage (Language, StringPackage->StringPkgHdr->Language)) { FreePool (Language); return EFI_UNSUPPORTED; } } FreePool (Language); // // Create a String package node // StringPackage = (HII_STRING_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_STRING_PACKAGE_INSTANCE)); if (StringPackage == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } StringPackage->StringPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) AllocateZeroPool (HeaderSize); if (StringPackage->StringPkgHdr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } StringPackage->StringBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize); if (StringPackage->StringBlock == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } StringPackage->Signature = HII_STRING_PACKAGE_SIGNATURE; StringPackage->FontId = 0; InitializeListHead (&StringPackage->FontInfoList); // // Copy the String package header. // CopyMem (StringPackage->StringPkgHdr, PackageHdr, HeaderSize); // // Copy the String blocks // CopyMem ( StringPackage->StringBlock, (UINT8 *) PackageHdr + HeaderSize, PackageHeader.Length - HeaderSize ); // // Collect all font block info // Status = FindStringBlock (Private, StringPackage, (EFI_STRING_ID) (-1), NULL, NULL, NULL, &StringPackage->MaxStringId, NULL); if (EFI_ERROR (Status)) { return Status; } // // Insert to String package array // InsertTailList (&PackageList->StringPkgHdr, &StringPackage->StringEntry); *Package = StringPackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += StringPackage->StringPkgHdr->Header.Length; } return EFI_SUCCESS; Error: if (StringPackage != NULL) { if (StringPackage->StringBlock != NULL) { FreePool (StringPackage->StringBlock); } if (StringPackage->StringPkgHdr != NULL) { FreePool (StringPackage->StringPkgHdr); } FreePool (StringPackage); } return Status; } /** Adjust all string packages in a single package list to have the same max string ID. @param PackageList Pointer to a package list which will be adjusted. @retval EFI_SUCCESS Adjust all string packages successfully. @retval others Can't adjust string packages. **/ EFI_STATUS AdjustStringPackage ( IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *Link; HII_STRING_PACKAGE_INSTANCE *StringPackage; UINT32 Skip2BlockSize; UINT32 OldBlockSize; UINT8 *StringBlock; UINT8 *BlockPtr; EFI_STRING_ID MaxStringId; UINT16 SkipCount; MaxStringId = 0; for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink ) { StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); if (MaxStringId < StringPackage->MaxStringId) { MaxStringId = StringPackage->MaxStringId; } } for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink ) { StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); if (StringPackage->MaxStringId < MaxStringId) { OldBlockSize = StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; // // Create SKIP2 EFI_HII_SIBT_SKIP2_BLOCKs to reserve the missing string IDs. // SkipCount = (UINT16) (MaxStringId - StringPackage->MaxStringId); Skip2BlockSize = (UINT32) sizeof (EFI_HII_SIBT_SKIP2_BLOCK); StringBlock = (UINT8 *) AllocateZeroPool (OldBlockSize + Skip2BlockSize); if (StringBlock == NULL) { return EFI_OUT_OF_RESOURCES; } // // Copy original string blocks, except the EFI_HII_SIBT_END. // CopyMem (StringBlock, StringPackage->StringBlock, OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK)); // // Create SKIP2 EFI_HII_SIBT_SKIP2_BLOCK blocks // BlockPtr = StringBlock + OldBlockSize - sizeof (EFI_HII_SIBT_END_BLOCK); *BlockPtr = EFI_HII_SIBT_SKIP2; CopyMem (BlockPtr + 1, &SkipCount, sizeof (UINT16)); BlockPtr += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); // // Append a EFI_HII_SIBT_END block to the end. // *BlockPtr = EFI_HII_SIBT_END; FreePool (StringPackage->StringBlock); StringPackage->StringBlock = StringBlock; StringPackage->StringPkgHdr->Header.Length += Skip2BlockSize; PackageList->PackageListHdr.PackageLength += Skip2BlockSize; StringPackage->MaxStringId = MaxStringId; } } return EFI_SUCCESS; } /** This function exports String packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS String Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportStringPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { LIST_ENTRY *Link; UINTN PackageLength; EFI_STATUS Status; HII_STRING_PACKAGE_INSTANCE *StringPackage; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; for (Link = PackageList->StringPkgHdr.ForwardLink; Link != &PackageList->StringPkgHdr; Link = Link->ForwardLink) { StringPackage = CR (Link, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE); PackageLength += StringPackage->StringPkgHdr->Header.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) StringPackage, EFI_HII_PACKAGE_STRINGS, Handle ); ASSERT_EFI_ERROR (Status); // // Copy String package header // CopyMem (Buffer, StringPackage->StringPkgHdr, StringPackage->StringPkgHdr->HdrSize); Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->HdrSize; // // Copy String blocks information // CopyMem ( Buffer, StringPackage->StringBlock, StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize ); Buffer = (UINT8 *) Buffer + StringPackage->StringPkgHdr->Header.Length - StringPackage->StringPkgHdr->HdrSize; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all String packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed String packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS String Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveStringPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_STRING_PACKAGE_INSTANCE *Package; HII_FONT_INFO *FontInfo; EFI_STATUS Status; ListHead = &PackageList->StringPkgHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_STRING_PACKAGE_INSTANCE, StringEntry, HII_STRING_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_STRINGS, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->StringEntry); PackageList->PackageListHdr.PackageLength -= Package->StringPkgHdr->Header.Length; FreePool (Package->StringBlock); FreePool (Package->StringPkgHdr); // // Delete font information // while (!IsListEmpty (&Package->FontInfoList)) { FontInfo = CR ( Package->FontInfoList.ForwardLink, HII_FONT_INFO, Entry, HII_FONT_INFO_SIGNATURE ); RemoveEntryList (&FontInfo->Entry); FreePool (FontInfo); } FreePool (Package); } return EFI_SUCCESS; } /** This function insert a Font package to a package list node. This is a internal function. @param Private Hii database private structure. @param PackageHdr Pointer to a buffer stored with Font package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created Font package @retval EFI_SUCCESS Font Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Font package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. @retval EFI_UNSUPPORTED A font package with same EFI_FONT_INFO already exists in current hii database. **/ EFI_STATUS InsertFontPackage ( IN HII_DATABASE_PRIVATE_DATA *Private, IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_FONT_PACKAGE_INSTANCE **Package ) { HII_FONT_PACKAGE_INSTANCE *FontPackage; EFI_HII_FONT_PACKAGE_HDR *FontPkgHdr; UINT32 HeaderSize; EFI_STATUS Status; EFI_HII_PACKAGE_HEADER PackageHeader; EFI_FONT_INFO *FontInfo; UINT32 FontInfoSize; HII_GLOBAL_FONT_INFO *GlobalFont; if (Private == NULL || PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); CopyMem (&HeaderSize, (UINT8 *) PackageHdr + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT32)); FontInfo = NULL; FontPackage = NULL; GlobalFont = NULL; // // It is illegal to have two font packages with same EFI_FONT_INFO within hii // database. EFI_FONT_INFO (FontName, FontSize, FontStyle) describes font's // attributes and identify a font uniquely. // FontPkgHdr = (EFI_HII_FONT_PACKAGE_HDR *) AllocateZeroPool (HeaderSize); if (FontPkgHdr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } CopyMem (FontPkgHdr, PackageHdr, HeaderSize); FontInfoSize = sizeof (EFI_FONT_INFO) + HeaderSize - sizeof (EFI_HII_FONT_PACKAGE_HDR); FontInfo = (EFI_FONT_INFO *) AllocateZeroPool (FontInfoSize); if (FontInfo == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } FontInfo->FontStyle = FontPkgHdr->FontStyle; FontInfo->FontSize = FontPkgHdr->Cell.Height; StrCpyS (FontInfo->FontName, (FontInfoSize - OFFSET_OF(EFI_FONT_INFO,FontName)) / sizeof (CHAR16), FontPkgHdr->FontFamily); if (IsFontInfoExisted (Private, FontInfo, NULL, NULL, NULL)) { Status = EFI_UNSUPPORTED; goto Error; } // // Create a Font package node // FontPackage = (HII_FONT_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_FONT_PACKAGE_INSTANCE)); if (FontPackage == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } FontPackage->Signature = HII_FONT_PACKAGE_SIGNATURE; FontPackage->FontPkgHdr = FontPkgHdr; InitializeListHead (&FontPackage->GlyphInfoList); FontPackage->GlyphBlock = (UINT8 *) AllocateZeroPool (PackageHeader.Length - HeaderSize); if (FontPackage->GlyphBlock == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } CopyMem (FontPackage->GlyphBlock, (UINT8 *) PackageHdr + HeaderSize, PackageHeader.Length - HeaderSize); // // Collect all default character cell information and backup in GlyphInfoList. // Status = FindGlyphBlock (FontPackage, (CHAR16) (-1), NULL, NULL, NULL); if (EFI_ERROR (Status)) { goto Error; } // // This font package describes an unique EFI_FONT_INFO. Backup it in global // font info list. // GlobalFont = (HII_GLOBAL_FONT_INFO *) AllocateZeroPool (sizeof (HII_GLOBAL_FONT_INFO)); if (GlobalFont == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } GlobalFont->Signature = HII_GLOBAL_FONT_INFO_SIGNATURE; GlobalFont->FontPackage = FontPackage; GlobalFont->FontInfoSize = FontInfoSize; GlobalFont->FontInfo = FontInfo; InsertTailList (&Private->FontInfoList, &GlobalFont->Entry); // // Insert this font package to Font package array // InsertTailList (&PackageList->FontPkgHdr, &FontPackage->FontEntry); *Package = FontPackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += FontPackage->FontPkgHdr->Header.Length; } return EFI_SUCCESS; Error: if (FontPkgHdr != NULL) { FreePool (FontPkgHdr); } if (FontInfo != NULL) { FreePool (FontInfo); } if (FontPackage != NULL) { if (FontPackage->GlyphBlock != NULL) { FreePool (FontPackage->GlyphBlock); } FreePool (FontPackage); } if (GlobalFont != NULL) { FreePool (GlobalFont); } return Status; } /** This function exports Font packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Font Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportFontPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { LIST_ENTRY *Link; UINTN PackageLength; EFI_STATUS Status; HII_FONT_PACKAGE_INSTANCE *Package; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; for (Link = PackageList->FontPkgHdr.ForwardLink; Link != &PackageList->FontPkgHdr; Link = Link->ForwardLink) { Package = CR (Link, HII_FONT_PACKAGE_INSTANCE, FontEntry, HII_FONT_PACKAGE_SIGNATURE); PackageLength += Package->FontPkgHdr->Header.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) Package, EFI_HII_PACKAGE_FONTS, Handle ); ASSERT_EFI_ERROR (Status); // // Copy Font package header // CopyMem (Buffer, Package->FontPkgHdr, Package->FontPkgHdr->HdrSize); Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->HdrSize; // // Copy Glyph blocks information // CopyMem ( Buffer, Package->GlyphBlock, Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize ); Buffer = (UINT8 *) Buffer + Package->FontPkgHdr->Header.Length - Package->FontPkgHdr->HdrSize; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all Font packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed Font packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS Font Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveFontPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_FONT_PACKAGE_INSTANCE *Package; EFI_STATUS Status; HII_GLYPH_INFO *GlyphInfo; LIST_ENTRY *Link; HII_GLOBAL_FONT_INFO *GlobalFont; ListHead = &PackageList->FontPkgHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_FONT_PACKAGE_INSTANCE, FontEntry, HII_FONT_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_FONTS, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->FontEntry); PackageList->PackageListHdr.PackageLength -= Package->FontPkgHdr->Header.Length; if (Package->GlyphBlock != NULL) { FreePool (Package->GlyphBlock); } FreePool (Package->FontPkgHdr); // // Delete default character cell information // while (!IsListEmpty (&Package->GlyphInfoList)) { GlyphInfo = CR ( Package->GlyphInfoList.ForwardLink, HII_GLYPH_INFO, Entry, HII_GLYPH_INFO_SIGNATURE ); RemoveEntryList (&GlyphInfo->Entry); FreePool (GlyphInfo); } // // Remove corresponding global font info // for (Link = Private->FontInfoList.ForwardLink; Link != &Private->FontInfoList; Link = Link->ForwardLink) { GlobalFont = CR (Link, HII_GLOBAL_FONT_INFO, Entry, HII_GLOBAL_FONT_INFO_SIGNATURE); if (GlobalFont->FontPackage == Package) { RemoveEntryList (&GlobalFont->Entry); FreePool (GlobalFont->FontInfo); FreePool (GlobalFont); break; } } FreePool (Package); } return EFI_SUCCESS; } /** This function insert a Image package to a package list node. This is a internal function. @param PackageHdr Pointer to a buffer stored with Image package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created Image package @retval EFI_SUCCESS Image Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Image package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. **/ EFI_STATUS InsertImagePackage ( IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_IMAGE_PACKAGE_INSTANCE **Package ) { HII_IMAGE_PACKAGE_INSTANCE *ImagePackage; UINT32 PaletteSize; UINT32 ImageSize; UINT16 Index; EFI_HII_IMAGE_PALETTE_INFO_HEADER *PaletteHdr; EFI_HII_IMAGE_PALETTE_INFO *PaletteInfo; UINT32 PaletteInfoOffset; UINT32 ImageInfoOffset; UINT16 CurrentSize; if (PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } // // Less than one image package is allowed in one package list. // if (PackageList->ImagePkg != NULL) { return EFI_INVALID_PARAMETER; } // // Create a Image package node // ImagePackage = (HII_IMAGE_PACKAGE_INSTANCE *) AllocateZeroPool (sizeof (HII_IMAGE_PACKAGE_INSTANCE)); if (ImagePackage == NULL) { return EFI_OUT_OF_RESOURCES; } // // Copy the Image package header. // CopyMem (&ImagePackage->ImagePkgHdr, PackageHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR)); PaletteInfoOffset = ImagePackage->ImagePkgHdr.PaletteInfoOffset; ImageInfoOffset = ImagePackage->ImagePkgHdr.ImageInfoOffset; // // If PaletteInfoOffset is zero, there are no palettes in this image package. // PaletteSize = 0; ImagePackage->PaletteBlock = NULL; if (PaletteInfoOffset != 0) { PaletteHdr = (EFI_HII_IMAGE_PALETTE_INFO_HEADER *) ((UINT8 *) PackageHdr + PaletteInfoOffset); PaletteSize = sizeof (EFI_HII_IMAGE_PALETTE_INFO_HEADER); PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteHdr + PaletteSize); for (Index = 0; Index < PaletteHdr->PaletteCount; Index++) { CopyMem (&CurrentSize, PaletteInfo, sizeof (UINT16)); CurrentSize += sizeof (UINT16); PaletteSize += (UINT32) CurrentSize; PaletteInfo = (EFI_HII_IMAGE_PALETTE_INFO *) ((UINT8 *) PaletteInfo + CurrentSize); } ImagePackage->PaletteBlock = (UINT8 *) AllocateZeroPool (PaletteSize); if (ImagePackage->PaletteBlock == NULL) { FreePool (ImagePackage); return EFI_OUT_OF_RESOURCES; } CopyMem ( ImagePackage->PaletteBlock, (UINT8 *) PackageHdr + PaletteInfoOffset, PaletteSize ); } // // If ImageInfoOffset is zero, there are no images in this package. // ImageSize = 0; ImagePackage->ImageBlock = NULL; if (ImageInfoOffset != 0) { ImageSize = ImagePackage->ImagePkgHdr.Header.Length - sizeof (EFI_HII_IMAGE_PACKAGE_HDR) - PaletteSize; ImagePackage->ImageBlock = AllocateZeroPool (ImageSize); if (ImagePackage->ImageBlock == NULL) { FreePool (ImagePackage->PaletteBlock); FreePool (ImagePackage); return EFI_OUT_OF_RESOURCES; } CopyMem ( ImagePackage->ImageBlock, (UINT8 *) PackageHdr + ImageInfoOffset, ImageSize ); } ImagePackage->ImageBlockSize = ImageSize; ImagePackage->PaletteInfoSize = PaletteSize; PackageList->ImagePkg = ImagePackage; *Package = ImagePackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += ImagePackage->ImagePkgHdr.Header.Length; } return EFI_SUCCESS; } /** This function exports Image packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Image Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportImagePackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { UINTN PackageLength; EFI_STATUS Status; HII_IMAGE_PACKAGE_INSTANCE *Package; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } Package = PackageList->ImagePkg; if (Package == NULL) { return EFI_SUCCESS; } PackageLength = Package->ImagePkgHdr.Header.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) Package, EFI_HII_PACKAGE_IMAGES, Handle ); ASSERT_EFI_ERROR (Status); ASSERT (Package->ImagePkgHdr.Header.Length == sizeof (EFI_HII_IMAGE_PACKAGE_HDR) + Package->ImageBlockSize + Package->PaletteInfoSize); // // Copy Image package header, // then justify the offset for image info and palette info in the header. // CopyMem (Buffer, &Package->ImagePkgHdr, sizeof (EFI_HII_IMAGE_PACKAGE_HDR)); Buffer = (UINT8 *) Buffer + sizeof (EFI_HII_IMAGE_PACKAGE_HDR); // // Copy Image blocks information // if (Package->ImageBlockSize != 0) { CopyMem (Buffer, Package->ImageBlock, Package->ImageBlockSize); Buffer = (UINT8 *) Buffer + Package->ImageBlockSize; } // // Copy Palette information // if (Package->PaletteInfoSize != 0) { CopyMem (Buffer, Package->PaletteBlock, Package->PaletteInfoSize); Buffer = (UINT8 *) Buffer + Package->PaletteInfoSize; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes Image package from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed Image packages. @param PackageList Package List which contains the to be removed Image package. @retval EFI_SUCCESS Image Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveImagePackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { HII_IMAGE_PACKAGE_INSTANCE *Package; EFI_STATUS Status; Package = PackageList->ImagePkg; // // Image package does not exist, return directly. // if (Package == NULL) { return EFI_SUCCESS; } Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_IMAGES, Handle ); if (EFI_ERROR (Status)) { return Status; } PackageList->PackageListHdr.PackageLength -= Package->ImagePkgHdr.Header.Length; FreePool (Package->ImageBlock); if (Package->PaletteBlock != NULL) { FreePool (Package->PaletteBlock); } FreePool (Package); PackageList->ImagePkg = NULL; return EFI_SUCCESS; } /** This function insert a Simple Font package to a package list node. This is a internal function. @param PackageHdr Pointer to a buffer stored with Simple Font package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created Simple Font package @retval EFI_SUCCESS Simple Font Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Simple Font package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. **/ EFI_STATUS InsertSimpleFontPackage ( IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_SIMPLE_FONT_PACKAGE_INSTANCE **Package ) { HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage; EFI_STATUS Status; EFI_HII_PACKAGE_HEADER Header; if (PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } // // Create a Simple Font package node // SimpleFontPackage = AllocateZeroPool (sizeof (HII_SIMPLE_FONT_PACKAGE_INSTANCE)); if (SimpleFontPackage == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } SimpleFontPackage->Signature = HII_S_FONT_PACKAGE_SIGNATURE; // // Copy the Simple Font package. // CopyMem (&Header, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); SimpleFontPackage->SimpleFontPkgHdr = AllocateZeroPool (Header.Length); if (SimpleFontPackage->SimpleFontPkgHdr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } CopyMem (SimpleFontPackage->SimpleFontPkgHdr, PackageHdr, Header.Length); // // Insert to Simple Font package array // InsertTailList (&PackageList->SimpleFontPkgHdr, &SimpleFontPackage->SimpleFontEntry); *Package = SimpleFontPackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += Header.Length; } return EFI_SUCCESS; Error: if (SimpleFontPackage != NULL) { if (SimpleFontPackage->SimpleFontPkgHdr != NULL) { FreePool (SimpleFontPackage->SimpleFontPkgHdr); } FreePool (SimpleFontPackage); } return Status; } /** This function exports SimpleFont packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS SimpleFont Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportSimpleFontPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { LIST_ENTRY *Link; UINTN PackageLength; EFI_STATUS Status; HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; for (Link = PackageList->SimpleFontPkgHdr.ForwardLink; Link != &PackageList->SimpleFontPkgHdr; Link = Link->ForwardLink) { Package = CR (Link, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE); PackageLength += Package->SimpleFontPkgHdr->Header.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) Package, EFI_HII_PACKAGE_SIMPLE_FONTS, Handle ); ASSERT_EFI_ERROR (Status); // // Copy SimpleFont package // CopyMem (Buffer, Package->SimpleFontPkgHdr, Package->SimpleFontPkgHdr->Header.Length); Buffer = (UINT8 *) Buffer + Package->SimpleFontPkgHdr->Header.Length; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all Simple Font packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed Simple Font packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS Simple Font Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveSimpleFontPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_SIMPLE_FONT_PACKAGE_INSTANCE *Package; EFI_STATUS Status; ListHead = &PackageList->SimpleFontPkgHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_SIMPLE_FONT_PACKAGE_INSTANCE, SimpleFontEntry, HII_S_FONT_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_SIMPLE_FONTS, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->SimpleFontEntry); PackageList->PackageListHdr.PackageLength -= Package->SimpleFontPkgHdr->Header.Length; FreePool (Package->SimpleFontPkgHdr); FreePool (Package); } return EFI_SUCCESS; } /** This function insert a Device path package to a package list node. This is a internal function. @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol instance @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @retval EFI_SUCCESS Device path Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Device path package. @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL. **/ EFI_STATUS InsertDevicePathPackage ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { UINT32 PackageLength; EFI_HII_PACKAGE_HEADER Header; if (DevicePath == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } // // Less than one device path package is allowed in one package list. // if (PackageList->DevicePathPkg != NULL) { return EFI_INVALID_PARAMETER; } PackageLength = (UINT32) GetDevicePathSize (DevicePath) + sizeof (EFI_HII_PACKAGE_HEADER); PackageList->DevicePathPkg = (UINT8 *) AllocateZeroPool (PackageLength); if (PackageList->DevicePathPkg == NULL) { return EFI_OUT_OF_RESOURCES; } Header.Length = PackageLength; Header.Type = EFI_HII_PACKAGE_DEVICE_PATH; CopyMem (PackageList->DevicePathPkg, &Header, sizeof (EFI_HII_PACKAGE_HEADER)); CopyMem ( PackageList->DevicePathPkg + sizeof (EFI_HII_PACKAGE_HEADER), DevicePath, PackageLength - sizeof (EFI_HII_PACKAGE_HEADER) ); // // Since Device Path package is created by NewPackageList, either NEW_PACK // or ADD_PACK should increase the length of package list. // PackageList->PackageListHdr.PackageLength += PackageLength; return EFI_SUCCESS; } /** This function exports device path package to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Device path Package is exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportDevicePathPackage ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { EFI_STATUS Status; UINT8 *Package; EFI_HII_PACKAGE_HEADER Header; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } Package = PackageList->DevicePathPkg; if (Package == NULL) { return EFI_SUCCESS; } CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER)); if (Header.Length + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (VOID *) Package, EFI_HII_PACKAGE_DEVICE_PATH, Handle ); ASSERT_EFI_ERROR (Status); // // Copy Device path package // CopyMem (Buffer, Package, Header.Length); } *ResultSize += Header.Length; return EFI_SUCCESS; } /** This function deletes Device Path package from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list. @param PackageList Package List which contains the to be removed Device Path package. @retval EFI_SUCCESS Device Path Package is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveDevicePathPackage ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { EFI_STATUS Status; UINT8 *Package; EFI_HII_PACKAGE_HEADER Header; Package = PackageList->DevicePathPkg; // // No device path, return directly. // if (Package == NULL) { return EFI_SUCCESS; } Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_DEVICE_PATH, Handle ); if (EFI_ERROR (Status)) { return Status; } CopyMem (&Header, Package, sizeof (EFI_HII_PACKAGE_HEADER)); PackageList->PackageListHdr.PackageLength -= Header.Length; FreePool (Package); PackageList->DevicePathPkg = NULL; return EFI_SUCCESS; } /** This function will insert a device path package to package list firstly then invoke notification functions if any. This is a internal function. @param Private Hii database private structure. @param NotifyType The type of change concerning the database. @param DevicePath Pointer to a EFI_DEVICE_PATH_PROTOCOL protocol instance @param DatabaseRecord Pointer to a database record contains a package list which will be inserted to. @retval EFI_SUCCESS Device path Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Device path package. @retval EFI_INVALID_PARAMETER DevicePath is NULL or PackageList is NULL. **/ EFI_STATUS AddDevicePathPackage ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN EFI_DEVICE_PATH_PROTOCOL *DevicePath, IN OUT HII_DATABASE_RECORD *DatabaseRecord ) { EFI_STATUS Status; if (DevicePath == NULL) { return EFI_SUCCESS; } ASSERT (Private != NULL); ASSERT (DatabaseRecord != NULL); // // Create a device path package and insert to packagelist // Status = InsertDevicePathPackage ( DevicePath, NotifyType, DatabaseRecord->PackageList ); if (EFI_ERROR (Status)) { return Status; } return InvokeRegisteredFunction ( Private, NotifyType, (VOID *) DatabaseRecord->PackageList->DevicePathPkg, EFI_HII_PACKAGE_DEVICE_PATH, DatabaseRecord->Handle ); } /** This function insert a Keyboard Layout package to a package list node. This is a internal function. @param PackageHdr Pointer to a buffer stored with Keyboard Layout package information. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list which will be inserted to. @param Package Created Keyboard Layout package @retval EFI_SUCCESS Keyboard Layout Package is inserted successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Keyboard Layout package. @retval EFI_INVALID_PARAMETER PackageHdr is NULL or PackageList is NULL. **/ EFI_STATUS InsertKeyboardLayoutPackage ( IN VOID *PackageHdr, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, OUT HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE **Package ) { HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage; EFI_HII_PACKAGE_HEADER PackageHeader; EFI_STATUS Status; if (PackageHdr == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } CopyMem (&PackageHeader, PackageHdr, sizeof (EFI_HII_PACKAGE_HEADER)); // // Create a Keyboard Layout package node // KeyboardLayoutPackage = AllocateZeroPool (sizeof (HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE)); if (KeyboardLayoutPackage == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } KeyboardLayoutPackage->Signature = HII_KB_LAYOUT_PACKAGE_SIGNATURE; KeyboardLayoutPackage->KeyboardPkg = (UINT8 *) AllocateZeroPool (PackageHeader.Length); if (KeyboardLayoutPackage->KeyboardPkg == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } CopyMem (KeyboardLayoutPackage->KeyboardPkg, PackageHdr, PackageHeader.Length); InsertTailList (&PackageList->KeyboardLayoutHdr, &KeyboardLayoutPackage->KeyboardEntry); *Package = KeyboardLayoutPackage; if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { PackageList->PackageListHdr.PackageLength += PackageHeader.Length; } return EFI_SUCCESS; Error: if (KeyboardLayoutPackage != NULL) { if (KeyboardLayoutPackage->KeyboardPkg != NULL) { FreePool (KeyboardLayoutPackage->KeyboardPkg); } FreePool (KeyboardLayoutPackage); } return Status; } /** This function exports Keyboard Layout packages to a buffer. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer be used. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @param ResultSize The size of the already exported content of this package list. @retval EFI_SUCCESS Keyboard Layout Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportKeyboardLayoutPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN UINTN UsedSize, IN UINTN BufferSize, IN OUT VOID *Buffer, IN OUT UINTN *ResultSize ) { LIST_ENTRY *Link; UINTN PackageLength; EFI_STATUS Status; HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package; EFI_HII_PACKAGE_HEADER PackageHeader; if (Private == NULL || PackageList == NULL || ResultSize == NULL) { return EFI_INVALID_PARAMETER; } if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } PackageLength = 0; Status = EFI_SUCCESS; for (Link = PackageList->KeyboardLayoutHdr.ForwardLink; Link != &PackageList->KeyboardLayoutHdr; Link = Link->ForwardLink) { Package = CR (Link, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE); CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER)); PackageLength += PackageHeader.Length; if (PackageLength + *ResultSize + UsedSize <= BufferSize) { // // Invoke registered notification function with EXPORT_PACK notify type // Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_EXPORT_PACK, (EFI_HII_PACKAGE_HEADER *) Package, EFI_HII_PACKAGE_KEYBOARD_LAYOUT, Handle ); ASSERT_EFI_ERROR (Status); // // Copy Keyboard Layout package // CopyMem (Buffer, Package->KeyboardPkg, PackageHeader.Length); Buffer = (UINT8 *) Buffer + PackageHeader.Length; } } *ResultSize += PackageLength; return EFI_SUCCESS; } /** This function deletes all Keyboard Layout packages from a package list node. This is a internal function. @param Private Hii database private data. @param Handle Handle of the package list which contains the to be removed Keyboard Layout packages. @param PackageList Pointer to a package list that contains removing packages. @retval EFI_SUCCESS Keyboard Layout Package(s) is deleted successfully. @retval EFI_INVALID_PARAMETER Any input parameter is not valid. **/ EFI_STATUS RemoveKeyboardLayoutPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN OUT HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList ) { LIST_ENTRY *ListHead; HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package; EFI_HII_PACKAGE_HEADER PackageHeader; EFI_STATUS Status; ListHead = &PackageList->KeyboardLayoutHdr; while (!IsListEmpty (ListHead)) { Package = CR ( ListHead->ForwardLink, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE ); Status = InvokeRegisteredFunction ( Private, EFI_HII_DATABASE_NOTIFY_REMOVE_PACK, (VOID *) Package, EFI_HII_PACKAGE_KEYBOARD_LAYOUT, Handle ); if (EFI_ERROR (Status)) { return Status; } RemoveEntryList (&Package->KeyboardEntry); CopyMem (&PackageHeader, Package->KeyboardPkg, sizeof (EFI_HII_PACKAGE_HEADER)); PackageList->PackageListHdr.PackageLength -= PackageHeader.Length; FreePool (Package->KeyboardPkg); FreePool (Package); } return EFI_SUCCESS; } /** This function will insert a package list to hii database firstly then invoke notification functions if any. It is the worker function of HiiNewPackageList and HiiUpdatePackageList. This is a internal function. @param Private Hii database private structure. @param NotifyType The type of change concerning the database. @param PackageList Pointer to a package list. @param DatabaseRecord Pointer to a database record contains a package list instance which will be inserted to. @retval EFI_SUCCESS All incoming packages are inserted to current database. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new Device path package. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS AddPackages ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList, IN OUT HII_DATABASE_RECORD *DatabaseRecord ) { EFI_STATUS Status; HII_GUID_PACKAGE_INSTANCE *GuidPackage; HII_IFR_PACKAGE_INSTANCE *FormPackage; HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *KeyboardLayoutPackage; HII_STRING_PACKAGE_INSTANCE *StringPackage; HII_FONT_PACKAGE_INSTANCE *FontPackage; HII_SIMPLE_FONT_PACKAGE_INSTANCE *SimpleFontPackage; HII_IMAGE_PACKAGE_INSTANCE *ImagePackage; EFI_HII_PACKAGE_HEADER *PackageHdrPtr; EFI_HII_PACKAGE_HEADER PackageHeader; UINT32 OldPackageListLen; BOOLEAN StringPkgIsAdd; // // Initialize Variables // StringPkgIsAdd = FALSE; FontPackage = NULL; StringPackage = NULL; GuidPackage = NULL; FormPackage = NULL; ImagePackage = NULL; SimpleFontPackage = NULL; KeyboardLayoutPackage = NULL; // // Process the package list header // OldPackageListLen = DatabaseRecord->PackageList->PackageListHdr.PackageLength; CopyMem ( &DatabaseRecord->PackageList->PackageListHdr, (VOID *) PackageList, sizeof (EFI_HII_PACKAGE_LIST_HEADER) ); if (NotifyType == EFI_HII_DATABASE_NOTIFY_ADD_PACK) { DatabaseRecord->PackageList->PackageListHdr.PackageLength = OldPackageListLen; } PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER)); CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); Status = EFI_SUCCESS; while (PackageHeader.Type != EFI_HII_PACKAGE_END) { switch (PackageHeader.Type) { case EFI_HII_PACKAGE_TYPE_GUID: Status = InsertGuidPackage ( PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &GuidPackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) GuidPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); break; case EFI_HII_PACKAGE_FORMS: Status = InsertFormPackage ( PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &FormPackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) FormPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); // // If Hii runtime support feature is enabled, // will export Hii info for runtime use after ReadyToBoot event triggered. // If some driver add/update/remove packages from HiiDatabase after ReadyToBoot, // will need to export the content of HiiDatabase. // But if form packages added/updated, also need to export the ConfigResp string. // if (gExportAfterReadyToBoot) { gExportConfigResp = TRUE; } break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: Status = InsertKeyboardLayoutPackage ( PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &KeyboardLayoutPackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) KeyboardLayoutPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); break; case EFI_HII_PACKAGE_STRINGS: Status = InsertStringPackage ( Private, PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &StringPackage ); if (EFI_ERROR (Status)) { return Status; } ASSERT (StringPackage != NULL); Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) StringPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); StringPkgIsAdd = TRUE; break; case EFI_HII_PACKAGE_FONTS: Status = InsertFontPackage ( Private, PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &FontPackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) FontPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); break; case EFI_HII_PACKAGE_IMAGES: Status = InsertImagePackage ( PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &ImagePackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) ImagePackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); break; case EFI_HII_PACKAGE_SIMPLE_FONTS: Status = InsertSimpleFontPackage ( PackageHdrPtr, NotifyType, DatabaseRecord->PackageList, &SimpleFontPackage ); if (EFI_ERROR (Status)) { return Status; } Status = InvokeRegisteredFunction ( Private, NotifyType, (VOID *) SimpleFontPackage, (UINT8) (PackageHeader.Type), DatabaseRecord->Handle ); break; case EFI_HII_PACKAGE_DEVICE_PATH: Status = AddDevicePathPackage ( Private, NotifyType, (EFI_DEVICE_PATH_PROTOCOL *) ((UINT8 *) PackageHdrPtr + sizeof (EFI_HII_PACKAGE_HEADER)), DatabaseRecord ); break; default: break; } if (EFI_ERROR (Status)) { return Status; } // // goto header of next package // PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length); CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); } // // Adjust String Package to make sure all string packages have the same max string ID. // if (!EFI_ERROR (Status) && StringPkgIsAdd) { Status = AdjustStringPackage (DatabaseRecord->PackageList); } return Status; } /** This function exports a package list to a buffer. It is the worker function of HiiExportPackageList. This is a internal function. @param Private Hii database private structure. @param Handle Identification of a package list. @param PackageList Pointer to a package list which will be exported. @param UsedSize The length of buffer has been used by exporting package lists when Handle is NULL. @param BufferSize Length of the Buffer. @param Buffer Allocated space for storing exported data. @retval EFI_SUCCESS Keyboard Layout Packages are exported successfully. @retval EFI_INVALID_PARAMETER Any input parameter is invalid. **/ EFI_STATUS ExportPackageList ( IN HII_DATABASE_PRIVATE_DATA *Private, IN EFI_HII_HANDLE Handle, IN HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList, IN OUT UINTN *UsedSize, IN UINTN BufferSize, OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer ) { EFI_STATUS Status; UINTN ResultSize; EFI_HII_PACKAGE_HEADER EndofPackageList; ASSERT (Private != NULL && PackageList != NULL && UsedSize != NULL); ASSERT (Private->Signature == HII_DATABASE_PRIVATE_DATA_SIGNATURE); ASSERT (IsHiiHandleValid (Handle)); if (BufferSize > 0 && Buffer == NULL ) { return EFI_INVALID_PARAMETER; } // // Copy the package list header // ResultSize indicates the length of the exported bytes of this package list // ResultSize = sizeof (EFI_HII_PACKAGE_LIST_HEADER); if (ResultSize + *UsedSize <= BufferSize) { CopyMem ((VOID *) Buffer, PackageList, ResultSize); } // // Copy the packages and invoke EXPORT_PACK notify functions if exists. // Status = ExportGuidPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportFormPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportKeyboardLayoutPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportStringPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportFontPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportImagePackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportSimpleFontPackages ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } Status = ExportDevicePathPackage ( Private, Handle, PackageList, *UsedSize, BufferSize, (VOID *) ((UINT8 *) Buffer + ResultSize), &ResultSize ); if (EFI_ERROR (Status)) { return Status; } // // Append the package list end. // EndofPackageList.Length = sizeof (EFI_HII_PACKAGE_HEADER); EndofPackageList.Type = EFI_HII_PACKAGE_END; if (ResultSize + *UsedSize + sizeof (EFI_HII_PACKAGE_HEADER) <= BufferSize) { CopyMem ( (VOID *) ((UINT8 *) Buffer + ResultSize), (VOID *) &EndofPackageList, sizeof (EFI_HII_PACKAGE_HEADER) ); } *UsedSize += ResultSize + sizeof (EFI_HII_PACKAGE_HEADER); return EFI_SUCCESS; } /** This function mainly use to get and update ConfigResp string. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @retval EFI_SUCCESS Get the information successfully. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the Configuration Setting data. **/ EFI_STATUS HiiGetConfigRespInfo( IN CONST EFI_HII_DATABASE_PROTOCOL *This ) { EFI_STATUS Status; HII_DATABASE_PRIVATE_DATA *Private; EFI_STRING ConfigAltResp; UINTN ConfigSize; ConfigAltResp = NULL; ConfigSize = 0; Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); // // Get ConfigResp string // Status = HiiConfigRoutingExportConfig(&Private->ConfigRouting,&ConfigAltResp); if (!EFI_ERROR (Status)){ ConfigSize = StrSize(ConfigAltResp); if (ConfigSize > gConfigRespSize){ // // Do 25% overallocation to minimize the number of memory allocations after ReadyToBoot. // Since lots of allocation after ReadyToBoot may change memory map and cause S4 resume issue. // gConfigRespSize = ConfigSize + (ConfigSize >> 2); if (gRTConfigRespBuffer != NULL){ FreePool(gRTConfigRespBuffer); DEBUG ((DEBUG_WARN, "[HiiDatabase]: Memory allocation is required after ReadyToBoot, which may change memory map and cause S4 resume issue.\n")); } gRTConfigRespBuffer = (EFI_STRING) AllocateRuntimeZeroPool (gConfigRespSize); if (gRTConfigRespBuffer == NULL){ FreePool(ConfigAltResp); DEBUG ((DEBUG_ERROR, "[HiiDatabase]: No enough memory resource to store the ConfigResp string.\n")); // // Remove from the System Table when the configuration runtime buffer is freed. // gBS->InstallConfigurationTable (&gEfiHiiConfigRoutingProtocolGuid, NULL); return EFI_OUT_OF_RESOURCES; } } else { ZeroMem(gRTConfigRespBuffer,gConfigRespSize); } CopyMem(gRTConfigRespBuffer,ConfigAltResp,ConfigSize); gBS->InstallConfigurationTable (&gEfiHiiConfigRoutingProtocolGuid, gRTConfigRespBuffer); FreePool(ConfigAltResp); } return EFI_SUCCESS; } /** This is an internal function,mainly use to get HiiDatabase information. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @retval EFI_SUCCESS Get the information successfully. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the Hiidatabase data. **/ EFI_STATUS HiiGetDatabaseInfo( IN CONST EFI_HII_DATABASE_PROTOCOL *This ) { EFI_STATUS Status; EFI_HII_PACKAGE_LIST_HEADER *DatabaseInfo; UINTN DatabaseInfoSize; DatabaseInfo = NULL; DatabaseInfoSize = 0; // // Get HiiDatabase information. // Status = HiiExportPackageLists(This, NULL, &DatabaseInfoSize, DatabaseInfo); ASSERT(Status == EFI_BUFFER_TOO_SMALL); if(DatabaseInfoSize > gDatabaseInfoSize ) { // // Do 25% overallocation to minimize the number of memory allocations after ReadyToBoot. // Since lots of allocation after ReadyToBoot may change memory map and cause S4 resume issue. // gDatabaseInfoSize = DatabaseInfoSize + (DatabaseInfoSize >> 2); if (gRTDatabaseInfoBuffer != NULL){ FreePool(gRTDatabaseInfoBuffer); DEBUG ((DEBUG_WARN, "[HiiDatabase]: Memory allocation is required after ReadyToBoot, which may change memory map and cause S4 resume issue.\n")); } gRTDatabaseInfoBuffer = AllocateRuntimeZeroPool (gDatabaseInfoSize); if (gRTDatabaseInfoBuffer == NULL){ DEBUG ((DEBUG_ERROR, "[HiiDatabase]: No enough memory resource to store the HiiDatabase info.\n")); // // Remove from the System Table when the configuration runtime buffer is freed. // gBS->InstallConfigurationTable (&gEfiHiiDatabaseProtocolGuid, NULL); return EFI_OUT_OF_RESOURCES; } } else { ZeroMem(gRTDatabaseInfoBuffer,gDatabaseInfoSize); } Status = HiiExportPackageLists(This, NULL, &DatabaseInfoSize, gRTDatabaseInfoBuffer); ASSERT_EFI_ERROR (Status); gBS->InstallConfigurationTable (&gEfiHiiDatabaseProtocolGuid, gRTDatabaseInfoBuffer); return EFI_SUCCESS; } /** This function adds the packages in the package list to the database and returns a handle. If there is a EFI_DEVICE_PATH_PROTOCOL associated with the DriverHandle, then this function will create a package of type EFI_PACKAGE_TYPE_DEVICE_PATH and add it to the package list. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure. @param DriverHandle Associate the package list with this EFI handle. If a NULL is specified, this data will not be associate with any drivers and cannot have a callback induced. @param Handle A pointer to the EFI_HII_HANDLE instance. @retval EFI_SUCCESS The package list associated with the Handle was added to the HII database. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary resources for the new database contents. @retval EFI_INVALID_PARAMETER PackageList is NULL or Handle is NULL. @retval EFI_INVALID_PARAMETER PackageListGuid already exists in database. **/ EFI_STATUS EFIAPI HiiNewPackageList ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList, IN CONST EFI_HANDLE DriverHandle, OPTIONAL OUT EFI_HII_HANDLE *Handle ) { EFI_STATUS Status; HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *DatabaseRecord; EFI_DEVICE_PATH_PROTOCOL *DevicePath; LIST_ENTRY *Link; EFI_GUID PackageListGuid; if (This == NULL || PackageList == NULL || Handle == NULL) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); CopyMem (&PackageListGuid, (VOID *) PackageList, sizeof (EFI_GUID)); // // Check the Package list GUID to guarantee this GUID is unique in database. // for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { DatabaseRecord = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); if (CompareGuid ( &(DatabaseRecord->PackageList->PackageListHdr.PackageListGuid), &PackageListGuid) && DatabaseRecord->DriverHandle == DriverHandle) { return EFI_INVALID_PARAMETER; } } EfiAcquireLock (&mHiiDatabaseLock); // // Build a PackageList node // Status = GenerateHiiDatabaseRecord (Private, &DatabaseRecord); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } // // Fill in information of the created Package List node // according to incoming package list. // Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, PackageList, DatabaseRecord); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } DatabaseRecord->DriverHandle = DriverHandle; // // Create a Device path package and add into the package list if exists. // Status = gBS->HandleProtocol ( DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath ); if (!EFI_ERROR (Status)) { Status = AddDevicePathPackage (Private, EFI_HII_DATABASE_NOTIFY_NEW_PACK, DevicePath, DatabaseRecord); ASSERT_EFI_ERROR (Status); } *Handle = DatabaseRecord->Handle; // // Check whether need to get the Database info. // Only after ReadyToBoot, need to do the export. // if (gExportAfterReadyToBoot) { HiiGetDatabaseInfo (This); } EfiReleaseLock (&mHiiDatabaseLock); // // Notes: // HiiGetDatabaseInfo () will get the contents of HII data base, // belong to the atomic behavior of Hii Database update. // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers // we can not think it belong to the atomic behavior of Hii Database update. // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo (). // // Check whether need to get the configuration setting info from HII drivers. // When after ReadyToBoot and need to do the export for form package add. // if (gExportAfterReadyToBoot && gExportConfigResp) { HiiGetConfigRespInfo (This); } return EFI_SUCCESS; } /** This function removes the package list that is associated with Handle from the HII database. Before removing the package, any registered functions with the notification type REMOVE_PACK and the same package type will be called. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param Handle The handle that was registered to the data that is requested for removal. @retval EFI_SUCCESS The data associated with the Handle was removed from the HII database. @retval EFI_NOT_FOUND The specified handle is not in database. @retval EFI_INVALID_PARAMETER The Handle was not valid. **/ EFI_STATUS EFIAPI HiiRemovePackageList ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN EFI_HII_HANDLE Handle ) { EFI_STATUS Status; HII_DATABASE_PRIVATE_DATA *Private; LIST_ENTRY *Link; HII_DATABASE_RECORD *Node; HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; HII_HANDLE *HiiHandle; if (This == NULL) { return EFI_INVALID_PARAMETER; } if (!IsHiiHandleValid (Handle)) { return EFI_NOT_FOUND; } EfiAcquireLock (&mHiiDatabaseLock); Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); // // Get the packagelist to be removed. // for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); if (Node->Handle == Handle) { PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList); ASSERT (PackageList != NULL); // // Call registered functions with REMOVE_PACK before removing packages // then remove them. // Status = RemoveGuidPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveFormPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveKeyboardLayoutPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveStringPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveFontPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveImagePackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveSimpleFontPackages (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } Status = RemoveDevicePathPackage (Private, Handle, PackageList); if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } // // Free resources of the package list // RemoveEntryList (&Node->DatabaseEntry); HiiHandle = (HII_HANDLE *) Handle; RemoveEntryList (&HiiHandle->Handle); Private->HiiHandleCount--; ASSERT (Private->HiiHandleCount >= 0); HiiHandle->Signature = 0; FreePool (HiiHandle); FreePool (Node->PackageList); FreePool (Node); // // Check whether need to get the Database info. // Only after ReadyToBoot, need to do the export. // if (gExportAfterReadyToBoot) { HiiGetDatabaseInfo (This); } EfiReleaseLock (&mHiiDatabaseLock); // // Notes: // HiiGetDatabaseInfo () will get the contents of HII data base, // belong to the atomic behavior of Hii Database update. // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers // we can not think it belong to the atomic behavior of Hii Database update. // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo (). // // // Check whether need to get the configuration setting info from HII drivers. // When after ReadyToBoot and need to do the export for form package remove. // if (gExportAfterReadyToBoot && gExportConfigResp) { HiiGetConfigRespInfo (This); } return EFI_SUCCESS; } } EfiReleaseLock (&mHiiDatabaseLock); return EFI_NOT_FOUND; } /** This function updates the existing package list (which has the specified Handle) in the HII databases, using the new package list specified by PackageList. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param Handle The handle that was registered to the data that is requested to be updated. @param PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER package. @retval EFI_SUCCESS The HII database was successfully updated. @retval EFI_OUT_OF_RESOURCES Unable to allocate enough memory for the updated database. @retval EFI_INVALID_PARAMETER PackageList was NULL. @retval EFI_NOT_FOUND The specified Handle is not in database. **/ EFI_STATUS EFIAPI HiiUpdatePackageList ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN EFI_HII_HANDLE Handle, IN CONST EFI_HII_PACKAGE_LIST_HEADER *PackageList ) { EFI_STATUS Status; HII_DATABASE_PRIVATE_DATA *Private; LIST_ENTRY *Link; HII_DATABASE_RECORD *Node; EFI_HII_PACKAGE_HEADER *PackageHdrPtr; HII_DATABASE_PACKAGE_LIST_INSTANCE *OldPackageList; EFI_HII_PACKAGE_HEADER PackageHeader; if (This == NULL || PackageList == NULL) { return EFI_INVALID_PARAMETER; } if (!IsHiiHandleValid (Handle)) { return EFI_NOT_FOUND; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageList + sizeof (EFI_HII_PACKAGE_LIST_HEADER)); Status = EFI_SUCCESS; EfiAcquireLock (&mHiiDatabaseLock); // // Get original packagelist to be updated // for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); if (Node->Handle == Handle) { OldPackageList = Node->PackageList; // // Remove the package if its type matches one of the package types which is // contained in the new package list. // CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); while (PackageHeader.Type != EFI_HII_PACKAGE_END) { switch (PackageHeader.Type) { case EFI_HII_PACKAGE_TYPE_GUID: Status = RemoveGuidPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_FORMS: Status = RemoveFormPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: Status = RemoveKeyboardLayoutPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_STRINGS: Status = RemoveStringPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_FONTS: Status = RemoveFontPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_IMAGES: Status = RemoveImagePackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_SIMPLE_FONTS: Status = RemoveSimpleFontPackages (Private, Handle, OldPackageList); break; case EFI_HII_PACKAGE_DEVICE_PATH: Status = RemoveDevicePathPackage (Private, Handle, OldPackageList); break; } if (EFI_ERROR (Status)) { EfiReleaseLock (&mHiiDatabaseLock); return Status; } PackageHdrPtr = (EFI_HII_PACKAGE_HEADER *) ((UINT8 *) PackageHdrPtr + PackageHeader.Length); CopyMem (&PackageHeader, PackageHdrPtr, sizeof (EFI_HII_PACKAGE_HEADER)); } // // Add all of the packages within the new package list // Status = AddPackages (Private, EFI_HII_DATABASE_NOTIFY_ADD_PACK, PackageList, Node); // // Check whether need to get the Database info. // Only after ReadyToBoot, need to do the export. // if (gExportAfterReadyToBoot && Status == EFI_SUCCESS) { HiiGetDatabaseInfo (This); } EfiReleaseLock (&mHiiDatabaseLock); // // Notes: // HiiGetDatabaseInfo () will get the contents of HII data base, // belong to the atomic behavior of Hii Database update. // And since HiiGetConfigRespInfo () will get the configuration setting info from HII drivers // we can not think it belong to the atomic behavior of Hii Database update. // That's why EfiReleaseLock (&mHiiDatabaseLock) is callled before HiiGetConfigRespInfo (). // // // Check whether need to get the configuration setting info from HII drivers. // When after ReadyToBoot and need to do the export for form package update. // if (gExportAfterReadyToBoot && gExportConfigResp && Status == EFI_SUCCESS) { HiiGetConfigRespInfo (This); } return Status; } } EfiReleaseLock (&mHiiDatabaseLock); return EFI_NOT_FOUND; } /** This function returns a list of the package handles of the specified type that are currently active in the database. The pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package handles to be listed. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param PackageType Specifies the package type of the packages to list or EFI_HII_PACKAGE_TYPE_ALL for all packages to be listed. @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then this is the pointer to the GUID which must match the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must be NULL. @param HandleBufferLength On input, a pointer to the length of the handle buffer. On output, the length of the handle buffer that is required for the handles found. @param Handle An array of EFI_HII_HANDLE instances returned. @retval EFI_SUCCESS The matching handles are outputted successfully. HandleBufferLength is updated with the actual length. @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that Handle is too small to support the number of handles. HandleBufferLength is updated with a value that will enable the data to fit. @retval EFI_NOT_FOUND No matching handle could not be found in database. @retval EFI_INVALID_PARAMETER HandleBufferLength was NULL. @retval EFI_INVALID_PARAMETER The value referenced by HandleBufferLength was not zero and Handle was NULL. @retval EFI_INVALID_PARAMETER PackageType is not a EFI_HII_PACKAGE_TYPE_GUID but PackageGuid is not NULL, PackageType is a EFI_HII_ PACKAGE_TYPE_GUID but PackageGuid is NULL. **/ EFI_STATUS EFIAPI HiiListPackageLists ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN UINT8 PackageType, IN CONST EFI_GUID *PackageGuid, IN OUT UINTN *HandleBufferLength, OUT EFI_HII_HANDLE *Handle ) { HII_GUID_PACKAGE_INSTANCE *GuidPackage; HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *Node; LIST_ENTRY *Link; BOOLEAN Matched; HII_HANDLE **Result; UINTN ResultSize; HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; LIST_ENTRY *Link1; // // Check input parameters // if (This == NULL || HandleBufferLength == NULL) { return EFI_INVALID_PARAMETER; } if (*HandleBufferLength > 0 && Handle == NULL) { return EFI_INVALID_PARAMETER; } if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) || (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); Matched = FALSE; Result = (HII_HANDLE **) Handle; ResultSize = 0; for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList); switch (PackageType) { case EFI_HII_PACKAGE_TYPE_GUID: for (Link1 = PackageList->GuidPkgHdr.ForwardLink; Link1 != &PackageList->GuidPkgHdr; Link1 = Link1->ForwardLink) { GuidPackage = CR (Link1, HII_GUID_PACKAGE_INSTANCE, GuidEntry, HII_GUID_PACKAGE_SIGNATURE); if (CompareGuid ( (EFI_GUID *) PackageGuid, (EFI_GUID *) (GuidPackage->GuidPkg + sizeof (EFI_HII_PACKAGE_HEADER)) )) { Matched = TRUE; break; } } break; case EFI_HII_PACKAGE_FORMS: if (!IsListEmpty (&PackageList->FormPkgHdr)) { Matched = TRUE; } break; case EFI_HII_PACKAGE_KEYBOARD_LAYOUT: if (!IsListEmpty (&PackageList->KeyboardLayoutHdr)) { Matched = TRUE; } break; case EFI_HII_PACKAGE_STRINGS: if (!IsListEmpty (&PackageList->StringPkgHdr)) { Matched = TRUE; } break; case EFI_HII_PACKAGE_FONTS: if (!IsListEmpty (&PackageList->FontPkgHdr)) { Matched = TRUE; } break; case EFI_HII_PACKAGE_IMAGES: if (PackageList->ImagePkg != NULL) { Matched = TRUE; } break; case EFI_HII_PACKAGE_SIMPLE_FONTS: if (!IsListEmpty (&PackageList->SimpleFontPkgHdr)) { Matched = TRUE; } break; case EFI_HII_PACKAGE_DEVICE_PATH: if (PackageList->DevicePathPkg != NULL) { Matched = TRUE; } break; // // Pseudo-type EFI_HII_PACKAGE_TYPE_ALL will cause all package handles // to be listed. // case EFI_HII_PACKAGE_TYPE_ALL: Matched = TRUE; break; default: break; } // // This active package list has the specified package type, list it. // if (Matched) { ResultSize += sizeof (EFI_HII_HANDLE); if (ResultSize <= *HandleBufferLength) { *Result++ = Node->Handle; } } Matched = FALSE; } if (ResultSize == 0) { return EFI_NOT_FOUND; } if (*HandleBufferLength < ResultSize) { *HandleBufferLength = ResultSize; return EFI_BUFFER_TOO_SMALL; } *HandleBufferLength = ResultSize; return EFI_SUCCESS; } /** This function will export one or all package lists in the database to a buffer. For each package list exported, this function will call functions registered with EXPORT_PACK and then copy the package list to the buffer. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param Handle An EFI_HII_HANDLE that corresponds to the desired package list in the HII database to export or NULL to indicate all package lists should be exported. @param BufferSize On input, a pointer to the length of the buffer. On output, the length of the buffer that is required for the exported data. @param Buffer A pointer to a buffer that will contain the results of the export function. @retval EFI_SUCCESS Package exported. @retval EFI_BUFFER_TO_SMALL The HandleBufferLength parameter indicates that Handle is too small to support the number of handles. HandleBufferLength is updated with a value that will enable the data to fit. @retval EFI_NOT_FOUND The specified Handle could not be found in the current database. @retval EFI_INVALID_PARAMETER BufferSize was NULL. @retval EFI_INVALID_PARAMETER The value referenced by BufferSize was not zero and Buffer was NULL. **/ EFI_STATUS EFIAPI HiiExportPackageLists ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN EFI_HII_HANDLE Handle, IN OUT UINTN *BufferSize, OUT EFI_HII_PACKAGE_LIST_HEADER *Buffer ) { LIST_ENTRY *Link; EFI_STATUS Status; HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *Node; UINTN UsedSize; if (This == NULL || BufferSize == NULL) { return EFI_INVALID_PARAMETER; } if (*BufferSize > 0 && Buffer == NULL) { return EFI_INVALID_PARAMETER; } if ((Handle != NULL) && (!IsHiiHandleValid (Handle))) { return EFI_NOT_FOUND; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); UsedSize = 0; for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); if (Handle == NULL) { // // Export all package lists in current hii database. // Status = ExportPackageList ( Private, Node->Handle, (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList), &UsedSize, *BufferSize, (EFI_HII_PACKAGE_LIST_HEADER *)((UINT8 *) Buffer + UsedSize) ); ASSERT_EFI_ERROR (Status); } else if (Handle != NULL && Node->Handle == Handle) { Status = ExportPackageList ( Private, Handle, (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList), &UsedSize, *BufferSize, Buffer ); ASSERT_EFI_ERROR (Status); if (*BufferSize < UsedSize) { *BufferSize = UsedSize; return EFI_BUFFER_TOO_SMALL; } return EFI_SUCCESS; } } if (Handle == NULL && UsedSize != 0) { if (*BufferSize < UsedSize) { *BufferSize = UsedSize; return EFI_BUFFER_TOO_SMALL; } return EFI_SUCCESS; } return EFI_NOT_FOUND; } /** This function registers a function which will be called when specified actions related to packages of the specified type occur in the HII database. By registering a function, other HII-related drivers are notified when specific package types are added, removed or updated in the HII database. Each driver or application which registers a notification should use EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() before exiting. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param PackageType Specifies the package type of the packages to list or EFI_HII_PACKAGE_TYPE_ALL for all packages to be listed. @param PackageGuid If PackageType is EFI_HII_PACKAGE_TYPE_GUID, then this is the pointer to the GUID which must match the Guid field of EFI_HII_GUID_PACKAGE_GUID_HDR. Otherwise, it must be NULL. @param PackageNotifyFn Points to the function to be called when the event specified by NotificationType occurs. @param NotifyType Describes the types of notification which this function will be receiving. @param NotifyHandle Points to the unique handle assigned to the registered notification. Can be used in EFI_HII_DATABASE_PROTOCOL.UnregisterPackageNotify() to stop notifications. @retval EFI_SUCCESS Notification registered successfully. @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures @retval EFI_INVALID_PARAMETER NotifyHandle is NULL. @retval EFI_INVALID_PARAMETER PackageGuid is not NULL when PackageType is not EFI_HII_PACKAGE_TYPE_GUID. @retval EFI_INVALID_PARAMETER PackageGuid is NULL when PackageType is EFI_HII_PACKAGE_TYPE_GUID. **/ EFI_STATUS EFIAPI HiiRegisterPackageNotify ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN UINT8 PackageType, IN CONST EFI_GUID *PackageGuid, IN CONST EFI_HII_DATABASE_NOTIFY PackageNotifyFn, IN EFI_HII_DATABASE_NOTIFY_TYPE NotifyType, OUT EFI_HANDLE *NotifyHandle ) { HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_NOTIFY *Notify; EFI_STATUS Status; if (This == NULL || NotifyHandle == NULL) { return EFI_INVALID_PARAMETER; } if ((PackageType == EFI_HII_PACKAGE_TYPE_GUID && PackageGuid == NULL) || (PackageType != EFI_HII_PACKAGE_TYPE_GUID && PackageGuid != NULL)) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); // // Allocate a notification node // Notify = (HII_DATABASE_NOTIFY *) AllocateZeroPool (sizeof (HII_DATABASE_NOTIFY)); if (Notify == NULL) { return EFI_OUT_OF_RESOURCES; } // // Generate a notify handle // Status = gBS->InstallMultipleProtocolInterfaces ( &Notify->NotifyHandle, &gEfiCallerIdGuid, NULL, NULL ); ASSERT_EFI_ERROR (Status); // // Fill in the information to the notification node // Notify->Signature = HII_DATABASE_NOTIFY_SIGNATURE; Notify->PackageType = PackageType; Notify->PackageGuid = (EFI_GUID *) PackageGuid; Notify->PackageNotifyFn = (EFI_HII_DATABASE_NOTIFY) PackageNotifyFn; Notify->NotifyType = NotifyType; InsertTailList (&Private->DatabaseNotifyList, &Notify->DatabaseNotifyEntry); *NotifyHandle = Notify->NotifyHandle; return EFI_SUCCESS; } /** Removes the specified HII database package-related notification. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param NotificationHandle The handle of the notification function being unregistered. @retval EFI_SUCCESS Notification is unregistered successfully. @retval EFI_INVALID_PARAMETER The Handle is invalid. @retval EFI_NOT_FOUND The incoming notification handle does not exist in current hii database. **/ EFI_STATUS EFIAPI HiiUnregisterPackageNotify ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN EFI_HANDLE NotificationHandle ) { HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_NOTIFY *Notify; LIST_ENTRY *Link; EFI_STATUS Status; if (This == NULL) { return EFI_INVALID_PARAMETER; } if (NotificationHandle == NULL) { return EFI_NOT_FOUND; } Status = gBS->OpenProtocol ( NotificationHandle, &gEfiCallerIdGuid, NULL, NULL, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL ); if (EFI_ERROR (Status)) { return EFI_NOT_FOUND; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); for (Link = Private->DatabaseNotifyList.ForwardLink; Link != &Private->DatabaseNotifyList; Link = Link->ForwardLink) { Notify = CR (Link, HII_DATABASE_NOTIFY, DatabaseNotifyEntry, HII_DATABASE_NOTIFY_SIGNATURE); if (Notify->NotifyHandle == NotificationHandle) { // // Remove the matching notification node // RemoveEntryList (&Notify->DatabaseNotifyEntry); Status = gBS->UninstallMultipleProtocolInterfaces ( Notify->NotifyHandle, &gEfiCallerIdGuid, NULL, NULL ); ASSERT_EFI_ERROR (Status); FreePool (Notify); return EFI_SUCCESS; } } return EFI_NOT_FOUND; } /** This routine retrieves an array of GUID values for each keyboard layout that was previously registered in the system. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param KeyGuidBufferLength On input, a pointer to the length of the keyboard GUID buffer. On output, the length of the handle buffer that is required for the handles found. @param KeyGuidBuffer An array of keyboard layout GUID instances returned. @retval EFI_SUCCESS KeyGuidBuffer was updated successfully. @retval EFI_BUFFER_TOO_SMALL The KeyGuidBufferLength parameter indicates that KeyGuidBuffer is too small to support the number of GUIDs. KeyGuidBufferLength is updated with a value that will enable the data to fit. @retval EFI_INVALID_PARAMETER The KeyGuidBufferLength is NULL. @retval EFI_INVALID_PARAMETER The value referenced by KeyGuidBufferLength is not zero and KeyGuidBuffer is NULL. @retval EFI_NOT_FOUND There was no keyboard layout. **/ EFI_STATUS EFIAPI HiiFindKeyboardLayouts ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN OUT UINT16 *KeyGuidBufferLength, OUT EFI_GUID *KeyGuidBuffer ) { HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *Node; HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; LIST_ENTRY *Link; LIST_ENTRY *Link1; UINT16 ResultSize; UINTN Index; UINT16 LayoutCount; UINT16 LayoutLength; UINT8 *Layout; HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package; if (This == NULL || KeyGuidBufferLength == NULL) { return EFI_INVALID_PARAMETER; } if (*KeyGuidBufferLength > 0 && KeyGuidBuffer == NULL) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); ResultSize = 0; // // Search all package lists in whole database to retrieve keyboard layout. // for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); PackageList = Node->PackageList; for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink; Link1 != &PackageList->KeyboardLayoutHdr; Link1 = Link1->ForwardLink ) { // // Find out all Keyboard Layout packages in this package list. // Package = CR ( Link1, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE ); Layout = (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16); CopyMem ( &LayoutCount, (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER), sizeof (UINT16) ); for (Index = 0; Index < LayoutCount; Index++) { ResultSize += sizeof (EFI_GUID); if (ResultSize <= *KeyGuidBufferLength) { CopyMem (KeyGuidBuffer + (ResultSize / sizeof (EFI_GUID) - 1), Layout + sizeof (UINT16), sizeof (EFI_GUID)); CopyMem (&LayoutLength, Layout, sizeof (UINT16)); Layout = Layout + LayoutLength; } } } } if (ResultSize == 0) { return EFI_NOT_FOUND; } if (*KeyGuidBufferLength < ResultSize) { *KeyGuidBufferLength = ResultSize; return EFI_BUFFER_TOO_SMALL; } *KeyGuidBufferLength = ResultSize; return EFI_SUCCESS; } /** This routine retrieves the requested keyboard layout. The layout is a physical description of the keys on a keyboard and the character(s) that are associated with a particular set of key strokes. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param KeyGuid A pointer to the unique ID associated with a given keyboard layout. If KeyGuid is NULL then the current layout will be retrieved. @param KeyboardLayoutLength On input, a pointer to the length of the KeyboardLayout buffer. On output, the length of the data placed into KeyboardLayout. @param KeyboardLayout A pointer to a buffer containing the retrieved keyboard layout. @retval EFI_SUCCESS The keyboard layout was retrieved successfully. @retval EFI_NOT_FOUND The requested keyboard layout was not found. @retval EFI_INVALID_PARAMETER The KeyboardLayout or KeyboardLayoutLength was NULL. @retval EFI_BUFFER_TOO_SMALL The KeyboardLayoutLength parameter indicates that KeyboardLayout is too small to support the requested keyboard layout. KeyboardLayoutLength is updated with a value that will enable the data to fit. **/ EFI_STATUS EFIAPI HiiGetKeyboardLayout ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN CONST EFI_GUID *KeyGuid, IN OUT UINT16 *KeyboardLayoutLength, OUT EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout ) { HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *Node; HII_DATABASE_PACKAGE_LIST_INSTANCE *PackageList; LIST_ENTRY *Link; LIST_ENTRY *Link1; UINTN Index; UINT8 *Layout; UINT16 LayoutCount; UINT16 LayoutLength; HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE *Package; if (This == NULL || KeyboardLayoutLength == NULL) { return EFI_INVALID_PARAMETER; } if (*KeyboardLayoutLength > 0 && KeyboardLayout == NULL) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); // // Retrieve the current keyboard layout. // if (KeyGuid == NULL) { if (Private->CurrentLayout == NULL) { return EFI_NOT_FOUND; } CopyMem (&LayoutLength, Private->CurrentLayout, sizeof (UINT16)); if (*KeyboardLayoutLength < LayoutLength) { *KeyboardLayoutLength = LayoutLength; return EFI_BUFFER_TOO_SMALL; } CopyMem (KeyboardLayout, Private->CurrentLayout, LayoutLength); return EFI_SUCCESS; } for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); PackageList = (HII_DATABASE_PACKAGE_LIST_INSTANCE *) (Node->PackageList); for (Link1 = PackageList->KeyboardLayoutHdr.ForwardLink; Link1 != &PackageList->KeyboardLayoutHdr; Link1 = Link1->ForwardLink ) { Package = CR ( Link1, HII_KEYBOARD_LAYOUT_PACKAGE_INSTANCE, KeyboardEntry, HII_KB_LAYOUT_PACKAGE_SIGNATURE ); Layout = (UINT8 *) Package->KeyboardPkg + sizeof (EFI_HII_PACKAGE_HEADER) + sizeof (UINT16); CopyMem (&LayoutCount, Layout - sizeof (UINT16), sizeof (UINT16)); for (Index = 0; Index < LayoutCount; Index++) { CopyMem (&LayoutLength, Layout, sizeof (UINT16)); if (CompareMem (Layout + sizeof (UINT16), KeyGuid, sizeof (EFI_GUID)) == 0) { if (LayoutLength <= *KeyboardLayoutLength) { CopyMem (KeyboardLayout, Layout, LayoutLength); return EFI_SUCCESS; } else { *KeyboardLayoutLength = LayoutLength; return EFI_BUFFER_TOO_SMALL; } } Layout = Layout + LayoutLength; } } } return EFI_NOT_FOUND; } /** This routine sets the default keyboard layout to the one referenced by KeyGuid. When this routine is called, an event will be signaled of the EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group type. This is so that agents which are sensitive to the current keyboard layout being changed can be notified of this change. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param KeyGuid A pointer to the unique ID associated with a given keyboard layout. @retval EFI_SUCCESS The current keyboard layout was successfully set. @retval EFI_NOT_FOUND The referenced keyboard layout was not found, so action was taken. @retval EFI_INVALID_PARAMETER The KeyGuid was NULL. **/ EFI_STATUS EFIAPI HiiSetKeyboardLayout ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN CONST EFI_GUID *KeyGuid ) { HII_DATABASE_PRIVATE_DATA *Private; EFI_HII_KEYBOARD_LAYOUT *KeyboardLayout; UINT16 KeyboardLayoutLength; EFI_STATUS Status; if (This == NULL || KeyGuid == NULL) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); // // The specified GUID equals the current keyboard layout GUID, // return directly. // if (CompareGuid (&Private->CurrentLayoutGuid, KeyGuid)) { return EFI_SUCCESS; } // // Try to find the incoming keyboard layout data in current database. // KeyboardLayoutLength = 0; KeyboardLayout = NULL; Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout); if (Status != EFI_BUFFER_TOO_SMALL) { return Status; } KeyboardLayout = (EFI_HII_KEYBOARD_LAYOUT *) AllocateZeroPool (KeyboardLayoutLength); ASSERT (KeyboardLayout != NULL); Status = HiiGetKeyboardLayout (This, KeyGuid, &KeyboardLayoutLength, KeyboardLayout); ASSERT_EFI_ERROR (Status); // // Backup current keyboard layout. // CopyMem (&Private->CurrentLayoutGuid, KeyGuid, sizeof (EFI_GUID)); if (Private->CurrentLayout != NULL) { FreePool(Private->CurrentLayout); } Private->CurrentLayout = KeyboardLayout; // // Signal EFI_HII_SET_KEYBOARD_LAYOUT_EVENT_GUID group to notify // current keyboard layout is changed. // Status = gBS->SignalEvent (gHiiKeyboardLayoutChanged); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; } /** Return the EFI handle associated with a package list. @param This A pointer to the EFI_HII_DATABASE_PROTOCOL instance. @param PackageListHandle An EFI_HII_HANDLE that corresponds to the desired package list in the HIIdatabase. @param DriverHandle On return, contains the EFI_HANDLE which was registered with the package list in NewPackageList(). @retval EFI_SUCCESS The DriverHandle was returned successfully. @retval EFI_INVALID_PARAMETER The PackageListHandle was not valid or DriverHandle was NULL. @retval EFI_NOT_FOUND This PackageList handle can not be found in current database. **/ EFI_STATUS EFIAPI HiiGetPackageListHandle ( IN CONST EFI_HII_DATABASE_PROTOCOL *This, IN EFI_HII_HANDLE PackageListHandle, OUT EFI_HANDLE *DriverHandle ) { HII_DATABASE_PRIVATE_DATA *Private; HII_DATABASE_RECORD *Node; LIST_ENTRY *Link; if (This == NULL || DriverHandle == NULL) { return EFI_INVALID_PARAMETER; } if (!IsHiiHandleValid (PackageListHandle)) { return EFI_INVALID_PARAMETER; } Private = HII_DATABASE_DATABASE_PRIVATE_DATA_FROM_THIS (This); for (Link = Private->DatabaseList.ForwardLink; Link != &Private->DatabaseList; Link = Link->ForwardLink) { Node = CR (Link, HII_DATABASE_RECORD, DatabaseEntry, HII_DATABASE_RECORD_SIGNATURE); if (Node->Handle == PackageListHandle) { *DriverHandle = Node->DriverHandle; return EFI_SUCCESS; } } return EFI_NOT_FOUND; }