UEFI News and Commentary

Friday, March 24, 2017

Sample Chapter From Beyond BIOS

My friends Zimmer and Rothman, co-authors with me on Harnessing the UEFI Shell have also recently released an updated version of their definitive work on UEFI, Beyond BIOS, with Suresh Marisetty. They have been driving forces in the UEFI standardization process from the beginning and their expertise shines through here.

Don't believe me? Well, take a look at a free sample chapter from the book and the table of contents.

Tuesday, March 21, 2017

Harnessing The UEFI Shell, 3rd Edition Now Available.

The 3rd edition of our book (co-written with Mike Rothman and Vincent Zimmer at Intel) is a substantial update, incorporating the latest from the UEFI Shell specification 2.2. It includes updates on security and how-to sections on UEFI shell applications and scripts. Before the OS starts, the UEFI Shell is small, fast and light-weight manufacturing, provisioning, diagnostics and configuration environment. Go pick up a copy here.

This follows up on the revised edition of another great UEFI book, Beyond BIOS, that came out last month. Between, they serve as an unrivaled introduction into all things UEFI.

Sunday, February 19, 2017

The UEFI Maze Game, Part 4

This is the fourth part of our series on a simple maze game built as a UEFI shell application. The first three parts discussed the main application, game loop and maze generation. This time, I will focus on UEFI's Graphics Output Protocol (GOP) and loading and decoding bitmaps from files.

The first part searches for the instances of the Graphics Output protocol in the system, chooses the one where the maze will be displayed and stores a pointer to it in a global variable.

Figure 1 - Find the Graphics Output Protocol, Bitmap.c

Line 25-35

Find all instances of the Graphics Output protocol that are available in the system. There can be one instance per graphical device in the system. Each one of the instances can be set to a different resolution and support a different number of colors. Rather than requiring the application to manage all of the devices, most systems use the Console Splitter driver, which acts as a meta-driver, aggregating the information from all of the drivers and drawing all bitmaps on all displays. The LocateHandleBuffer() function in the UEFI Boot Services allocates a buffer to hold all of the handles that support a specified protocol. 

Lines 37-46

Now that we have found handles for all drivers that support the Graphics Output protocol, we examine each handle to see if it also has an instance of the Device Path protocol. Why? Because the one way to distinguish the Console Splitter from all other graphical devices in the system is that it is not actually a hardware device. Since it is not a hardware device, it does not have a Device Path protocol associated with it, since the Device Path protocol used to describe how a device is attached to the system. If we find a handle that doesn't have an instance, the pointer to that instance of the Graphics Output protocol is saved in a global variable.

Lines 47-53

Now we just have to clean things up and return. First, we free the buffer that the system allocated when we called LocateHandleBuffer. Then, we check whether we found a Graphics Output protocol instance that meets our need and return TRUE if we did and FALSE if we did not.

Now, in the next section, we're going to dive into the meat of converting a buffer formatted as a Bitmap (BMP) into a format that can be used with the Graphics Output protocol.

Figure 2 - Converting .bmp Files to Graphics Output format, Bitmap.c

Lines 73-83

On entry, this function takes a buffer that is formatted following the BMP format (see here for more information), along with its size. On output, this function returns a pointer to an array of pixels (GopBlt), the size of that buffer in bytes (GopBltSize). The pixels are divided into PixelHeight rows, with each row containing PixelWidth pixels. Each of the output pixels is formatted as a EFI_GRAPHICS_OUTPUT_BLT_PIXEL structure. This structure has 8 bits for red, green and blue, and 8 reserved bits, making 32-bits per pixel.

Lines 85-98

These are the local variable declarations. BmpHeader and BmpColorMap are pointers to structures that are part of the BMP specification. The EDK2 implementation stores these structures in MdePkg\Include\IndustryStandard\Bmp.h.

Lines 100-104

A simple sanity check makes sure that the buffer passed in at least has the number of bytes required to hold the standard BMP format header structure. 

Figure 3 - Perform Sanity Checks on the BMP Header, Bitmap.c

Lines 106-108

Another basic sanity check is so see if the first couple of bytes in the file have the signature 'B' and 'M'. 

Lines 110-123

This function doesn't support all of the various sub-formats described in the BMP specification. For example, it doesn't support any of the compression formats or any of the extended headers.

Lines 125-137

This function then checks to see whether the data is 4-byte aligned, relative to the start of the buffer. Also, the remaining size of the buffer after the header should be equal to the size of the bitmap as specified in the bitmap header.

Lines 139-146

The color map translates bytes in the bitmap buffer portion of the BMP format into actual colors. The pixels in the bitmap are packed as 1-bit per pixel (2 colors), 4-bits per pixel (16 colors), 8-bits per pixel (256 colors) or the default (24-bits per pixel). The color map translates the bits-per-pixel in the bitmap into actual colors. So 0 might be black, but 1 might be blue (not black) and 2 might be green, etc.  

Lines 148-166

The number of pixels determines the size of the color map. So 1-bit per pixel has two possible color map values (0 and 1) while 4-bits per pixel has 16 possible color map values (0, 1...15). If there are 24-bits per pixel, then no color map is needed. The color map appears between the BMP header and the actual bitmap, so the function performs a sanity check to make sure that the color map is the right size.

Lines 168-172

Now the temporary Image and ImageHeader are set to the beginning of the image within the BMP format. Image will be incremented as pixels are processed while ImageHeader remains unchanged.

Figure 5 - Allocate Buffer to Hold Returned Bitmap, Bitmap.c

Lines 174-184

The function determines how much memory will be required to hold the returned bitmap based on the vertical and horizontal dimensions of the image. A sanity check makes sure that this doesn't result in multiplied value that is ridiculously large.

Lines 186-205

If the user passed in a buffer pointer via GopBlt, then try to use that buffer, as long as it is large enough. This improves performance by reusing a buffer, where possible. If it isn't large enough, it returns the EFI_OUT_OF_RESOURCES error to let the caller know the buffer was too small and returns the size that would be required. If the user did not pass in a buffer pointer via GopBlt, then the function allocates a buffer that is large enough. 

Lines 207-208

Now that we have the buffers, and the size, set the return size in pixels.

Lines 210-215

This outer loop cycles through all of the rows in the input image buffer, setting Blt to the first pixel in the output row. 

Line 216

This inner loop cycles through all of the packed pixels in an input image buffer row.

Line 217

Each of the following switch case statements deals with one way of packing pixels into bytes. Each of the case statements is responsible for leaving the loop counter Width and the output buffer pointer Blt in the correct location for the next iteration of the inner loop. 

Lines 218-232

This section handles the case whether there are 8 pixels packed in a single byte in the input image buffer. The loop works through all 8 bits, isolating the pixel value and then translating it to a full GOP pixel value in the output buffer using the color map.

Lines 234-250

This section handles the 4-bits per pixel case, where two pixels are packed into a single byte. Each half of the byte is translated into a pixel in the output bitmap using the color map. There is a special check for the case when there are an odd number of pixels on a line and this is the last byte in the input image buffer.

Lines 252-259

This section handles the 8-bits per pixel case, where a single pixel is packed into a single byte. Each byte is translated into a pixel in the output bitmap using the color map.

Lines 261-268

This section handles the 24-bits per pixel case, where a single pixel is packed into three bytes. No translation is done with the color map, since it is already in full color encoding. 

Lines 270-280

This section handles the case when the bitmap header specified anything other than 1, 4, 8 or 24-bits per pixel. In this case, buffers are freed and an error status code is returned. 

Lines 284-291

After finishing a single row, the input buffer pointer is bumped up to the next 32-bit boundary.

Line 293

At this point, we're all done and have a completely decoded bitmap.

The next section loads any file into memory.

Lines 297-303

This function loads an entire file into memory. On entry, the caller provides the path of the file. Since this is a shell application, the caller can use mappings such as FS0, FS1, etc. On exit, this function returns a pointer to the buffer containing the entire file's contents and the size of the file, in bytes.

Lines 305-308

Using the standard C library functions, the file is opened. If there is a problem, an error is returned.

Lines 310-312

Now that the file is open, see to the end in order to determine the file's size. Then return back to the start.

Lines 314-317

Now allocate a buffer large enough to hold the entire file, using the file size calculated.

Lines 319-322

Read the entire file into the allocated buffer, close the file and return.

Now we will wrap up this article with a helper function that uses all of the pieces we've introduced so far. This function reads a file into memory, converts it into a Graphics Output protocol bitmap, and then frees the allocated memory for the file.

Lines 327-333

On entry, the caller provides the path of the BMP format file to convert. On exit, this function returns a pointer to the bitmap, and the bitmap's width and height.

Lines 335-343

First, load the file into an allocated buffer.

Lines 345-357

Now convert the file into a GOP style bitmap.

Lines 359-360

Now free the memory occupied by the file (but not the bitmap) and return success.

Now we have come to the end of our little program. The files will be checked into the sourceforge repository in the next week.

Thursday, January 12, 2017

Firmware Bugs and Firmware Updates

My co-author and partner in various things UEFI, Vincent Zimmer, has penned some wise words about how firmware bugs are perceived on his blog (here). He quotes the first chapter of Embedded Firmware Solutions wherein an anonymous manager states, "If you can fix a hardware bug in firmware, it’s not a bug but a documentation issue."

What Vincent said about hardware used to be the same for operating systems. That is, it was often hard to (a) convince an OS company that they had a bug, (b) get them to fix that bug and (c) get that fix out to customers. But now, Patch Tuesday is a weekly event, monitored by websites everywhere. The OS images used by OEMs can have hot-fixes applied. So, now the situation is fixed. Hardware is the hardest to fix, followed by firmware, followed by the OS, followed by applications.

That is why firmware update has been a major focus of the recent UEFI specification updates, standardizing how 3rd party components can produce and process updates (c.f. capsules and the Firmware Management protocol, ESRT). These updates are not only for the system firmware's flash device, but also for the embedded flash on smaller chips, as well as attached USB and PCI devices. Security concerns, in particular, are driving the need for reliable and timely updates of all of these.

The next frontier is delivery of these firmware updates via the OS. While there has been some progress here by the OS vendors (Redhat, Microsoft, Canonical, see older summary here), there seems to be reluctance on the part of some OEMs. Part of this is that some of their unique value(if you can call the little tray icon apps "value") is getting sucked into the OS. Part of this is relying on the process by a 3rd party (or more than one 3rd parties) to deliver updates. Part of this is: older, out of production platforms aren't interesting any more. But highly publicized hacks and bugs are putting pressure on the industry to solve the distribution problem.

Whatever the case, platform stability rests solidly on firmware stability because of its unique capabilities to fix or mitigate hardware and OS issues, as testified to by Marvel's Agents of SHIELD.

Saturday, December 03, 2016

The UEFI Maze Game, Part 3

This is the third part in a series of posts about a simple game written as a UEFI Shell application. It consists of generating a random graphical maze and navigating a little man through that maze from entrance to exit.

This post gets to the actual maze generation, which is actually a recursive function. Pick a random position. Then pick a random direction and, if that cell is completely surrounded, then mark the cell as a path. If there is no such cell in any direction, then back up. This algorithm generates that there are no circular paths through the maze.

Figure 10.40  Maze generation main function, part 1 in Game.c
Lines 272-280
This function gets called once for each grid cell. The coordinates of the current cell are X and Y.
Lines 282-288
The local variables keep track of which neighbors to the current cell. The number of valid neighbors and then the direction from the current cell. 
Lines 293-299
If the neighboring cell to the left is surrounded by walls, then it is a possible cell that we could go to next. So record the cell’s coordinates and increment the number of valid neighbors.
Lines 301-307
If the neighboring cell above is surrounded by walls, then it is a possible cell that we could go to next. So record the cell’s coordinates and increment the number of valid neighbors.

Figure 10.41 Maze generation main function, part 2 in Game.c
Lines 310-315
If the neighboring cell down is surrounded by walls, then it is a possible cell that we could go to next. So record the cell’s coordinates and increment the number of valid neighbors.
Lines 301-307
If the neighboring cell to the right is surrounded by walls, then it is a possible cell that we could go to next. So record the cell’s coordinates and increment the number of valid neighbors.
Lines 328-331
If there are no valid neighbors then we need to back track to the last valid position and try again.

Figure 10.42 Maze generation main function, part 3 in Game.c

Lines 336-340
Pick a random direction and update the coordinates in that direction.
Lines 343-345
Save the coordinates in the backtrack list.
Lines 349-357
Mark the maze in that direction as a path and increment the number of cells visited.
Lines 361
Now recursively call this function, but this time start at the next location.

Next Steps

Now the finish line is nearly in sight. We have the environment, we have the bitmaps, and we have the maze. Now we just need to draw it and move the man around.

Oh, wait. We haven't seen how to read the bitmap files or draw them with transparency. These functions are not provided within UEFI itself, so we will add them in a single post!

Tuesday, November 22, 2016

The UEFI Maze Game, Part 2

This is the second article in a series describing a simple UEFI Shell game that generates a random maze and lets you navigate a character through that maze to the exit. The goal is to show how to use graphics and the UEFI Shell together, line by line.

The next step is to initialize the grid and the maze. The maze uses two-by-two sections of the grid. These sections can have one of the following configurations

Notice that in each chase, the lower-right cell is always a rock, and the upper-right cell is always empty. The only question is whether there is a pathway to the right, to the bottom, or both.

Figure 35

Lines 407-423
This function divides up the screen into cells based on the size of the loaded bitmap images. If there aren’t e

nough cells to make a reasonable maze then the function exits with an error. The maze uses a two by two section for each part of the maze. In addition, the first row and first column must be all walls. This means that the number of rows and columns must be odd. 
Lines 425-434
The function creates the buffer for the maze bitmap.
Lines 436-441
The function creates the buffer for the maze grid contents.

Figure 36
Lines 443-448
Initialize every cell in the grid to a background image.
Lines 450-451
Display the empty background grid. This is important, because the other images (rock and player) need to be drawn on to another color besides black.
Lines 454-460
Initialize the maze generation data structures, create the random maze, copy that maze over to the grid and then free up the allocated data structures.
Lines 462-469
The entrance is at a random location on the top edge. The exit is at a random location on the bottom edge.
Lines 471-475
Now move the character to the entrance and draw it on the bitmap. 

During maze initialization, we create a temporary grid.

Figure 37
Lines 231-242
The temporary two-dimensional array mMaze holds either PATH or WALL for every location.
Lines 245-259
The backtrack arrays are used so that when we get to a dead end, the maze generator can back up to the last place where a decision was made.
Lines 261-269
Since in every 2x2 section of the maze, the bottom right cell is a rock wall, set that now.

These utility functions simply make it easier.

Figure 38

Lines 195-200
These global variables hold the maze and the backtrack data structures. The maze (mMaze) is a two-dimensional array where each element is set to either a path (PATH) or wall (WALL). The backtrack arrays contain the coordinates in the maze of the last point where a decision was made.
Lines 202-207
Utility function to return what is at a specific set of coordinates in the maze.
Lines 209-214
Utility function to change what is at a specific set of coordinates in the maze.
Lines 216-226
Utility function that returns whether there are walls in all four directions.

Now there are the two functions to generate the maze and shutdown the maze.

Figure 39

Lines 380-385
This function calls the maze generation function, starting at the upper-left hand cornder of the maze. Since each maze cell requires a 2x2 section of the grid, we divide both the height and width of the grid by 2. We subtract 1 because we leave one extra for the wall on the top and left of the grid.
Lines 389-394
Free up all of the resources used by the maze generation.
Next Steps
Now we have all of the pieces we need to generate the maze and all the parts to draw it. In the next article, we'll dig in to the heart of the maze generation function.

Sunday, November 13, 2016

The UEFI Maze Game, Part 1

This UEFI Shell application features a very simple maze game that uses UEFI’s Graphics Output protocol to draw a random maze and direct a character from entrance to exit using a keyboard. It will be added to the SVN repository after the last article in this series is published.

This application features a few nifty touches, including converting bitmap (.bmp) files to HII, merging bitmaps using transparency and a nifty maze generation algorithm. This application uses both the standard C library, as well as UEFI-specific libraries.

This game doesn’t have any villains or time limits, yet. Originally, I planned to integrate the thermometer application previously discussed so that the main character got hotter and hotter and little ice cubs in the maze would cool him down. You can add villains in the maze, or the animation could move smoothly from cell to cell or there could be some sort of time limit.

The source is spread over two .C files. It also uses three bitmap files, which are included in the online source code. These bitmaps are: a rock, a player, and a solid green background.

The First Source File: Game.c
Figure 1: Global Variables in Game.c
Lines 1-13
These are the include files for the standard C library, basic UEFI services and, surprise(!) bitmaps. The MdePkg\Include\IndustryStandard contains constants, data structures and file formats from many popular industry standards, including PCI, ACPI and USB.
Lines 15-41
These are the key function declarations from the other source file, Bitmap.c. Rather than create a separate header file, they are just listed here.
Figure 2: Game State Data in Game.c

Next we move on the various global variables that maintain the game state.

Lines 46-47
DisplayImageStack is the global function that refreshes the screen from the internal buffer that holds the game’s bitmap image.
Lines 50-51, 64-65
These globals hold the width of the loaded background images and other images. These should be the same.
Lines 52-54
These point to the three bitmaps used in the game: the rock, the background and the player. Each is 50 x 50 pixels.
Lines 56-58
The game maintains a pixel-for-pixel copy of what is actually going to be displayed on the maze portion of the screen.  All of the player actions are updated here before they are copied to the screen. 
Lines 60-62
The game also maintains a cell-by-cell copy of what is in each part of the grid. The array mGrid contains a two dimensional array, mGridWidth cells wide by mGridHeight cells tall. Each element in the array points to one of the bitmaps: rock, background or player. The size of the array is calculated based on the screen resolution.
Lines 67-74
These mark the coordinates (within mGrid) of the character’s position, the entrance position and the exit position. Initially, the character’s position is at the entrance position. The game ends when the character reaches the exit position.
Figure 3 Game entry point in Game.c

Now that you are thoroughly bored with the global definitions, we finally reach the entry point of the game. 

Lines 590-596
This uses the standard C-style entry point. But there are no command-line options parsed.
Line 598
The srand() function is used to initialize the random number generator with a seed value. In this case, the seed value is derived from the system time. When debugging the maze generation algorithm, it was useful to set this to a fixed value so that the maze would be the same each time, facilitation easier debugging of issues.
Line 600
Reset the console so that the screen is empty.
Lines 602-606
Load all of the bitmap images and convert them into the format used by the UEFI graphics output functions. If there is an error, it means that not all of the images could be loaded or (less likely) the system cannot switch to graphics mode.
Line 608
Initialize the game data structures, including the maze.
Line 610-614
Display the maze for the first time.
Line 616
Enter the main game loop. This loop continues until the user indicates they are finished or they have reached the maze exit.
Line 619-621
Clear the screen and exit.

Figure 4 Setup bitmap images and Graphics Output Protocol in Game.c

The first step for the game is to load all of the bitmaps out of the files.

Lines 108-110
Find the instance of the UEFI Graphics Output protocol.
Lines 112-127
Load each of the three bitmaps from external files. Each of the files is formatted using the industry standard .bmp file format. 

Next Time
In the next installment, we'll look at exactly how to initialize UEFI's Graphics Output Protocol and load a bitmap.