Skip to content

Commit c4ada2d

Browse files
committed
Add UEFI test infrastructure
Add automated UEFI testing using QEMU. The test framework: - Downloads OVMF firmware for QEMU - Builds a test disk image with the UEFI shell and framework tool - Runs test.nsh which exercises version, help, hash, and capsule commands - Validates results via serial output markers (TESTS_COMPLETE/TEST_FAILED) - Adds CI job to run UEFI tests on ubuntu-24.04 Signed-off-by: Daniel Schaefer <dhs@frame.work>
1 parent e86c4a0 commit c4ada2d

4 files changed

Lines changed: 172 additions & 5 deletions

File tree

.github/workflows/ci.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,25 @@ jobs:
106106
name: UEFI-Shell-fwk.iso
107107
path: framework_uefi/build/x86_64-unknown-uefi/UEFI-Shell-fwk.iso
108108

109+
test-uefi:
110+
name: Test UEFI
111+
runs-on: ubuntu-24.04
112+
env:
113+
CARGO_NET_GIT_FETCH_WITH_CLI: true
114+
steps:
115+
- uses: actions/checkout@v4
116+
117+
- name: Setup Rust toolchain
118+
run: rustup show
119+
120+
- name: Install dependencies
121+
run: |
122+
sudo apt-get update
123+
sudo apt-get install -y mtools parted qemu-system-x86
124+
125+
- name: Run UEFI tests in QEMU
126+
run: make -C framework_uefi test
127+
109128
build-windows:
110129
name: Build Windows
111130
runs-on: windows-2022

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ result*
1919

2020
# Claude Code
2121
tmpclaude*
22+
23+
# UEFI test artifacts
24+
dump.bmp

framework_uefi/Makefile

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,24 @@ FEATURES?=''
55
SRC_DIR=.
66

77
QEMU?=qemu-system-x86_64
8+
OVMF_CODE?=$(BUILD)/OVMF_CODE.fd
9+
OVMF_VARS?=$(BUILD)/OVMF_VARS.fd
10+
811
QEMU_FLAGS=\
912
-M q35 \
1013
-m 1024 \
1114
-net none \
1215
-vga std \
13-
-bios /usr/share/OVMF/OVMF_CODE.fd
16+
-drive if=pflash,format=raw,readonly=on,file=$(OVMF_CODE) \
17+
-drive if=pflash,format=raw,file=$(BUILD)/ovmf_vars.fd
18+
19+
QEMU_TEST_FLAGS=\
20+
$(QEMU_FLAGS) \
21+
-display none \
22+
-serial file:$(BUILD)/serial.log \
23+
-no-reboot
1424

15-
.PHONY: qemu clean
25+
.PHONY: qemu clean test test-qemu
1626

1727
all: $(BUILD)/boot.img
1828

@@ -21,8 +31,8 @@ iso: $(BUILD)/UEFI-Shell-fwk.iso
2131
clean:
2232
rm -rf $(BUILD)
2333

24-
qemu: $(BUILD)/boot.img
25-
$(QEMU) $(QEMU_FLAGS) $<
34+
qemu: $(BUILD)/boot.img $(BUILD)/OVMF_CODE.fd $(BUILD)/ovmf_vars.fd
35+
$(QEMU) $(QEMU_FLAGS) -drive format=raw,file=$<
2636

2737
# Create ESP partition and filesystem
2838
$(BUILD)/boot.img: $(BUILD)/efi.img
@@ -46,7 +56,14 @@ $(BUILD)/efi.img: $(BUILD)/boot.efi
4656
mv $@.tmp $@
4757

4858
$(BUILD)/shellx64.efi:
49-
wget https://github.com/pbatard/UEFI-Shell/releases/download/24H2/shellx64.efi -O $@
59+
mkdir -p $(BUILD)
60+
curl -L https://github.com/pbatard/UEFI-Shell/releases/download/24H2/shellx64.efi -o $@
61+
62+
# Download OVMF firmware for QEMU
63+
$(BUILD)/OVMF_CODE.fd $(BUILD)/OVMF_VARS.fd:
64+
mkdir -p $(BUILD)
65+
curl -L https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_CODE.fd -o $(BUILD)/OVMF_CODE.fd
66+
curl -L https://retrage.github.io/edk2-nightly/bin/RELEASEX64_OVMF_VARS.fd -o $(BUILD)/OVMF_VARS.fd
5067

5168
$(BUILD)/UEFI-Shell-fwk.iso: $(BUILD)/boot.efi $(BUILD)/shellx64.efi
5269
mkdir -p $(BUILD)/$@.tmp/efi/boot
@@ -66,3 +83,55 @@ $(BUILD)/boot.efi: ../Cargo.lock $(SRC_DIR)/Cargo.toml $(SRC_DIR)/src/*
6683
--release \
6784
-- \
6885
--emit link=framework_uefi/$@
86+
87+
# Test targets
88+
$(BUILD)/ovmf_vars.fd: $(BUILD)/OVMF_VARS.fd
89+
cp $< $@
90+
91+
$(BUILD)/test.img: $(BUILD)/boot.efi $(BUILD)/shellx64.efi tests/test.nsh ../framework_lib/test_bins/winux.bin
92+
dd if=/dev/zero of=$@.tmp bs=512 count=131072
93+
mkfs.vfat $@.tmp
94+
mmd -i $@.tmp efi
95+
mmd -i $@.tmp efi/boot
96+
# Copy shell as boot loader, our tool as fwk.efi
97+
mcopy -i $@.tmp $(BUILD)/shellx64.efi ::efi/boot/bootx64.efi
98+
mcopy -i $@.tmp $(BUILD)/boot.efi ::efi/boot/fwk.efi
99+
# Also copy as bootx64 location for the test script
100+
mcopy -i $@.tmp $(BUILD)/boot.efi ::bootx64.efi
101+
# Copy test script as startup.nsh
102+
mcopy -i $@.tmp tests/test.nsh ::startup.nsh
103+
# Copy test files
104+
mcopy -i $@.tmp ../framework_lib/test_bins/winux.bin ::winux.bin
105+
mv $@.tmp $@
106+
107+
$(BUILD)/test-boot.img: $(BUILD)/test.img
108+
dd if=/dev/zero of=$@.tmp bs=512 count=133120
109+
parted $@.tmp -s -a minimal mklabel gpt
110+
parted $@.tmp -s -a minimal mkpart EFI FAT16 2048s 131071s
111+
parted $@.tmp -s -a minimal toggle 1 boot
112+
dd if=$< of=$@.tmp bs=512 count=131072 seek=2048 conv=notrunc
113+
mv $@.tmp $@
114+
115+
test-qemu: $(BUILD)/test-boot.img $(BUILD)/OVMF_CODE.fd $(BUILD)/ovmf_vars.fd
116+
@echo "Running UEFI tests in QEMU..."
117+
@rm -f $(BUILD)/serial.log
118+
timeout 60 $(QEMU) $(QEMU_TEST_FLAGS) -drive format=raw,file=$< || true
119+
@echo ""
120+
@echo "=== Test Output ==="
121+
@cat $(BUILD)/serial.log
122+
@echo ""
123+
@echo "=== Test Results ==="
124+
@if grep -q "TESTS_COMPLETE" $(BUILD)/serial.log; then \
125+
echo "All tests completed."; \
126+
else \
127+
echo "ERROR: Tests did not complete!"; \
128+
exit 1; \
129+
fi
130+
@if grep -q "TEST_FAILED" $(BUILD)/serial.log; then \
131+
echo "ERROR: Some tests failed!"; \
132+
grep "TEST_FAILED" $(BUILD)/serial.log; \
133+
exit 1; \
134+
fi
135+
@echo "All tests passed!"
136+
137+
test: test-qemu

framework_uefi/tests/test.nsh

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
@echo -off
2+
echo "=== UEFI Test Suite Starting ==="
3+
4+
# Clean up any files from previous test runs
5+
if exist fs0:\dump.bmp then
6+
del fs0:\dump.bmp
7+
endif
8+
9+
# Set path to our tool (fwk.efi is our framework tool)
10+
set fwk fs0:\efi\boot\fwk.efi
11+
12+
echo ""
13+
echo "=== TEST: --version ==="
14+
%fwk% --version
15+
if %lasterror% == 0 then
16+
echo "TEST_PASSED: version"
17+
else
18+
echo "TEST_FAILED: version (exit code %lasterror%)"
19+
endif
20+
21+
echo ""
22+
echo "=== TEST: --help ==="
23+
%fwk% --help
24+
# --help returns 1 (LOAD_ERROR) which is expected behavior for this tool
25+
if %lasterror% == 0x1 then
26+
echo "TEST_PASSED: help"
27+
else
28+
echo "TEST_FAILED: help (expected 0x1, got %lasterror%)"
29+
endif
30+
31+
echo ""
32+
echo "=== TEST: --hash on tool itself ==="
33+
%fwk% --hash fs0:\efi\boot\fwk.efi
34+
if %lasterror% == 0 then
35+
echo "TEST_PASSED: hash"
36+
else
37+
echo "TEST_FAILED: hash (exit code %lasterror%)"
38+
endif
39+
40+
echo ""
41+
echo "=== TEST: --hash on winux.bin ==="
42+
%fwk% --hash fs0:\winux.bin
43+
if %lasterror% == 0 then
44+
echo "TEST_PASSED: hash_winux"
45+
else
46+
echo "TEST_FAILED: hash_winux (exit code %lasterror%)"
47+
endif
48+
49+
echo ""
50+
echo "=== TEST: --capsule dump ==="
51+
%fwk% --capsule fs0:\winux.bin --dump fs0:\dump.bmp
52+
if %lasterror% == 0 then
53+
echo "TEST_PASSED: capsule_dump"
54+
else
55+
echo "TEST_FAILED: capsule_dump (exit code %lasterror%)"
56+
endif
57+
58+
echo ""
59+
echo "=== TEST: verify dump.bmp was created ==="
60+
if exist fs0:\dump.bmp then
61+
%fwk% --hash fs0:\dump.bmp
62+
if %lasterror% == 0 then
63+
echo "TEST_PASSED: dump_exists"
64+
else
65+
echo "TEST_FAILED: dump_exists (hash command failed)"
66+
endif
67+
else
68+
echo "TEST_FAILED: dump_exists (dump.bmp was not created)"
69+
endif
70+
71+
echo ""
72+
echo "=== UEFI Test Suite Complete ==="
73+
echo "TESTS_COMPLETE"
74+
75+
# Shutdown QEMU
76+
reset -s

0 commit comments

Comments
 (0)