Running a UEFI program upon reboot

Linux is only one of the Operating Systems that our chips need to support. While some features need a complete OS for testing, we want to make sure that features are as tested as possible before we try to debug them through Linux.

My current code implements has to talk to the firmware. Thus we need to have a responder in the firmware. Testing this from Linux has to go through the entire Linux networking stack.

The developers of the firmware already have to deal with UEFI. UEFI is installed with the firmware. Since writing UEFI apps is basically like writing DOS apps (according to Ron Minnich) it is not a huge demand on our Firmware team to have them use UEFI as the basis for writing thei test code. Thus, they produced a simple app called RespTest.efi That checks that their code does what they expect it to do.

The normal process is that they boot the UEFI shell, switch to the file system, and copy up the Executable via tftp, Once it is on the system, they run it manually. After the first time the executable is leaded, the executable is persisted on the system. Thus, to run it a second or third time, after, say, a change to the firmware, can be automated from the operating system.

ls /boot/efi/
EFI  ResponderTest.efi  spinor.img

The above was executed from a Linux system running that has the efi partition mounted in /boot/efi. The RespTest.efi binary was copied up using tftp.

To see the set of UEFI boot options, we can use efibootmgr. These are mostly various flavors of PXE

efibootmgr
BootCurrent: 0001
Timeout: 10 seconds
BootOrder: 0000,0001,0002,0003,0004,0005,0006,0007,0008,0009,000A
Boot0000* UiApp	FvVol(5c60f367-a505-419a-859e-2a4ff6ca6fe5)/FvFile(462caa21-7614-4503-836e-8ab6f4662331)
Boot0001* Fedora (Samsung SSD 970 EVO Plus 250GB)	PcieRoot(0x60000)/Pci(0x1,0x0)/Pci(0x0,0x0)/NVMe(0x1,00-25-38-5A-91-51-38-0A)/HD(1,GPT,4c1510a2-110f-492f-8c64-50127bc2e552,0x800,0x200000)/File(\EFI\fedora\shimaa64.efi) File(.????????)
Boot0002* UEFI PXEv4 (MAC:0C42A15A9B28)	PcieRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x0)/MAC(0c42a15a9b28,1)/IPv4(0.0.0.00.0.0.0,0,0){auto_created_boot_option}
...
Boot0009* UEFI HTTPv6 (MAC:0C42A15A9B29)	PcieRoot(0x0)/Pci(0x1,0x0)/Pci(0x0,0x1)/MAC(0c42a15a9b29,1)/IPv6([::]:<->[::]:,0,0)/Uri(){auto_created_boot_option}
Boot000A* UEFI Shell	FvVol(5c60f367-a505-419a-859e-2a4ff6ca6fe5)/FvFile(7c04a583-9e3e-4f1c-ad65-e05268d0b4d1)

Lets say I want to boot to the UEFI shell next time. Since that has an index of 000A, I can run the following command to tell UEFI to boot to the shell once and only once. After that it will return to the default order:

efibootmgr –bootnext 000A

Here are the first few lines of output from that command;

# efibootmgr --bootnext 000A
BootNext: 000A
BootCurrent: 0001
Timeout: 10 seconds

If I want to add an addition boot option, I can use the –create option. To tell it to boot the ResponderTest,efi executable:

efibootmgr efibootmgr --create -d /dev/nvme0n1p1 --label RespTest -l RespTest.efi

The last line of output from that command is:

Boot000B* RespTest	HD(1,GPT,4c1510a2-110f-492f-8c64-50127bc2e552,0x800,0x200000)/File(RespTest.efi)efibootmgr

If I then want to make UEFI select this option upon next boot…

# efibootmgr --bootnext 000B
BootNext: 000B
BootCurrent: 0001
Timeout: 10 seconds

Note that the executable is in /boot/efi mounted on the Linux filesystem, but that will be the EF0: in UEFI. If you wish to put something further down the tree, you can, but remember that UEFI uses reverse slashes. I think it would look something like this…but I have not tried it yet:

efibootmgr efibootmgr –create -d /dev/nvme0n1p1 –label RespTest -l EFI\\RespTest.efi

Note the double slash to avoid Linux escaping….I think this is necessary.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.