In the last lesson we've discovered that internally HII Database stores Package lists and its packages not in a continious data array, but in a complex data structure with many double linked lists.
But when we've used ExportPackageLists
from the EFI_HII_DATABASE_PROTOCOL
, we received continious data array of Package lists and its packages. It is a handy interface to hide/abstract inernals of the HII Database and provide data to the user in a form that is easy to parse.
The same goes when we want to add Package list to the database via NewPackageList
from the EFI_HII_DATABASE_PROTOCOL
. This functions expects incoming Package list in a continious data array in the same form.
EFI_HII_DATABASE_PROTOCOL.NewPackageList()
Summary:
Adds the packages in the package list to the HII database.
Prototype:
typedef
EFI_STATUS
(EFIAPI *EFI_HII_DATABASE_NEW_PACK) (
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
);
Parameters:
This A pointer to the EFI_HII_DATABASE_PROTOCOL instance
PackageList A pointer to an EFI_HII_PACKAGE_LIST_HEADER structure
DriverHandle Associate the package list with this EFI handle
Handle A pointer to the EFI_HII_HANDLE instance
Description 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.
Let's inspect one more time the output of our ShowHII
application:
FS0:\> ShowHII.efi
PackageList[0]: GUID=A487A478-51EF-48AA-8794-7BEE2A0562F1; size=0x1ADC
Package[0]: type=STRINGS; size=0x1AC4
Package[1]: type=END; size=0x4
PackageList[1]: GUID=19618BCE-55AE-09C6-37E9-4CE04084C7A1; size=0x21E4
Package[0]: type=STRINGS; size=0x21CC
Package[1]: type=END; size=0x4
PackageList[2]: GUID=2F30DA26-F51B-4B6F-85C4-31873C281BCA; size=0xA93
Package[0]: type=STRINGS; size=0xA7B
Package[1]: type=END; size=0x4
PackageList[3]: GUID=F74D20EE-37E7-48FC-97F7-9B1047749C69; size=0x2EE9
Package[0]: type=IMAGES; size=0x2ED1
Package[1]: type=END; size=0x4
PackageList[4]: GUID=EBF8ED7C-0DD1-4787-84F1-F48D537DCACF; size=0x46C
Package[0]: type=FORMS; size=0x82
Package[1]: type=FORMS; size=0x82
Package[2]: type=STRINGS; size=0x199
Package[3]: type=STRINGS; size=0x19B
Package[4]: type=DEVICE_PATH; size=0x1C
Package[5]: type=END; size=0x4
PackageList[5]: GUID=FE561596-E6BF-41A6-8376-C72B719874D0; size=0x93F
Package[0]: type=FORMS; size=0xF5
Package[1]: type=STRINGS; size=0x40A
Package[2]: type=STRINGS; size=0x40C
Package[3]: type=DEVICE_PATH; size=0x1C
Package[4]: type=END; size=0x4
PackageList[6]: GUID=2A46715F-3581-4A55-8E73-2B769AAA30C5; size=0x6B0
Package[0]: type=FORMS; size=0x143
Package[1]: type=STRINGS; size=0x539
Package[2]: type=DEVICE_PATH; size=0x1C
Package[3]: type=END; size=0x4
PackageList[7]: GUID=99FDC8FD-849B-4EBA-AD13-FB9699C90A4D; size=0x6FE
Package[0]: type=STRINGS; size=0x340
Package[1]: type=STRINGS; size=0x3A6
Package[2]: type=END; size=0x4
PackageList[8]: GUID=E38C1029-E38F-45B9-8F0D-E2E60BC9B262; size=0x15DA
Package[0]: type=STRINGS; size=0xA88
Package[1]: type=STRINGS; size=0xB3A
Package[2]: type=END; size=0x4
PackageList[9]: GUID=D9DCC5DF-4007-435E-9098-8970935504B2; size=0x855
Package[0]: type=FORMS; size=0x1F6
Package[1]: type=STRINGS; size=0x62B
Package[2]: type=DEVICE_PATH; size=0x1C
Package[3]: type=END; size=0x4
PackageList[10]: GUID=F5F219D3-7006-4648-AC8D-D61DFB7BC6AD; size=0x14EC
Package[0]: type=SIMPLE_FONTS; size=0x14D4
Package[1]: type=END; size=0x4
PackageList[11]: GUID=4B47D616-A8D6-4552-9D44-CCAD2E0F4CF9; size=0x6AC8
Package[0]: type=FORMS; size=0x1030
Package[1]: type=STRINGS; size=0x3C99
Package[2]: type=STRINGS; size=0x1DCB
Package[3]: type=DEVICE_PATH; size=0x1C
Package[4]: type=END; size=0x4
PackageList[12]: GUID=F95A7CCC-4C55-4426-A7B4-DC8961950BAE; size=0x13909
Package[0]: type=STRINGS; size=0x138F1
Package[1]: type=END; size=0x4
PackageList[13]: GUID=DEC5DAA4-6781-4820-9C63-A7B0E4F1DB31; size=0x8677
Package[0]: type=STRINGS; size=0x865F
Package[1]: type=END; size=0x4
PackageList[14]: GUID=4344558D-4EF9-4725-B1E4-3376E8D6974F; size=0x83BD
Package[0]: type=STRINGS; size=0x83A5
Package[1]: type=END; size=0x4
PackageList[15]: GUID=0AF0B742-63EC-45BD-8DB6-71AD7F2FE8E8; size=0xCB04
Package[0]: type=STRINGS; size=0xCAEC
Package[1]: type=END; size=0x4
PackageList[16]: GUID=25F200AA-D3CB-470A-BF51-E7D162D22E6F; size=0x1D3D7
Package[0]: type=STRINGS; size=0x1D3BF
Package[1]: type=END; size=0x4
PackageList[17]: GUID=5F5F605D-1583-4A2D-A6B2-EB12DAB4A2B6; size=0x3048
Package[0]: type=STRINGS; size=0x3030
Package[1]: type=END; size=0x4
PackageList[18]: GUID=F3D301BB-F4A5-45A8-B0B7-FA999C6237AE; size=0x26B5
Package[0]: type=STRINGS; size=0x269D
Package[1]: type=END; size=0x4
PackageList[19]: GUID=7C04A583-9E3E-4F1C-AD65-E05268D0B4D1; size=0x5CB
Package[0]: type=STRINGS; size=0x5B3
Package[1]: type=END; size=0x4
From this output you can see that each Package list contains one or more data packages and ends with a special END
package.
Ordinary package contains EFI_HII_PACKAGE_HEADER
and data content. But the END
package is simply a EFI_HII_PACKAGE_HEADER
with a Type
field set to EFI_HII_PACKAGE_END
.
Just in case here are prototypes for the header structures once again:
typedef struct {
EFI_GUID PackageListGuid;
UINT32 PackagLength;
} EFI_HII_PACKAGE_LIST_HEADER;
typedef struct {
UINT32 Length:24;
UINT32 Type:8;
UINT8 Data[ … ];
} EFI_HII_PACKAGE_HEADER;
So basically package list data here looks something like this:
Ordinary packages can be of different types. For the examples take a look at the possible defines for the EFI_HII_PACKAGE_HEADER.type
field:
//
// Value of HII package type
//
#define EFI_HII_PACKAGE_TYPE_ALL 0x00
#define EFI_HII_PACKAGE_TYPE_GUID 0x01
#define EFI_HII_PACKAGE_FORMS 0x02
#define EFI_HII_PACKAGE_STRINGS 0x04
#define EFI_HII_PACKAGE_FONTS 0x05
#define EFI_HII_PACKAGE_IMAGES 0x06
#define EFI_HII_PACKAGE_SIMPLE_FONTS 0x07
#define EFI_HII_PACKAGE_DEVICE_PATH 0x08
#define EFI_HII_PACKAGE_KEYBOARD_LAYOUT 0x09
#define EFI_HII_PACKAGE_ANIMATIONS 0x0A
#define EFI_HII_PACKAGE_END 0xDF
#define EFI_HII_PACKAGE_TYPE_SYSTEM_BEGIN 0xE0
#define EFI_HII_PACKAGE_TYPE_SYSTEM_END 0xFF
In the next lessons we would try to add a Package list with Strings packages.
EFI_HII_PACKAGE_HEADER.type = EFI_HII_PACKAGE_STRINGS
Initialize new app from our template script:
./createNewApp.sh HIIStringsC
And add new app to the UefiLessonsPkg/UefiLessonsPkg.dsc
:
[Components]
...
UefiLessonsPkg/HIIStringsC/HIIStringsC.inf
As every Package list has its own GUID we need to create GUID and add it to our DEC file (UefiLessonsPkg/UefiLessonsPkg.dec
):
[Guids]
...
gHIIStringsCGuid = { 0x8e0b8ed3, 0x14f7, 0x499d, { 0xa2, 0x24, 0xae, 0xe8, 0x9d, 0xc9, 0x7f, 0xa3 }}
To reference it in our code we should declare it in the application INF file as well. Add this to our UefiLessonsPkg/HIIStringsC/HIIStringsC.inf
file:
[Guids]
gHIIStringsCGuid
For this GUID to be included we also need to add UefiLessonsPkg/UefiLessonsPkg.dec
in the Packages
section:
[Packages]
...
UefiLessonsPkg/UefiLessonsPkg.dec
As each of the HII protocols can have only one instance in the system, there is a library that abstracts all the LocateProtocol
logic in its constructor and fills global variables for protocols (https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Library/UefiHiiServicesLib):
EFI_HII_STRING_PROTOCOL *gHiiString // UEFI HII String Protocol
EFI_HII_DATABASE_PROTOCOL *gHiiDatabase // UEFI HII Database Protocol
EFI_HII_CONFIG_ROUTING_PROTOCOL *gHiiConfigRouting // UEFI HII Config Routing Protocol
EFI_HII_FONT_PROTOCOL *gHiiFont // UEFI HII Font Protocol
EFI_HII_IMAGE_PROTOCOL *gHiiImage // UEFI HII Image Protocol
So instead of using this in our last application:
EFI_STATUS Status;
EFI_HII_DATABASE_PROTOCOL* HiiDbProtocol;
Status = gBS->LocateProtocol(&gEfiHiiDatabaseProtocolGuid,
NULL,
(VOID**)&HiiDbProtocol);
if (EFI_ERROR(Status)) {
Print(L"ERROR: Could not find HII Database protocol: %r\n", Status);
return Status;
}
We could simply include UefiHiiServicesLib
to the app INF file and use gHiiDatabase
instead as a EFI_HII_DATABASE_PROTOCOL*
.
Let's use UefiHiiServicesLib
in our current app. For this add UefiHiiServicesLib
to the Library classes in the UefiLessonsPkg/HIIStringsC/HIIStringsC.inf
:
[LibraryClasses]
...
UefiHiiServicesLib
Also we need to include this library package DEC file in the application INF:
[Packages]
...
MdeModulePkg/MdeModulePkg.dec
Finally add necessary include to our *.c file UefiLessonsPkg/HIIStringsC/HIIStringsC.c
:
#include <Library/UefiHiiServicesLib.h>
Here is a starting template for our application. We cheat a little bit here as we don't calculate size for our Package list, but use some number bigger that we would actually need in this example. This lesson is splitted in many parts and is hard enough as it is, I don't want to complicate things even more, so take my word on it that this size would be enough for the thing we are about to do:
CHAR8* Data = (CHAR8*) AllocateZeroPool(200); // CHEAT! NEEDS CORRECTION FOR YOUR OWN PACKAGES!
UINT32 offset = 0;
EFI_HII_PACKAGE_LIST_HEADER* PackageListHdr = (EFI_HII_PACKAGE_LIST_HEADER*)&Data[offset];
PackageListHdr->PackageListGuid = gHIIStringsCGuid;
offset += sizeof(EFI_HII_PACKAGE_LIST_HEADER);
<...> // Fill String Packages in the memory starting from &Data[offset]
offset += <...> // Add packages size to the 'offset' variable
EFI_HII_PACKAGE_HEADER* HIIEndPackageHdr = (EFI_HII_PACKAGE_HEADER*)&Data[offset];
HIIEndPackageHdr->Type = EFI_HII_PACKAGE_END;
HIIEndPackageHdr->Length = sizeof(EFI_HII_PACKAGE_HEADER);
offset += sizeof(EFI_HII_PACKAGE_HEADER);
PackageListHdr->PackageLength = offset;
<...> // Add new package to the HII Database
FreePool(Data);
Off course don't forget to add include for using memory allocation functions:
#include <Library/MemoryAllocationLib.h>