UEFI News and Commentary

Sunday, December 06, 2009

UEFI HII (Part 7): Character Encoding

How do you know that the character 'A' corresponds to the character value 0x0041? Or that character value 0x215d is the character '⅝'? Well, standard, such as ASCII or the Unicode standard (or, going further back EBCDIC) describe the mapping between a numeric value and a specific characer.

But how to convert those numeric values into actual bits and bytes? 7-bits, 8-bits, 16-bits, 32-bits? And if more than one byte, is it big-endian or little-endian? That conversion process is called encoding.

I have the Unicode 1.0 specification sitting on my shelf. At that time, there was some optimism that all the character values that anyone would ever need could be contained in 16-bits: 65,536 character values. But even then, there were some signs that people were inventing and had invented many more character glyphs than could be contained. For example, in some scripts, individual cities had their own glyphs. And what about the Mahjong tile characters (0x1F000-0x1F002b)? So, prior to the Unicode 2.0 specification, the predominant form of encoding (known as UCS-2) embodied this 16-bit assumption.

But prior to that point, many operating systems (such as Windows NT) and firmware specifications (such as EFI 1.10) had taken root. While most operating systems have since migrated to the preferred encoding standard (UTF-16), which can handle the full set of Unicode character values, the UEFI specification still retains UCS-2.

So what is the big difference between UCS-2 and UTF-16? They are both 16-bit encoding schemes. For all the character values we care about, they are identical. Most of these characterThe real difference comes in how they handle character values beyond 0x10000 (that is, beyond character 65,536).

For UCS-2, these characters don't exist. There is no proper way to encode charcter 0x10001.  For UTF-16, characters values more than 0x10000 are encoded by combining two adjacent 16-bit characters. No one was particularly happy about this solution, since it took everyone back into the multi-byte character encoding nightmare that had plagued so many previous standards attempts (Shift-JI1, GB5, Windows code pages, etc.). But the alternative was to require a 32-bit unsigned integer to represent the characters, which would add a lot of bloat. But the advantage of this technique was that only a limit range of character values could appear as the first half of a surrogate pair (0xD800-0xDBFF) and another limited range of character values could appear as the second half (0xDC00-0xDFFF).  To calculate a character value, you take 6 bits from each and add 0x10000 to the result. This gives you a range of possible character values between 0x0000000-0xFFFFFFF. By separating the surrogate pair values in to first-half and second-half allowed string processing functions to work no matter where in the string they started from and which direction they processed the string. For more information, you can read the FAQ at the Unicode site.

But, for the purposes of the UEFI specification, those surrogate pair character values have no special meaning and would each be treated as a separate character. That is, 0xD800 0xDC00 would be a single character in UTF-16, but two characters under UEFI and UCS-2.

The UEFI specification does use another range of characters with special meaning defined in the Unicode specification: the Private Usage Areas. The Private Usage Area, which is a range of character values from 0xE000-0xF7FF) is left open to use by an application. In UEFI, these are used for embedding font control information directly into strings. The values 0xF620-0xF62B control turning specific font styles, such as bold, italics, etc. The values 0xF700-0xF7FF are used to select a specific font. The values 0xF800-0xF8FF select a font of a specific cell height. These values will never occur in normal text.

For more information on these character values, as well as others given special treatment in UEFI, see section of the UEFI 2.3 specification.

Next time we'll continue by looking at the characteristics of Proportional Fonts.

Saturday, November 28, 2009

UEFI HII (Part 6): Simple Fonts

Prior to to UEFI 2.10, there was only one graphics display mode: 800 x 600 x 32-bit color depth. Those numbers still show up as a required mode for external plug-in graphics adapters. But what if you want to draw text on those graphical displays? Where does the font come from? How big is it? Does the font really hold all 40K+ characters from the Unicode specification?

According to the EFI (and then UEFI), the system firmware was required to carry the ISO Latin-1 charcters (essentially characters U-0020 through U-00FF in the Unicode specification) as well as the line drawing characters. But that still leaves the question: how big are the bitmaps (or glyphs) in the font?

For a long time, prior to the UEFI 2.10 specification, the answer was 8 pixels wide and 19 pixels high. With a little math, you find that this works perfectly to put 80 columns and 25 rows of text on a 640 x 480 pixel display. That number of pixels, in turn, happens to be the highest resolution that could be produced by a standard VGA adapter. However, a character cell of 8 x 19 is not large enough to hold many of the glyphs found in other scripts, most notably Chinese, Japanese and Korean. So, in addition to the narrow 8 x 19 pixel character cells, a wide 16 x 19 pixel character cell was also supported.

One of the design goals for HII, back when UEFI 2.10 was being crafted, was the support for bitmapped, proportional fonts. But rather than throw away the previous way that font glyph encoding, the previous method was added as another package type: Simple Fonts (type 0x07).


Narrow glyphs consist of a header, followed by 19 bytes. Each of the bytes represents one row of the glyph. Byte 0 represents the top of the glyph and byte 18 represents the bottom of the glyph. Each bit in those bytes represents a single pixel, with a value of zero being off and a value of one being on. Bit 0 is the left-most pixel and bit 7 is the right-most pixel.

Wide glyphs consist of a header, followed by 38 bytes. Essentially they are encoded as two narrow glyphs, first the left half 8 x 19 image, followed by the right half 8 x 19 image.

The Simple Font package consists of the standard package header, a bit of housekeeping data and then an array of narrow glyph information, followed by an array of wide glyph information.
Each of the narrow glyphs has a small header, followed by the encoded glyph data.

      UINT16           NumberOfNarrowGlyphs;
      UINT16           NumberOfWideGlyphs;
      EFI_NARROW_GLYPH NarrowGlyphs[];
      EFI_WIDE_GLYPH   WideGlyphs[];

Next week, we'll look at normal fonts.

typedef struct {

  CHAR16 UnicodeWeight;
  UINT8  Attributes;

The Attributes indicate whether the glyph is narrow or wide and whether the character value is non-spacing. Normally, after drawing a character, the position of the next character would be directly to the right. For non-spacing characters, the next character would be drawn in exactly the same character cell. This allows, for example, the ` or ~ character to act as combining diacritical marks so that, when printed prior to an a or n, would display as á or ñ.
Each of the wide glyphs has a small header followed by the encoded glyph data:

typedef struct {

  CHAR16 UnicodeWeight;
  UINT8 Attributes;
  UINT8 Pad[3];

Multiple Language Support
Let's say I'm designing a plug-in card and I want to support Chinese. But I don't know whether or not the system firmware in the platform where my card is installed supports all the Chinese characters (glyphs) that I need. What can I do? Well, with UEFI 2.10, your driver can just carry the characters you need that are in addition to those provided by the ISO Latin-1 characters that the platform is required to carry in its firmware. The HII Database will automatically combine glyphs from fonts which have the same font family, size and style.
Using The Simple Font
The simple font can be accessed, like all other fonts, through the HII Font protocol. The simple font has the name 'system' and has a height of 19 pixels.

Friday, November 13, 2009

Harnessing The UEFI Shell Book

Ok, a little promotion for the book I co-wrote, which is finally for sale. We finished writing it over 6 months ago. Not that most of you are going to run out and write UEFI Shell apps. But if you were...


Monday, October 26, 2009

UEFI HII (Part 5): Strings API

Last time we learned that strings in a specific language are grouped together in packages and packages are grouped together in package lists. Strings not only have text and a language, but they also have an associated font, font size and font style.

To get to a specific string, you need three things: the package list handle (EFI_HII_HANDLE), the string identifier (EFI_STRING_ID) and the language. Since you are normally using the platform's current language, you generally don't have to worry about that and use the default setting.

There are two sets of string-related protocols: (a) those which add, modify and remove strings from the HII Database and (b) those which create a bitmap using the strings text.

With EFI_HII_STRING_PROTOCOL, you can create new strings, retrieve the string's text, change the string's text and find out which languages are supported.
  • NewString() lets you create a new string within a specific package list and returns back a new string identifier. You can specify (if you want), the language and the font information. If you don't specify the language, the platform's current language is used. If you don't specify a font, then the platform's standard font is used.
  • GetString() retrieves information about a specific string, including the string's text and the associated font. If you don't specify the language, the platform's current language is used.
  • SetString() changes information about a specific string, including the string's text and (optionally), the string's font information. If you don't specify the language, the platform's current language is used.
  • GetLanguages() reports the languages that are supported by a specific package list.
  • GetSecondaryLanguages() reports the regional versions of a specific language supported by a specific package list. For example, if you passed in "en", it might return "en-US", "en-UK" "en-PH" if there were specific translations for those regional variations in English.
The EFI_HII_FONT_PROTOCOL deals with fonts and we'll return to that subject in a later article, in all its proportional font glory. Right now, we'll just focus on the two functions which deal with strings:
  • StringToImage() draws a string's text onto a bitmap or the screen at a specific location. If the font is not specified, then the platform's standard font is used instead. If the language is not specified, then the platform's current language is used.  This function also allows you to clip the text to a rectangle in a variety of ways, wrap the text, draw transparently and handle multi-line text. Even more useful to sophisticated users, it also reports the positioning of each character in the string in the bitmap so that user-interface code can use it for cursor movement and mouse selection.
  • StringIdToImage() does the same thing, except that you pass in a string identifier and a package list handle.
Next time we'll start looking into the wonderful world of bitmapped fonts.


Thursday, October 15, 2009

UEFI HII (Part 4): Strings

Up to this point, we've discussed the HII Database and how individual drivers can contribute resources (strings, fonts, images, forms, etc.) in the form of packages to that database. Groups of packages are called package lists. Later the form browser extracts these package lists from the database to use in constructing the user interface for platform configuration and other user-interface tasks.

One type of package that drivers can contribute to the HII Database is the strings package. A string package is a collection of strings associated with a specific language. Each string has a number (called the string identifier) that uniquely identifies it within the package list, and default font information, such as font name, size and style.

Each string package only contains text in one language. For example, one string package contains English (U.S.), another Korean, another Pilipino and another French. By separating the languages into separate string packages, it is easy to delete support for a particular language: just delete the associated package.

The UEFI firmware maintains the system user-interface language information in two special EFI variables:
  1. PlatformLangCodes. The list of languages that the platform supports.
  2. PlatformLang. The current platform language.
These EFI variables are also used by other UEFI protocols, such as the EFI Driver Configuration protocol, the EFI Driver Diagnostics protocol, the Component Name protocol and the Unicode Collation protocol.

Languages are encoded according to RFC 4646, which specifies two and three letter codes for each language, along with additional modifiers representing a specific geographic location. For example:
  • en-US (English, United States)
  • fr (French)
  • fr-FR (French, France)
  • zh-CN (Chinese, mainland China)
  • sr-CS (Serbian, Serbia/Montenegro)
The rules by which a form browser might substitute an alternate language (say, Portuguese from Portugal if there was no Portuguese from Brazil, or English if there was no French), is specific to the implementation.

It is possible to find out which languages are supported by iterating through all of the package lists in the system (using ListPackageLists()) and then using GetLanguages() and GetSecondaryLanguages().

Each string is associated with a specific font family, font size and font style. The form browser may choose to use this information, ignore it completely or substitute a similar but different font. So this font information might be considered more of a suggestion, rather than a command. In many cases, firmware implementations may use this information to cull the fonts that are included in the BIOS ROM (for space reasons) so that the font only contains the characters used.

The HII-related protocols (such as HII Font or HII String) will use the font information associated with the string to select the display font unless an alternate is provided by the caller.

There are three font attributes associated with each string.
  • Font Name. The font name the family of font (Arial, Helvetica, Times Roman, Courier), which identifies, in broad terms, the visual style of the font.  
  • Font Size. This is the cell height, in pixels. To give some perspective, the "standard" UEFI font size is 19 pixels high.
  • Font Style. The font style indicates how the basic font should be modified. The following styles can be described: bold, italic, emboss, outline, shadow, underline and double-underline.
If the form browser does not have access to the exact font specified by a string, it might substitute a different font or it might synthesize using an algorithm. An example of substitution would be using Helvetica instead of Arial. An example of sythesizing would be if a doubled 12-size font were used for a 24-size font or if the italic style were simulated by shifting the successive lines of a glyph over by one pixel so that it would slant.

Strings are uniquely identified in the system by a string identifier (EFI_STRING_ID), a package list handle (EFI_HII_HANDLE) and a language. If the system's display language is English ('en-US') and you ask for string #1, you would get string #1 from the English string package. If the system's display language is French ('fr') and you ask for string #1, you would get string #1 from the French string package. Likewise, for Japanese ('jp'). As a rule, UEFI drivers don't hand around pointers to null-terminated strings. Instead, they pass around string identifiers and package list handles.

Can you actually examine and modify the text? Of course. GetString() retrieves the actual text and SetString() lets you modify it. NewString() let's you create a brand new string, with a unique string identifier.

Each string package begins with the standard header (EFI_HII_PACKAGE_HEADER) with the Type set to EFI_HII_PACKAGE_STRINGS. Following the standard header is the string-package-specific header:

typedef struct _EFI_HII_STRING_PACKAGE_HDR {

  UINT32 HdrSize;
  UINT32 StringInfoOffset;
  CHAR16 LanguageWindow[16];
  EFI_STRING_ID LanguageName;
//CHAR8 Language[ … ];

The actual string data begins at StringInfoOffset bytes from the start of this structure. The LanguageWindow array is used for setting up the default "windows" used for the compression algorithm. More on this later. Language is the RFC 4646 null-termined language string which identifies which language this package is for. For example, "en-US" or "fr" or "jp". LanguageName is the string identifier of the string that gives the user-readable name of the language this package is for. For example, "English" or "French" or "Japanese" These can be used when presenting choices to a user.

The string information consists of a series of records, which can be broken down into three categories:
  1. String Records. These records assign the current string identifier value to specific string text .
  2. Identifier Records. These records change the current string identifier value.
  3. Font Records. These records describe the fonts used by later strings.
String Records
String records are broken down into three types:
  1. Use compressed text or uncompressed text. Text can be compressed using the Standard Compression Scheme for Unicode (SCSU), which is described in Unicode's Technical Report #6. Optimized for reducing the number of bytes required to describe Korean, Japanese and Chinese characters, this scheme uses the concept of "windows" of 127 characters than can be selected for a sub-string of characters. The default settings for these windows are specified in the report. But they can also be optimized for the exact strings in the package by altering the values in the LanguageWindow array in the header. Uncompressed text is simply listed as a null-termined UCS-2 string.
  2. List single string or multiple strings. Strings which have string identifiers which are sequential can be listed in a single record. Or a single string can be listed.
  3. Use the default font or a specific font. Strings which use the default font require fewer bytes to encode because the font is implied.
  4. Use text provided or duplicate text. One of the record types simply implies that the text for the new string is a copy of the text for a string which was previously defined.
As mentioned before, strings are associated with a specific font. However, the fonts can be changed in the middle of a string using a series of special control characters. The character values used are marked as "implementation-specific" in the Unicode specification:

For example, characters 0xF7xx (where xx is the font identifier assigned by a font record, below) can be used to switch fonts. Characters 0xF8xx (where xx is the font size) can be used to change just the font's size. Characters 0xF620 and 0xF621 turn bold on and off. Characters 0xF622 and 0xF623 turn italic on and off. Characters 0xF624 and 0xF625 turn underline on and off. Characters 0xF626 and 0xF627 turn emboss on and off. Characters 0xF628 and 0xF629 turn outline on and off. Characters 0xF62A and 0xF62B turn double underline on and off.

Identifier Records
Identifier records are used to adjust the current string identifier value without assigning any string text. This can be useful when there are gaps in the string identifiers. When processing the string records, the current string identifier is always set to 1 and is incremented each time a string record is processed. So, normally, the first string is assigned identifier #1, the second #2, etc. But if the identifiers are not sequential (i.e. 1,2, 16) you can use a skip record so that after the second string, you just skip the next 13 identifiers.

Font Records
The font records must appear before the first instance of a string that uses them. The exception for this is the "default" font which is initialize to the system's default font. Each font is assigned a number that is only valid within the package, starting with 0 (for the default font) and going upwards. That means there is a theoretical maximum of 256 fonts used wihtin a string package. In addition to the identifier, each font has the usual attributes (name, size, style).

Strings are an important part of any user-interface. The ability and the flexibility to display strings in multiple languages, using a variety of font styles, sizes and families is important in making a rich user interface.

Next time, we begin to delve into the wicked world of HII fonts.

Tuesday, October 13, 2009

UEFI @ Intel IDF.

I just saw that they posted publicly the information from Intel's IDF, including the UEFI track, here. You can see a number of interesting articles from the industry heavyweights, like Dell, IBM, Microsoft and Intel. Not to mention the co-authors of a book (Vincent Zimmer, Mike Rothman) about the UEFI Shell. Good reading.

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[…];

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;

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.

Saturday, October 03, 2009

Phoenix Demos 1 Second UEFI Boot

Several news sources have posted coverage of IDF 2009, where Phoenix (that's who I work for) booting a UEFI-based system in 1+ seconds and Windows 7 in 7-10 seconds. You can read about it (for example) here.

The UEFI Shell: Moving The Platform Beyond DOS

Hey, just a plug for a book that I co-wrote with three other UEFI experts (Mike Rothman, Vincent Zimmer and Bob Hale) about the UEFI Shell. You can read an excerpt from the book on the Intel Press web site here.

Saturday, September 26, 2009

UEFI HII (Part 2)

This week, we will look at some of the key elements of the Human Interface Infrastructure portion of the UEFI 2.1 and later specifications. UEFI platform firmware provides two key facilities:
  1. The HII Database. The database acts a repository for all sorts of configuration and user-interface resources, including forms, fonts, strings, images, animations, and keyboard layouts. The platform and individual drivers can install and remove these resources.
  2. The HII Forms Browser. The browser is the platform-provided user interface where the forms are displayed and input from the user is taken in order to update configuration settings.
The platform firmware decides when the user interface should be displayed. This is different from legacy BIOS and UEFI 2.0, where individual option ROMs could put up their own user interface elements, provide their own boot hot keys for entering those utilities and delay the boot in order to display instructions and copyright information. Now, with UEFI 2.1 and beyond, the individual drivers provide user interface information to the platform and the platform presents it to the user.
In most implementations, the decision about when is controlled by the UEFI Boot Manager. The how might be part of the boot manager itself or a separate driver or application. Why? The boot manager is already responsible for hot keys for launching boot options and applications. The boot manager is also responsible for the UEFI driver health support and the UEFI user identification support, both of which can be user-interface intensive and are heavily involved with the boot process.
For drivers, the most important API is the EFI_HII_DATABASE_PROTOCOL. Normally, during driver initialization (if one page manages all driver-supported devices) or during Start(), the driver will install the forms and strings that it will use for configuration, driver health and user identification using NewPackageList().
The next important API for drivers is the EFI_HII_CONFIG_ACCESS_PROTOCOL, which is provided by the driver to handle configuration-related behaviors. This protocol provides three important functions:
  1. ExtractConfig(). Return the current configuration settings.
  2. RouteConfig() . Change the current configuration settings.
  3. Callback(). Handle callbacks while the user is interacting with the forms.

That's it. The driver publishes forms and strings and provides a way to read and write configuration values and handle callbacks from the forms. Of course, there's a lot more in the nitty-gritty details and we'll dig into that soon.

But next, week we will spend a little time on how the resources are put together and delivered to the HII Database and even OS-present applications.

Wednesday, September 23, 2009

UEFI HII (Part 1)

Starting with version 2.1, the UEFI Specification began to describe a standardized way in which firmware could communicate with a user or application concerning firmware-related settings. Previously, the EFI 1.10 specification had the EFI_DRIVER_CONFIGURATION_PROTOCOL, which provided a means by which driver could take control of the console and throw up their own configuration screens. This mechanism provided a great deal of flexibility. The platform firmware could provide its own instance of this protocol for motherboard components and each of the 3rd party drivers, such as those on plug-in cards, could provide an instance also. A platform firmware application could list out these instances for a user to choose from. But this decentralized approach led to other problems. It meant that:
  1. There was no consistent look-and-feel for a platform, since each driver got to pick its own color scheme, its own keyboard commands and its own screen layout.
  2. Individual drivers had to make assumptions about the type of input and output devices available. For example, some platforms might have five buttons and a two line 25 character LCD display while others might have BitBlt graphics and input-method editors. 3rd party drivers would have to invest a lot to make their drivers work on a wide range of consoles.
  3. There was no means of centralized platform configuration (for provisioning or remote management). For example, if I wanted to save the settings from one platform and use those to configure a brand-new bare-metal platform. How to get ahold of the settings and apply them in a uniform fashion?
In order to address these issues, the UEFI 2.1 specification introduced the Human Interface Infrastructure (HII), which was designed to give the platform firmware centralized control over how input, output and configuration were managed. HII includes everything from fonts, bitmaps, forms to the routing of configuration information between the system and drivers. There were several goals when we created HII. These included:
  • Localization. Localization is the process by which a product is adapted to a local market. Most significantly for platform firmware, this includes display languages and input languages.
  • Forms. Forms provide the abstraction by which drivers expose the configuration settings to the platform firmware.
  • Remote and Off-Line and OS-Present Configuration. The configuration settings for a platform must be exposed in such a way that an implementation could support a variety of alternate ways to configure the platform. For example, remote scripting, remote interactive, semi-interactive (off-line but with forms) or OS application-driven configuration of the platform.
  • Provide APIs which would allow drivers, including those on plug-in cards to have full access to the HII resources, including fonts, strings and forms, and be able to contribute additional resources.
  • Support a wide-range of display devices.
This led to a fairly sophisicated and flexible infrastructure and a lot of confusion, because in many places the HII specification added abstractions between display, configuration and configuration storage that had never existed before in the firmware world. Next week, we'll look at some of the key design decisions and why they were made.

Tuesday, September 22, 2009

UEFI Shell: Profiles

Last time, I discussed how the UEFI Shell can come in four basic flavors, called support levels. Level 0 was the most basic, supporting almost all of the API, but none of the scripting language and no user interface. Level 1 added basic scripting. Level 2 added file manipulation scripting. Level 3 added user-interface related scripting. Ok. So now we have a robust shell. But it can't do very much. In a manufacturing environment, it is important that software developers, including those who write provisioning and management scripts for systems, be able to depend on other types of commands, such as those which connect to the network stack or those which provide debug capabilities. If my script depends on these commands being present, how can I detect or even automatically correct such a situation? Enter Shell Command Profiles. A Shell Command Profile is a group of related commands that have a name. Names are made up of numbers, letters and the underscore ('_') character. Profile names that start with a '_' are reserved for usage by 3rd parties. Profile names that start with a letter or number are reserved for use by the UEFI Shell specification. The names of all profiles are stored in the environment variable "profiles" and are separated by the semicolon (';') character. This environment variable is initialized based on (a) the profiles that are built into the shell executable itself and (b) a file named "profiles.txt" that exists in the same directory as the shell executable. A script can determine which profiles are installed by searching this environment variable for the name of a specific profile. For example: if not Profile("Network1") then echo Required script command profile "Network1" not found. exit /b 1 endif The Profile() operator searches the "profiles" environment variable for the one specified and returns 1 if it is found or o if it is not. The UEFI 2.0 Shell Specification supports four standard profiles:
  • Driver1. Standard set of driver-related commands. This includes connect, devices, devtree, dh, disconnect, drivers, drvcfg, drvdiag, reconnect and unload.
  • Debug1. Standard set of debug commands. This includes the following commands: bcfg, comp, dblk, dmem, dmpstore, edit, eficompress, efidecompress, guid, hexedit, loadpcirom, mem, memmap,mm, mode, pci, sermod, setsize and smbiosview.
  • Network1. Standard set of networking-related commands. This includes ifconfig, ipconfig, and ping.
  • Install1. Standard set of commands to aid installation. This includes only bcfg.
Shell profiles provide an extensible method for creating standard groups of commands that can be relied up by 3rd party applications. Next Time: The UEFI Shell API.

Monday, September 07, 2009

UEFI Shell: Levels of Support

The UEFI shell comes in four flavors, called levels of support. These "levels" (from 0 to 3) allows for compliant implementations of the shell that range from light-weight, bare-bones to a full-featured versions. At the same time, the user of the shell can determine, at run-time, whether the necessary features are available for it to run correctly. Why offer different levels of support?
  1. Size. While the rest of the universe expands storage capacity exponentially, the firmware world still lives with relatively expensive flash devices. Suffice it to say that the types of flash and trends in flash which are driving down the cost for devices such as the iPod are a little slower in dropping the average price of motherboard flash. Flash size can significantly impact the cost of a motherboard. So there is constant pressure to keep the "required" elements of the firmware as small as possible. NOTE: One additional trend is that silicon vendors such as Intel are gobbling up room on the flash devices as well, both with their own firmware modules and with support for on-board micro controllers such as the ME (Management Engine). In some systems, 2/3 of the flash space is consumed by support for these devices. So the shell in the firmware must be small.
  2. Video & Keyboard Support. When most of us think of a "shell" we usually think of some sort of command-prompt console at which a user can type in commands, execute scripts, etc. However, in many of the systems, the shell is used primarily for execution of scripts or applications that do not require a console at all.
So the UEFI shell can provide any of 4 standard support levels:
  • 0 (Minimal). This is the most basic support. The APIs are fully supported, but there is no support for scripting, aliases or a console. Normal shell applications will execute.
  • 1 (Scripting). This level adds support for scripts and the script control commands, but none of the other commands that do anything (such as write text to the screen or manipulate files). This allows scripts to be launched, but all of the script commands must be executables (.efi files) on a mapped drive.
  • 2 (Basic). This level adds file script commands, such as rm, ls and mkdir. At this level, there is still no console support. As a result, those commands which would normally output to the console do not do so at this support level. Notice that, up to this point, an application could use the APIs to read and write files, but not execute scripts which used the common file manipulation commands.
  • 3 (Interactive). This level adds console input and output, as well as those script commands which depend on the console, such as echo, type and cls.
The support level provided by the UEFI shell can be checked by any script or application by examining the environment variable shellsupport which contains the text "0" for Level 0, "1" for Level 1 and so on. Next week we'll look at how support provided by the shell can further be augmented in a standard way using "profiles". Tim

UEFI Updates Specification Roadmap.

Hey, just noticed that UEFI has officially updated their roadmap here. For me, the big questions revolve around SCT support for ARM, HII and the user identification and security parts of 2.2 and 2.3. These additions are hefty (clocking in at over 300 pages).