UEFI News and Commentary

Tuesday, October 06, 2009

UEFI HII (Part 3)


The UEFI Human Interface Infrastructure (or HII) provides a means for drivers provided by 3rd party hardware and software vendors to expose their configuration settings. Then, a browser or provisioning application can store, restore or change those configuration settings. The configuration settings are encoded as packages. There are several different types of packages defined in the UEFI specification: fonts, strings, images, animations and, most importantly, forms. Each package has the following header:

typedef struct {
  UINT32 Length:24;
  UINT32 Type:8;
//UINT8 Data[…];
} EFI_HII_PACKAGE_HEADER;

This structure contains both the package Type (font, form, image, etc.) and the package Length (including the header), in bytes. Each driver can group these packages (called a package list) and install them in the HII Database using NewPackageList(). Then later an application can find them and display them. The package list has the following header:

typedef struct {
  EFI_GUID PackageListGuid;
  UINT32 PackagLength;
} EFI_HII_PACKAGE_LIST_HEADER;

So that leaves two big questions:
  1. How do you create the packages and package lists?
  2. How does the driver find them?
Well, the first question is a bit tricky and each BIOS vendor probably answers this question differently. The EDK (published by Intel at http://www.tianocore.org/), uses a script language called Visual Forms Representation (or VFR) that is compiled down into IFR. It also specifies strings in special .UNI files, which associate a label with a string and language. At the end of the day, these different package types get built into a binary. And that binary can be packaged four ways:
  1. Built-Into The Driver. In this method, a tool takes the bytes that make up the package list and generates an assembly-language (.ASM) source file, which is then linked together with the rest of the driver. This method makes it easy to find the package list, since it has a normal label that resolves during the linking process.
  2. Separate File. With this method, the binary is packaged up as a normal firmware file with a special file type or, more commonly, a special file name. The driver then searches the firmware volume in which it resides for a file with the special name, loads it into memory and then gets a pointer to the first byte. This method takes a little more work, but it allows the package list to be generated separately. Since the package list can be easily located, it can then be edited at some point after the driver has been compiled but before the final flash image is created. This is very useful when you want to process the package lists without ever touching the source code. For example, if your driver ships supporting 30 languages, but you only have ROM space for 3, you could either recompile the driver or you could just edit the binary information. Or perhaps you want to allow a downstream VAR to substitute their logo for the generic logo. By making the binary form of the package list easy to locate, these changes can be made easily. This method also allows files to be on separate media, such as a disk.
  3. Same File, Separate Section. This method is similar to the method described above, in that the binary information is packaged separately from the EXE. However, here, the binary is included as a separate section in the same file. The Firmware File Specification (either the older Intel Tiano version or the newer UEFI PI version) allows certain file types to be broken up into sections. One section contains the driver itself and, in this case, another section contains the package list. This shares many of the advantages of the previous method, but creates a direct association between the driver and its related forms, fonts, strings and images.
  4. Same File, Resources. This method embeds the binary into the EXE portion of the file as a resource with the resource type "HII" (see the LoadImage()). When LoadImage() runs, it looks for the resource and, if its is found, installs a protocol on image's handle with the GUID EFI_HII_PACKAGE_LIST_PROTOCOL_GUID that contains a pointer to the package list. A driver uses HandleProtocol on its own image handle to find a pointer. This has an advantage over the previous methods in that it does not require a UEFI PI image or the firmware file system. So therefore it is suitable for pure UEFI drivers or drivers that are loaded from a plug-in card's option ROM.
After finding the resources, the driver simply passes a pointer to the package list into NewPackageList().

Next time we'll look in greater detail at the different types of packages, starting with the strings.

1 comment:

Unknown said...

Hi,

I am trying to present Hii interface to the user during boot time.I have an ASUS Z67 motherboard with UEFI.I can create blank UEFI driver with Hii and in nt32 shell Iam able to see the formset. But I am looking for how to do the same in UEFI BIOS