Add AArch64 UEFI support (NVIDIA Jetson Orin) - #818
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request adds a new aarch64_efi target so wolfBoot can run as an AArch64 UEFI application (validated on NVIDIA Jetson Orin), loading/verifying kernel.img/update.img from the ESP and booting via UEFI LoadImage/StartImage.
Changes:
- Add a new AArch64 UEFI HAL (
hal/aarch64_efi.c) plus boot glue (src/boot_aarch64_efi.c) and linker-script stub. - Extend the build system to support an AArch64 PE/COFF
wolfboot.efioutput and a new example config. - Add helper scripts and documentation for building gnu-efi for AArch64 and running under QEMU/Jetson deployment.
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/scripts/build-gnu-efi-aarch64.sh | Helper to clone/build/install gnu-efi (AArch64) into the repo tree |
| tools/scripts/aarch64-efi-qemu.sh | Convenience runner for wolfboot.efi under QEMU + AAVMF |
| tools/keytools/keygen.c | Extends keystore section handling for the new UEFI target macro |
| src/boot_aarch64_efi.c | Adds UEFI-target do_boot() glue for AArch64 |
| Makefile | Makes the wolfboot.efi objcopy output format configurable per target |
| hal/aarch64_efi.ld | Empty placeholder linker script (gnu-efi script used instead) |
| hal/aarch64_efi.c | New AArch64 UEFI HAL: ESP file loading, verification, LoadImage/StartImage handoff |
| docs/Targets.md | Adds aarch64_efi target documentation (Jetson Orin + QEMU workflow) |
| config/examples/aarch64_efi.config | Example configuration for aarch64_efi |
| arch.mk | Adds aarch64_efi target build flags, gnu-efi paths, and linking rules |
| .gitignore | Ignores gnu-efi build artifacts and staging dirs for the new target |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
308bf22 to
1963856
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 12 comments.
Comments suppressed due to low confidence (1)
hal/aarch64_efi.c:1
- UEFI
EFI_FILE_PROTOCOL.Open()ignores the Attributes parameter unlessEFI_FILE_MODE_CREATEis set; passingREAD_ONLY|HIDDEN|SYSTEMhere is nonstandard and can cause opens to fail on stricter firmwares. For read-only opens, pass0for the Attributes argument and keep access control viaEFI_FILE_MODE_READ.
/* aarch64_efi.c
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 22 out of 23 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (2)
hal/aarch64_efi.c:504
- open_kernel_image() stores FileSize() into a uint32_t, which truncates files >4GiB. That can lead to partial reads and confusing verification failures. Also, returning EFI_STATUS from an int-returning function can truncate the high-bit error codes on 64-bit builds; it’s safer to keep the return values as 0/-1 here since the caller doesn’t consume EFI_STATUS.
*sz = FileSize(file);
pages = (*sz / PAGE_SIZE) + 1;
wolfBoot_printf("Opening file: %s, size: %u\n", filename, *sz);
status = uefi_call_wrapper(BS->AllocatePages,
4,
hal/aarch64_efi.c:528
- On Read() failure, open_kernel_image() returns EFI_STATUS through an int return type. On AArch64, EFI_STATUS uses the high bit for errors, so truncating to int can turn errors into 0 (success) if a future caller checks it. Return -1 here (and rely on the already-printed status) to keep the int contract consistent.
if (status != EFI_SUCCESS) {
wolfBoot_printf("file Read failed: 0x%lx\n", (unsigned long)status);
uefi_call_wrapper(BS->FreePages, 2, *_addr, pages);
*_addr = 0;
return status;
1f35be7 to
d325fbd
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
hal/aarch64_efi.c:528
- open_kernel_image() assigns the UINT64 EFI file size into a uint32_t and then computes pages as (sz / PAGE_SIZE) + 1, which always over-allocates when the file is an exact multiple of PAGE_SIZE and silently truncates sizes >4GiB. Validate the file size up front and compute the page count with a proper round-up division.
*sz = FileSize(file);
pages = (*sz / PAGE_SIZE) + 1;
wolfBoot_printf("Opening file: %s, size: %u\n", filename, *sz);
There was a problem hiding this comment.
🟡 Not ready to approve
The AArch64 EFI file-loading path currently truncates 64-bit file sizes into a 32-bit length and miscomputes page rounding, which can cause incorrect allocation/reads and should be fixed before merging.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (4)
hal/aarch64_efi.c:550
- FileSize() returns a UINT64, but open_kernel_image stores it into a uint32_t and uses that truncated value for page allocation and Read(). A file >4GiB would be silently truncated, potentially causing partial reads/under-allocation. Also, pages is computed as (sz/PAGE_SIZE)+1, which over-allocates an extra page when the size is an exact multiple of PAGE_SIZE.
*sz = FileSize(file);
pages = (*sz / PAGE_SIZE) + 1;
wolfBoot_printf("Opening file: %s, size: %u\n", filename, *sz);
tools/scripts/aarch64-efi-qemu.sh:27
- This script still claims wolfBoot reads an external \cmdline.txt and copies cmdline.txt into the ESP, but the EFI targets now take the kernel command line from the authenticated HDR_CMDLINE TLV inside kernel.img (no external file is consumed). Keeping this copy/comment is misleading for users trying to change the command line.
# optional Linux kernel command line (M3): read by wolfboot as \cmdline.txt
cp "$ROOT/aarch64_efi-stage/cmdline.txt" "$ESP"/ 2>/dev/null || true
tools/keytools/sign.c:3595
- The new --cmdline option introduces user-facing argument parsing and TLV encoding constraints (1..255 bytes, tag HDR_CMDLINE) but there is no automated coverage for it. Existing CI/unit tests already exercise other sign-tool options (e.g. --custom-tlv-string/buffer), so adding a targeted test for --cmdline would help prevent regressions (including length boundary cases and verifying the emitted TLV tag/value).
else if (strcmp(argv[i], "--cmdline") == 0) {
/* Shorthand for --custom-tlv-string HDR_CMDLINE "<args>": stores the
* OS command line as a signature-covered TLV in the manifest. */
int p = CMD.custom_tlvs;
uint16_t len;
uint32_t j;
if (p >= MAX_CUSTOM_TLVS) {
fprintf(stderr, "Too many custom TLVs.\n");
exit(16);
}
if (argc < (i + 2)) {
fprintf(stderr, "Missing --cmdline argument.\n");
exit(16);
}
len = (uint16_t)strlen(argv[i + 1]);
if (len == 0 || len > 255) {
fprintf(stderr, "cmdline must be 1..255 bytes: %s\n", argv[i + 1]);
exit(16);
}
CMD.custom_tlv[p].tag = HDR_CMDLINE;
CMD.custom_tlv[p].len = len;
CMD.custom_tlv[p].buffer = malloc(len);
if (CMD.custom_tlv[p].buffer == NULL) {
fprintf(stderr, "Error malloc for cmdline tlv buffer %d\n", len);
exit(16);
}
for (j = 0; j < len; j++) {
CMD.custom_tlv[p].buffer[j] = (uint8_t)argv[i + 1][j];
}
CMD.custom_tlvs++;
i += 1;
}
tools/scripts/sign-efi-secureboot.sh:86
- The script generates PEM .crt, .esl and .auth outputs, but many UEFI setup menus expect DER-encoded certs (commonly .cer/.der) for file-based enrollment. Since openssl is already required, consider emitting a DER .cer alongside the PEM to avoid an extra manual conversion step (and to better match the docs' enrollment flow).
# ESL (EFI signature list) form of the cert, tagged with our owner GUID.
cert-to-efi-sig-list -g "$GUID" "$name.crt" "$name.esl"
- Files reviewed: 19/20 changed files
- Comments generated: 0 new
- Review effort level: Lite
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Summary
Adds a new
aarch64_efitarget that builds wolfBoot as an AArch64 UEFI application (wolfboot.efi) -- the direct sibling of the existing Qemu x86-64 UEFI target. It uses only UEFI Boot Services (no SoC-specific registers), so the same binary runs on any AArch64 UEFI platform. The platform firmware launcheswolfboot.efi, which reads the next-stage image from the EFI Simple File System, authenticates it with wolfCrypt, and boots it viaLoadImage/StartImage(an AArch64 LinuxImageis itself a PE/COFF EFI-stub application).Validated end to end on the NVIDIA Jetson Orin Nano Developer Kit (Tegra234): the on-module UEFI firmware (edk2-nvidia) launches wolfBoot after the NVIDIA-signed early chain (BootROM -> MB1 -> MB2 -> UEFI), and wolfBoot verifies and boots NVIDIA Jetson Linux (L4T R36.4.4,
5.15.148-tegra) to an Ubuntu 22.04 login prompt.What it adds
hal/aarch64_efi.c,hal/aarch64_efi.ld) andconfig/examples/aarch64_efi.config. No bare-metal init -- UEFI owns DRAM/MMU/GIC; the flash ops are stubs and storage/console come from Boot Services.MEASURED_BOOT_TCG2=1): usingEFI_TCG2_PROTOCOL, wolfBoot extends the verified kernel, its command line, and the platform device tree into a PCR (MEASURED_PCR_A, default 9) withHashLogExtendEvent, then reads the PCR back. The firmware/fTPM does the hashing and log append, so wolfBoot needs no TPM transport driver and pulls in no wolfTPM.HDR_CMDLINETLV in the manifest header instead of an unsigned file. wolfBoot reads it from the verified image and passes it to the kernel EFI stub viaLoadOptions, so kernel arguments (root=,init=, security flags) cannot be altered without breaking the image signature. Sign with--cmdline "..."(a shorthand for theHDR_CMDLINEstring TLV). The same path is added tox86_64_efi(which previously had no command-line mechanism).wolfboot.efi, which in turn enforces the kernel -- a complete hardware root of trust.Notable details
open_kernel_image()now returns-1on error rather than a truncatedEFI_STATUS(aUINTNwhose error high-bit would become a positiveint) -- addresses review feedback.include/wolfboot_efi.h,wolfBoot_efi_get_cmdline()) included by both EFI HALs after their gnu-efi headers -- one auditable copy, no build wiring.IMAGE_HEADER_SIZE(the default 256-byte ED25519/SHA256 header holds roughly 70 bytes; setIMAGE_HEADER_SIZE=512for longer lines). If the image carries noHDR_CMDLINETLV, wolfBoot boots with no command line and the kernel uses its built-inCONFIG_CMDLINE.Testing
aarch64_efiandx86_64_efibuild (makewith each config;wolfboot.efiproduced).sign --ed25519 --sha256 --cmdline "root=..." kernel.img key.der 1produces aHDR_CMDLINE(0x0034) TLV that reads back exactly via the wolfBoot header parser.wolfboot.efi+ a signedkernel.imgon a FAT ESP boots L4T to an Ubuntu login; the console showsFirmware Validand the TCG2 measurement lines.Docs
docs/Targets.mdgains the "NVIDIA Jetson Orin (aarch64_efi)" section (deploy, boot Linux, Secure Boot enrollment, measured boot);docs/Signing.mddocuments--cmdline/HDR_CMDLINE.