In previous lesson we've developed an app that showed us current boot options:
FS0:\> ShowBootVariables.efi
Boot0000
UiApp
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
Boot0001
UEFI QEMU DVD-ROM QM00003
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Boot0002
UEFI QEMU HARDDISK QM00001
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Boot0003*
EFI Internal Shell
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
Boot0004
UEFI PXEv4 (MAC:525400123456)
PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
If you want to know information about the printed GUIDs here it is:
FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid
https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.infFILE_GUID = 462CAA21-7614-4503-836E-8AB6F4662331
- UiApp module is driver for BDS phase https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Application/UiApp/UiApp.inf
As for the 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1
it is a GUID for the firmware volume in our OVMF image.
https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf
This *.fdf file lists what drivers/apps are placed in every volume in the image (this includes volumes for SEC, PEI or DXE stages):
...
[FV.SECFV]
FvNameGuid = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015
BlockSize = 0x1000
FvAlignment = 16
...
INF <...>
...
[FV.PEIFV]
FvNameGuid = 6938079B-B503-4E3D-9D24-B28337A25806
BlockSize = 0x10000
FvAlignment = 16
...
INF <...>
...
[FV.DXEFV]
FvForceRebase = FALSE
FvNameGuid = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1 ### <---- this is a GUID from our output
BlockSize = 0x10000
FvAlignment = 16
...
INF ShellPkg/Application/Shell/Shell.inf <--- this apps are placed in the FV.DXEFV firmware volume
...
INF MdeModulePkg/Application/UiApp/UiApp.inf
For the complete edk2 FDF file specification look at the https://edk2-docs.gitbook.io/edk-ii-fdf-specification/
If you look at the https://github.com/tianocore/edk2/blob/master/ShellPkg/Application/Shell/Shell.inf you'll see that EFI Shell is a simple UEFI_APPLICATION
. We've developed a lot of those in these lessons, so let's try to add one of our apps to boot options.
We will try to add our HelloWorld
application to the boot options. We will look at how Shell app is included and try to do the same.
First we need to add our app to OVMF image. So let's add UefiLessonsPkg/HelloWorld/HelloWorld.inf
to the [FV.DXEFV]
section next to INF ShellPkg/Application/Shell/Shell.inf
in a OvmfPkg/OvmfPkgX64.fdf b/OvmfPkg/OvmfPkgX64.fdf
we've already discussed.
[FV.DXEFV]
FvForceRebase = FALSE
FvNameGuid = 7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1
BlockSize = 0x10000
FvAlignment = 16
...
INF ShellPkg/Application/Shell/Shell.inf
+ INF UefiLessonsPkg/HelloWorld/HelloWorld.inf
...
If we try to build OVMF now we would get:
$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
...
build.py...
: error F001: Module /home/kostr/tiano/edk2/UefiLessonsPkg/HelloWorld/HelloWorld.inf NOT found in DSC file; Is it really a binary module?
...
Ok, so we need to add information to the OvmfPkg/OvmfPkgX64.dsc
file. If you look at this file, you'll see that ShellPkg/Application/Shell/Shell.inf
is listed under [Components]
section. We've already used it in our first lesson when we've tried to compile our app without package. Add UefiLessonsPkg/HelloWorld/HelloWorld.inf
next to the Shell INF file.
[Components]
...
ShellPkg/Application/Shell/Shell.inf {
...
}
+ UefiLessonsPkg/HelloWorld/HelloWorld.inf
...
Shell.inf file has some information inside the brackets {...}
. Don't mind it, we don't need such info for our simple HelloWorld.inf
.
Now we can compile OVMF without errors:
$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
Our HelloWorld
app would be compiled and embedded in the OVMF image but unfortunately in wouldn't be listed in a boot options.
When we used our ShowBootVariables.efi
app we saw that UEFI shell boot option had a description EFI Internal Shell
. Let's try search for that in a edk2 codebase:
$ grep "EFI Internal Shell" -r ./ --exclude=Build
./ArmVirtPkg/Library/PlatformBootManagerLib/PlatformBm.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLibBhyve/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLibGrub/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
For our case we're interested in a ./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
file:
VOID
EFIAPI
PlatformBootManagerAfterConsole (
VOID
)
{
...
//
// Register UEFI Shell
//
PlatformRegisterFvBootOption (
&gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
);
...
}
If you grep for a gUefiShellFileGuid
:
./OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c: &gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
./OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf: gUefiShellFileGuid
./ShellPkg/Application/Shell/Shell.inf: FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 # gUefiShellFileGuid
./ShellPkg/ShellPkg.dec: gUefiShellFileGuid = {0x7c04a583, 0x9e3e, 0x4f1c, {0xad, 0x65, 0xe0, 0x52, 0x68, 0xd0, 0xb4, 0xd1}}
Ok it looks like we need to create a UefiLessonsPkg/UefiLessonsPkg.dec
file with something like gHelloWorldFileGuid
with a value equal to the one that is listed in a UefiLessonsPkg/HelloWorld/HelloWorld.inf
file.
Let's do it:
[Defines]
DEC_SPECIFICATION = 0x00010005
PACKAGE_NAME = UefiLessonsPkg
PACKAGE_GUID = 7e7edbba-ca2c-4177-a3f0-d3371358773a
PACKAGE_VERSION = 1.01
[Guids]
# FILE_GUID as defined in UefiLessonsPkg/HelloWorld/HelloWorld.inf
gHelloWorldFileGuid = {0x2e55fa38, 0xf148, 0x42d3, {0xaf, 0x90, 0x1b, 0xe2, 0x47, 0x32, 0x3e, 0x30}}
EDK2 Package Declaration (DEC) File Format Specification can be found at link https://edk2-docs.gitbook.io/edk-ii-dec-specification/
Let's add our GUID to the OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
file
[Guids]
...
gUefiShellFileGuid
+ gHelloWorldFileGuid
So we could use it in a OvmfPkg/Library/PlatformBootManagerLib/BdsPlatform.c
file:
VOID
EFIAPI
PlatformBootManagerAfterConsole (
VOID
)
{
...
//
// Register UEFI Shell
//
PlatformRegisterFvBootOption (
&gUefiShellFileGuid, L"EFI Internal Shell", LOAD_OPTION_ACTIVE
);
//
// Register HelloWorld app
//
PlatformRegisterFvBootOption (
&gHelloWorldFileGuid, L"Hello World", LOAD_OPTION_ACTIVE
);
...
}
If we try to build OVMF now we would get an error:
$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5
...
build.py...
/home/kostr/tiano/edk2/OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf(87): error 4000: Value of Guid [gHelloWorldFileGuid] is not found under [Guids] section in
/home/kostr/tiano/edk2/MdePkg/MdePkg.dec
/home/kostr/tiano/edk2/MdeModulePkg/MdeModulePkg.dec
/home/kostr/tiano/edk2/SourceLevelDebugPkg/SourceLevelDebugPkg.dec
/home/kostr/tiano/edk2/OvmfPkg/OvmfPkg.dec
/home/kostr/tiano/edk2/SecurityPkg/SecurityPkg.dec
/home/kostr/tiano/edk2/ShellPkg/ShellPkg.dec
...
To correct in we need our newly created UefiLessonsPkg/UefiLessonsPkg.dec
to the OvmfPkg/Library/PlatformBootManagerLib/PlatformBootManagerLib.inf
:
[Packages]
...
ShellPkg/ShellPkg.dec
UefiLessonsPkg/UefiLessonsPkg.dec
Finally we can successfully build OVMF. Let's run it and test our newly created boot option.
Execute QEMU launch as usual. Now if you'll execute our ShowBootVariables.efi
app you would get:
FS0:\> ShowBootVariables.efi
Boot0000
UiApp
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
Boot0001
UEFI QEMU DVD-ROM QM00003
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Boot0002
UEFI QEMU HARDDISK QM00001
PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Boot0003*
EFI Internal Shell
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
Boot0004
Hello World
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(2E55FA38-F148-42D3-AF90-1BE247323E30)
Boot0005
UEFI PXEv4 (MAC:525400123456)
PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
Hooraay! Our boot option is present in the system.
UEFI shell has a command bcfg
to print boot variables. You can check that the data from our app is correct, if you execute bcfg boot dump
:
Shell> bcfg boot dump
Option: 00. Variable: Boot0000
Desc - UiApp
DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
Optional- N
Option: 01. Variable: Boot0001
Desc - UEFI QEMU DVD-ROM QM00003
DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Optional- Y
Option: 02. Variable: Boot0002
Desc - UEFI QEMU HARDDISK QM00001
DevPath - PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
Optional- Y
Shell> 03. Variable: Boot0003
Desc - EFI Internal Shell
DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4F1C-AD65-E05268D0B4D1)
Optional- N
Option: 04. Variable: Boot0004
Desc - Hello World
DevPath - Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(2E55FA38-F148-42D3-AF90-1BE247323E30)
Optional- N
Option: 05. Variable: Boot0005
Desc - UEFI PXEv4 (MAC:525400123456)
DevPath - PciRoot(0x0)/Pci(0x3,0x0)/MAC(525400123456,0x1)/IPv4(0.0.0.0)
Optional- Y
Just in case I've placed Ovmf.diff
in this lesson folder that shows all the necessary changes.