In part 1, we looked at the top-most layer of our disassembler, which retrieved all of the installed resources from the database. The resources are binary-encoded into variable-length data structures called Packages and then grouped together into Package Lists. Part 1 handled the Package Lists and now we will take a look at the Package structure and parsing code.
UEFI HII Packages
The encoding for UEFI HII Packages is deceptively simple: there is a header and then a body. The header describes what type of package it is and its size, in bytes.typedef struct {
UINT32 Length:24;
UINT32 Type:8;
// UINT8 Data[...];
} EFI_HII_PACKAGE_HEADER;
So, likewise, the basic data structure for holding UEFI HII Packages is quite simple:
#define UEFI_HII_PACKAGE_SIGNATURE 0x5F504855 // "UHP_"
typedef struct _UEFI_HII_PACKAGE_P {
SYS_OBJ Obj;
UINT8 Type; // See EFI_HII_PACKAGE_x
UEFI_HII_PACKAGE_LIST_P *PkgList; // package list parent.
SYS_OBJ *PkgData; // ptr to data specific to package type.
} UEFI_HII_PACKAGE_P;
typedef UEFI_HII_PACKAGE_P UefiHiiPackageP;
The Obj member provides the basic object-oriented functionality of the SysLib, including function pointers to initialization, emptying, copying and validity-checking functions.
The Type member matches the Type member of the IFR Package header. There are currently 8 types of packages as well as a GUIDed type for expansion and 32 reserved types for system vendors.
The PkgList member points to the structure that represents the package list which contains this package. If the package was parsed independently, as would happen when disassembling a file containing only package binary-encoded data, this would be NULL.
The PkgData member points to an object that represents the contents of the package. The exact object depends on the Type member. So for forms, this is a pointer to a UEFI_HII_FORM_PACKAGE_P. By using the object pointer, we can handle copying and memory management without knowing the exact structure.
UefiHiiParsePkg()
In part 1, we saw that UefiHiiParsePkgList() walks through all packages in a package list and calls this function to handle actually parsing the package data and converting it into our structure. Essentially this is a factory function which creates a package object. It then uses the Type value to call another parsing function which processes the package body and records the pointer to the resulting data object.EFI_STATUS
UefiHiiParsePkg (
IN EFI_HII_PACKAGE_HEADER *Pkg,
OUT UEFI_HII_PACKAGE *PHandle
)
{
EFI_STATUS s;
UINT8 *PkgData;
UINT32 PkgDataSize;
UEFI_HII_PACKAGE_P *PkgP;
if (Pkg == NULL || PHandle == NULL) {
return EFI_INVALID_PARAMETER;
}
if (Pkg->Length < sizeof (EFI_HII_PACKAGE_HEADER)) {
return EFI_INVALID_PARAMETER;
}
...
PkgP = SysNew (UefiHiiPackageP);
if (PkgP == NULL) {
return EFI_OUT_OF_RESOURCES;
}
*PHandle = (UEFI_HII_PACKAGE)PkgP;
UefiHiiSetPkgType (*PHandle, (UINT8) Pkg->Type);
PkgData = (UINT8 *)(Pkg + 1);
PkgDataSize = Pkg->Length - sizeof (EFI_HII_PACKAGE_HEADER);
switch (Pkg->Type) {
case EFI_HII_PACKAGE_FORMS:
s = UefiHiiParseFormPkg (
(EFI_IFR_OP_HEADER *)PkgData,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_STRINGS:
s = UefiHiiParseStringPkg (
(EFI_HII_STRING_PACKAGE_HDR *)Pkg,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_SIMPLE_FONTS:
s = UefiHiiParseSimpleFontPkg (
(EFI_HII_SIMPLE_FONT_PACKAGE_HDR *)Pkg,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_ANIMATIONS:
s = UefiHiiParseAnimationPkg (
(EFI_HII_ANIMATION_PACKAGE_HDR *)Pkg,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_IMAGES:
s = UefiHiiParseImagePkg (
(EFI_HII_IMAGE_PACKAGE_HDR *)Pkg,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_FONTS:
s = UefiHiiParseFontPkg (
(EFI_HII_FONT_PACKAGE_HDR *)Pkg,
PkgDataSize,
PkgP,
&PkgP->PkgData
);
break;
case EFI_HII_PACKAGE_DEVICE_PATH:
s = EFI_SUCCESS;
break;
case EFI_HII_PACKAGE_END:
s = EFI_SUCCESS;
break;
default:
s = EFI_INVALID_PARAMETER;
break;
}
if (EFI_ERROR(s)) {
SysDelete (PkgP);
}
return s;
}
No comments:
Post a Comment