Edk2
Edk2 is the official UEFI implementation. One problem I encountered is that it doesn't provide a way to specify the default boot entry.
If you already know what the default boot device or application should be, then it should be possible to set it in the 'to be flashed' file.
Here I made a patch that add a PCD option to choose which entry will be Boot0000
,
hence it will be booted first if no other value has been set in the NVStore
.
Compile EDK2
See Getting Started with EDK II for complete compilation steps.
It boils down to the following:
# Download edk2 source
Now our shell is setup with edk2 environment and we can build UEFI firmwares. But first, we'll add the patch.
Apply the patch
It can also be found in the form of a pull request
diff --git MdeModulePkg/MdeModulePkg.dec MdeModulePkg/MdeModulePkg.dec
index 0ff058b0..6ee074c3 100644
# @Prompt The value is use for Usb Network rate limiting supported.
gEfiMdeModulePkgTokenSpaceGuid.PcdUsbNetworkRateLimitingFactor|100|UINT32|0x10000028
+ ## Indicate the first boot entry, does not set bootorder
+ # @Prompt First boot entry.
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootBoot0000|L""|VOID*|0x0000012e
+
[PcdsPatchableInModule]
## Specify memory size with page number for PEI code when
# Loading Module at Fixed Address feature is enabled.
diff --git MdeModulePkg/Universal/BdsDxe/BdsDxe.inf MdeModulePkg/Universal/BdsDxe/BdsDxe.inf
index 5bac635d..557c2361 100644
gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdCapsuleOnDiskSupport ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformRecoverySupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootBoot0000 ## CONSUMES
[Depex]
TRUE
diff --git MdeModulePkg/Universal/BdsDxe/BdsEntry.c MdeModulePkg/Universal/BdsDxe/BdsEntry.c
index 72de8d32..dc773513 100644
EFI_STATUS BootManagerMenuStatus;
EFI_BOOT_MANAGER_LOAD_OPTION PlatformDefaultBootOption;
BOOLEAN PlatformDefaultBootOptionValid;
+ EFI_BOOT_MANAGER_LOAD_OPTION PlatformDefaultBoot0000;
+ BOOLEAN PlatformDefaultBoot0000Valid;
+ CONST CHAR16 *Boot0000;
HotkeyTriggered = NULL;
Status = EFI_SUCCESS;
BootNext = NULL;
}
+ Boot0000 = ((CONST CHAR16 *)PcdGetPtr (PcdPlatformBootBoot0000));
+ if (Boot0000 && (*Boot0000 != L'\0')) {
+ FilePath = ConvertTextToDevicePath (Boot0000);
+ if (FilePath == NULL) {
+ DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));
+ CpuDeadLoop ();
+ }
+
+ PlatformDefaultBoot0000Valid = EfiBootManagerInitializeLoadOption (
+ &PlatformDefaultBoot0000,
+ 0,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ L"Default PlatformBoot",
+ FilePath,
+ NULL,
+ 0
+ ) == EFI_SUCCESS;
+
+ DEBUG ((DEBUG_ERROR, "%d\n", PlatformDefaultBoot0000Valid));
+ ASSERT (PlatformDefaultBoot0000Valid == TRUE);
+ if (PlatformDefaultBoot0000Valid) {
+ EfiBootManagerLoadOptionToVariable (&PlatformDefaultBoot0000);
+ EfiBootManagerFreeLoadOption (&PlatformDefaultBoot0000);
+ }
+
+ FreePool (FilePath);
+ }
+
//
// Initialize the platform language variables
//
--
2.43.0
Edk2 source code has CRLF line endings and has whitespace-only lines, which can confuse the patch command. However, git apply works fine.
In edk2 source code:
git apply --ignore-whitespace -p0 Pcd-boot0000.patch
Build a firmware
With the patch applied edk2 accepts a new configuration key gEfiMdeModulePkgTokenSpaceGuid.PcdPlatformBootBoot0000
,
which takes an UTF-16
string.
To enter the correct value, we need first to find our firmware GUID and the application GUID:
It is then possible to choose the default boot:
Fv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(7C04A583-9E3E-4f1c-AD65-E05268D0B4D1)
boots into shellFv(7CB8BDC9-F8EB-4F34-AAEA-3EE4AF6516A1)/FvFile(462CAA21-7614-4503-836E-8AB6F4662331)
boots into uefi manager
It uses EfiDevicePathProtocol
under the hood, you can guess more boot options from these files:
note
Anything that is recognized as a filesystem by edk2 can be booted directly with its path (
/EFI/BOOT/grub.efi
)Firmware memory can be mapped as a filesystem with
LoadFileOnFv2
.
Anyway, let's build:
Test with QEMU
qemu-system-x86_64 -m 64M -enable-kvm -nographic -drive if=pflash,file="$(find -name OVMF.fd)",format=raw,readonly=on
It's good to know that QEMU will automatically create an NVStore for the firmware to use and will automatically set a BootOrder. This can be configured using fw_cfg.
Alternative
If you intend to flash the target device's NVRAM, you can achieve the same result with virt-fw-vars
, see this stackoverflow post for more details.
Conclusion
Now you can choose the default boot at the compilation step and before the first boot without touching the NVStore
.
That's all, good day!