UEFI News and Commentary

Sunday, May 21, 2017

Using C++ With EDK2, Part 1: new and delete

This is the first in a series of articles looking at what it takes to compile a UEFI C++ application under EDK2. This isn't an attempt to cover everything. I'm not a compiler library expert, so I'm not trying to port everything in the STL over. Nor am I a regular GCC user, so my efforts have been focused on Visual Studio 2015. Finally, I am focused on UEFI Shell applications, rather than normal UEFI apps or UEFI drivers.

I was initially intrigued by the fact that "#ifdef __cplusplus" occurs in several places. It appears in the StdLib header files, but that makes sense since they were originally a port from an environment that supported C++ and C. It also appears in the AutoGen.h files that are automatically created by the EDK2 build system for each module. It looks something like this:

#ifdef __cplusplus
extern "C" {


extern GUID  gEfiCallerIdGuid;
extern CHAR8 *gEfiCallerBaseName;

// Guids
extern EFI_GUID gEfiAuthenticatedVariableGuid;
extern EFI_GUID gEfiVariableGuid;

// Definition of PCDs used in this module
#define _PCD_TOKEN_PcdFlashNvStorageVariableBase  5U
PeimInitializeVariableServices (
  IN       EFI_PEI_FILE_HANDLE  FileHandle,
#ifdef __cplusplus

That is, all of the C symbols that are automatically included into the build have the extern "C" linkage specifier placed around them so that they will handle calls from either C or C++ source code. So someone was thinking about C++.

For my solution, which is checked in on SourceForge here, I started simply by handling the necessary support for the new and delete operators, with no support for exceptions. This C++ library depends on the StdLib C library that comes with EDK2. For the most part, the C headers would work just fine, but two critical files (MdePkg/Include/Base.h and StdLib/Include/sys/EfiCDefs.h) generate errors when pulled in to C++ code. For now, I simply created new, slightly modified versions to work around the minor issues. This requres that your .inf file list the new library before listing the StdLib.


This changes the include order so that, if there is a modified version for the C++ library, it will be preferred over the one in StdLib.

So far, only the new header file declares anything of substance. The others (wchar.h, stdlib.h, stdio.h) just provide wrappers for the StdLib that bring in the versions of Base.h and EfiCDefs.h that work with the library.

But the results are pretty nice. Assuming you don't need exception handling or the C++ standard library, you can use all of the normal C++ features, such as classes and inheritance and templates.

This is just the starting point. Over the next articles, I will expand the support for both the C++ and C libraries.

Wednesday, April 26, 2017

Maze Game Source Code

Feeling frustrated by the fact that I used bitmaps for all source code in the simple maze game articles I posted? Fret no more, the code has been checked in under BSD license here:


Look in Applications\Maze

Tuesday, April 11, 2017

Control Systems, UEFI & Cyber-Security

A few weeks ago, I had a chance to attend the meeting sponsored by the Control System Cyber Security Association International (CS2AI), They are working with experts like Dr. Jun Dai (professor at Sacramento State) and Martin Noufer (McAfee, Intel) to develop emphasize and develop security expertise.

The session started with an excellent overview of IoT security by Rahner James, who works with cyber-security solutions firm GRIMM and teaches a computer forensics course locally. His excellent presentation (which can be found here), his knowledge of industry war stories and his collection of fascinating little testing "devices" gave us insight into the range of possible attacks (hardware, software, social) and possible goals (theft, disruption). The large number of IoT devices and the low profit margins mean a high probability that there are a substantial number of devices on the net that are easily hackable.

One of the key points that was raised during the discussion that followed is how little help is given to software engineers to understand and defend against security issues in IoT devices. Market pressures demand quick deliver of functional (but not necessarily secure) hardware. Open source provides access to amazing security primitives, but also gives access to catastrophic security holes. The real answer is education, one of CS2AI's goals.

Education is certainly needed when it comes to UEFI and security. UEFI isn't for everybody in the IoT space, because of RAM and ROM size, but it does have a thorough security story with Secure Boot, Capsule Update and even User Identity. Working with well-designed hardware, UEFI helps guard the integrity of the flash device in which the firmware resides and the memory in which it executes. My colleague, David Chen, gave an excellent overview of some of these topics at the recent UEFI Plug-Fest in Nanjing. Others talked about SMM security, ARM security and flash update security.

The presentation we saw claimed that in 2020 there will be 50 billion IoT devices. Security for these devices is become a board-of-directors conversation topic: are our devices secure? What will you say when they ask you? What will you do when you're wrong?

[1] See Matthew Garrett's summary here.
[2] See a quick summary about AMD's stuff here.

Wednesday, March 29, 2017

UEFI Plugfest 2017 in Nanjing

My colleague from Insyde, David Chen, talking about security in UEFI
The UEFI Forum hosted a plug-fest and educational seminar in Nanjing, China this week. I have many fond memories of visiting this historic city over a period of 2-3 years.

For those that don't know, a plug-fest is an occasion where folks who provide the different parts of an industry standard ecosystem get together to make sure that they all play nicely together. So, for UEFI, this includes motherboard, plug-in card, OS, system application and BIOS vendors.

These events, along with the SCT (Self-Certification Test) tools, help the wildly diverse group of folks who use UEFI specifications to increase the chances that the blind-date scenario that is the PC industry works harmoniously.

The presentations are being posted on-line here. Insyde posted a few other pictures from the event here.

Sample Chapter from Harnessing the UEFI Shell

Not to be out-done by the Beyond BIOS book, another UEFI book has made an appearance: Harnessing the UEFI Shell. Two of the likely suspects (Zimmer and Rothman) are involved with both new editions (as they should be!) and I joined them on the latter since I write a lot of shell apps.

You can get a glimpse inside a sample chapter and the table of contents.

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.