The Minnowboard Chronicles Episode 10: The UEFI Shell

Today, I created my first UEFI shell script. And, by a happy coincidence, I noticed a new book in Amazon, Harnessing the UEFI Shell, by Michael Rothman, Vince Zimmer, and Tim Lewis.

In last week’s Episode 9 of the Minnowboard Chronicles, I used the macro command language within SourcePoint to print “Hello World”, read Intel MSRs, and display devices on the Minnowboard’s JTAG chain, among other things. I really liked the power of the command environment: its ability to execute command line functions, chain multiple commands on a single line, wrap multiple commands over multiple lines, and of course, execute scripts. The SourcePoint command language has rich support for conditional logic, looping, branching, and the other capabilities you might expect out of a scripting language. And since it comprehends the ‘C’ programming language and is identical to the legacy Intel ITP I programming language, my learning curve was extremely short.

Since my interest is in UEFI, this week I decided to explore its shell, and see what capabilities lay therein. It’s worthwhile to note that UEFI has support for both scripts and applications. Scripts end with an “.nsh” suffix, whereas applications end with “.efi”. Creating UEFI applications is a little more complicated, so I’ll leave that for another day. Instead, let’s see what goes into creating a simple looping “Hello World” script, like I did last week with SourcePoint in Episode 9.

The convenient thing about the Minnowboard is that it boots out of the box into the UEFI shell. Typing “Help” at the Shell prompt displays the following list of commands:


Displays, creates, or deletes UEFI Shell aliases.


Displays or modifies the attributes of files or directories.


Manages the boot and driver options that are stored in NVRAM.


Displays or changes the current directory.


Clears standard output and optionally changes background color.


Compares the contents of two files on a byte-for-byte basis.


Binds a driver to a specific device and starts the driver.


Copies one or more files or directories to another location.


Displays and sets the current date for the system.


Displays one or more blocks from a block device.


Displays the list of devices managed by UEFI drivers.


Displays the UEFI Driver Model compliant device tree.


Displays the device handles in the UEFI environment.


Disconnects one or more drivers from the specified devices.


Displays the contents of system or device memory.


Manages all UEFI variables.


Displays the UEFI driver list.


Invokes the driver configuration.


Invokes the Driver Diagnostics Protocol.


Controls script file command echoing or displays a message.


Provides a full screen text editor for ASCII or UCS-2 files.


Compresses a file using UEFI Compression Algorithm.


Decompresses a file using UEFI Decompression Algorithm.


Identifies the code executed when 'if' is FALSE.


Ends a 'for' loop.


Ends the block of a script controlled by an 'if' statement.


Exits the UEFI Shell or the current script.


Starts a loop based on 'for' syntax.


Gets the MTC from BootServices and displays it.


Moves around the point of execution in a script.


Displays the UEFI Shell command list or verbose command help.


Provides a full screen hex editor for files, block devices, or memory.


Executes commands in specified conditions.


Modifies the default IP address of the UEFI IPv4 Network Stack.


Loads a UEFI driver into memory.


Loads a PCI Option ROM.


Lists the contents of a directory or file information.


Displays or defines file system mappings.


Displays the memory map maintained by the UEFI environment.


Creates one or more new directories.


Displays or modifies MEM/MMIO/IO/PCI/PCIE address space.


Displays or changes the console output device mode.


Moves one or more files to a destination within or between file systems.


Displays the protocols and agents associated with a handle.


Retrieves a value from a standard format output file.


Pauses a script and waits for an operator to press a key.


Displays a PCI device list or PCI function configuration space of a device.


Pings the target host with an IPv4 or IPv6 stack.


Reconnects drivers to the specific device.


Resets the system.


Deletes one or more files or directories.


Sets serial port attributes.


Displays or modifies UEFI Shell environment variables.


Adjusts the size of a file.


Displays or modifies a UEFI variable.


Shifts in-script parameter positions.


Displays SMBIOS information.


Stalls the operation for a specified number of microseconds.


Displays or sets the current time for the system.


Displays or sets time zone information.


Updates the filename timestamp with the current system date and time.


Sends the contents of a file to the standard output device.


Unloads a driver image that was already loaded.


Displays UEFI Firmware version information.


Displays or modifies information about a disk volume.

For example, typing “ver” yields the following:

Shell> ver

UEFI Interactive Shell v2.1


UEFI v2.50 (EDK II, 0x00010000)

It is possible to print “Hello World” to the terminal with the “echo” command:

Shell> echo Hello World

Hello World


Interestingly, it doesn’t seem possible to use the looping/branching commands on the command line, as you can do with the shells in SourcePoint, Python, and other platforms. During my first attempt to echo “Hello World” to the screen ten times, I got the below error message:

Shell> for (i=0; i<10; i++) echo Hello World!

The command 'for' is incorrect outside of a script

Command Error Status: Aborted

At this point, I decided it was time to look at the documentation. The UEFI Forum Specifications page seemed like a good place to start, where I found the UEFI Shell Specification Version 2.2 (dated January 26, 2016) being the most current. This manual was fairly difficult to plumb through, but I finally managed to figure out that the equivalent UEFI shell script to print “Hello World” ten times looks like this:

echo -off

for %i run (0 10 1)

echo Hello World!


There’s a fairly easy-to-use editor built into the UEFI Shell, appropriately named “edit”. I decided to create a shell script named “junk.nsh” with the above program, and save it to the USB stick plugged into my Minnowboard; then it’s just a simple matter of typing it at the command line to get my program running:

FS0:\> junk.nsh

FS0:\> echo -off

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!

Hello World!


And now for the amazing coincidence; after the above experiments, I happened to be browsing on my LinkedIn account, and noticed that one of my connections had “Liked” a new book on the UEFI Shell. Clicking on the link took me to Amazon, where I found Harnessing the UEFI Shell: Moving the Platform Beyond DOS, written by Michael Rothman, Vince Zimmer, and Tim Lewis. It’s recently published (March 6, 2017) and an update to a book that was originally released in 2010, so I purchased it (warning, it’s not cheap!). An excerpt of the book’s preview in Amazon is below:

Focusing on the use of the UEFI Shell and its recently released formal specification, this book unlocks a wide range of usage models which can help people best utilize the shell solutions. This text also expands on the obvious intended utilization of the shell and explains how it can be used in various areas such as security, networking, configuration, and other anticipated uses such as manufacturing, diagnostics, etc. Among other topics, Harnessing the UEFI Shell demonstrates how to write Shell scripts, how to write a Shell application, how to use provisioning options and more. Since the Shell is also a UEFI component, the book will make clear how the two things interoperate and how both Shell developers as well as UEFI developers can dip into the other's field to further expand the power of their solutions.

Harnessing the UEFI Shell is authored by the three chairs of the UEFI working sub-teams, Michael Rothman (Intel, chair of the UEFI Configuration and UEFI Shell sub-teams), Vincent Zimmer (Intel, chair of the UEFI networking sub-team and security sub-team), and Tim Lewis (Insyde Software, chair of the UEFI security sub-team). This book is perfect for any OEMs that ship UEFI-based solutions (which is all of the MNCs such as IBM, Dell, HP, Apple, etc.), software developers who are focused on delivering solutions targeted to manufacturing, diagnostics, hobbyists, or stand-alone kiosk environments.

I’ll review the book in an upcoming episode of The Minnowboard Chronicles. I’m hoping the book will give me some tips on creating an actual .efi UEFI application, after which I’ll debug it using SourcePoint.

For last week's episode of the Minnowboard Chronicles, go here: The Minnowboard Chronicles – Episode 9; where I covered the SourcePoint macro language.

Episode 11 gives a powerful demonstration of Processor Trace on the more recent Intel parts, such as the Bay Trail-I which is on the Minnowboard Turbot. 

For a preview of how I’ll be using SourcePoint to debug my app, have a look at our eBook, UEFI Framework Debugging (note: requires registration).