88
99from pathlib import Path
1010
11+ TARGET_AARCH64 = 'aarch64-unknown-uefi'
12+ TARGET_I686 = 'i686-unknown-uefi'
13+ TARGET_X86_64 = 'x86_64-unknown-uefi'
1114
12- def run (* cmd , capture = False , check = True , env = None ):
15+ def run (* cmd , capture = False , check = True , env = None , timeout = None ):
1316 """Print and run a command, optionally capturing the output."""
1417 cmd = [str (p ) for p in cmd ]
1518 print (' ' .join (cmd ))
1619 return subprocess .run (cmd ,
1720 capture_output = capture ,
1821 check = check ,
1922 env = env ,
20- text = True )
21-
23+ text = True ,
24+ timeout = timeout )
25+
26+ def build_and_run (tmp_dir , target ):
27+ if target == TARGET_AARCH64 :
28+ boot_file_name = 'bootaa64.efi'
29+ ovmf_dir = Path ('/usr/share/AAVMF' )
30+ ovmf_code = 'AAVMF_CODE.fd'
31+ ovmf_vars = 'AAVMF_VARS.fd'
32+ qemu = 'qemu-system-aarch64'
33+ machine = 'virt'
34+ cpu = 'cortex-a72'
35+ elif target == TARGET_I686 :
36+ boot_file_name = 'bootia32.efi'
37+ ovmf_dir = Path ('/usr/share/OVMF' )
38+ ovmf_code = 'OVMF32_CODE_4M.secboot.fd'
39+ ovmf_vars = 'OVMF32_VARS_4M.fd'
40+ # The i686 target intentionally uses 64-bit qemu; the important
41+ # difference is that the OVMF code provides a 32-bit environment.
42+ qemu = 'qemu-system-x86_64'
43+ machine = 'q35'
44+ cpu = 'qemu64'
45+ elif target == TARGET_X86_64 :
46+ boot_file_name = 'bootx64.efi'
47+ ovmf_dir = Path ('/usr/share/OVMF' )
48+ ovmf_code = 'OVMF_CODE.fd'
49+ ovmf_vars = 'OVMF_VARS.fd'
50+ qemu = 'qemu-system-x86_64'
51+ machine = 'q35'
52+ cpu = 'qemu64'
53+ else :
54+ raise KeyError ('invalid target' )
2255
23- def build_and_run (tmp_dir ):
2456 host_artifacts = Path ('/checkout/obj/build/x86_64-unknown-linux-gnu' )
2557 stage0 = host_artifacts / 'stage0/bin'
2658 stage2 = host_artifacts / 'stage2/bin'
@@ -33,7 +65,6 @@ def build_and_run(tmp_dir):
3365 shutil .copytree ('/uefi_qemu_test' , test_crate )
3466
3567 # Build the UEFI executable.
36- target = 'x86_64-unknown-uefi'
3768 run ('cargo' ,
3869 'build' ,
3970 '--manifest-path' ,
@@ -49,22 +80,32 @@ def build_and_run(tmp_dir):
4980
5081 # Copy the executable into the ESP.
5182 src_exe_path = test_crate / 'target' / target / 'debug/uefi_qemu_test.efi'
52- shutil .copy (src_exe_path , boot / 'bootx64.efi' )
83+ shutil .copy (src_exe_path , boot / boot_file_name )
84+ print (src_exe_path , boot / boot_file_name )
85+
86+ # Select the appropriate EDK2 build.
87+ ovmf_code = ovmf_dir / ovmf_code
88+ ovmf_vars = ovmf_dir / ovmf_vars
89+
90+ # Make a writable copy of the vars file. aarch64 doesn't boot
91+ # correctly with read-only vars.
92+ ovmf_rw_vars = Path (tmp_dir ) / 'vars.fd'
93+ shutil .copy (ovmf_vars , ovmf_rw_vars )
5394
5495 # Run the executable in QEMU and capture the output.
55- qemu = 'qemu-system-x86_64'
56- ovmf_dir = Path ('/usr/share/OVMF' )
57- ovmf_code = ovmf_dir / 'OVMF_CODE.fd'
58- ovmf_vars = ovmf_dir / 'OVMF_VARS.fd'
5996 output = run (qemu ,
97+ '-machine' ,
98+ machine ,
99+ '-cpu' ,
100+ cpu ,
60101 '-display' ,
61102 'none' ,
62103 '-serial' ,
63104 'stdio' ,
64105 '-drive' ,
65106 f'if=pflash,format=raw,readonly=on,file={ ovmf_code } ' ,
66107 '-drive' ,
67- f'if=pflash,format=raw,readonly=on ,file={ ovmf_vars } ' ,
108+ f'if=pflash,format=raw,readonly=off ,file={ ovmf_rw_vars } ' ,
68109 '-drive' ,
69110 f'format=raw,file=fat:rw:{ esp } ' ,
70111 capture = True ,
@@ -73,7 +114,9 @@ def build_and_run(tmp_dir):
73114 # shutdown under some circumstances. That has been
74115 # fixed in newer versions of QEMU, but for now just
75116 # don't check the exit status.
76- check = False ).stdout
117+ check = False ,
118+ # Set a timeout to kill the VM in case something goes wrong.
119+ timeout = 60 ).stdout
77120
78121 if 'Hello World!' in output :
79122 print ('VM produced expected output' )
@@ -86,10 +129,13 @@ def build_and_run(tmp_dir):
86129
87130
88131def main ():
89- # Create a temporary directory so that we have a writeable
90- # workspace.
91- with tempfile .TemporaryDirectory () as tmp_dir :
92- build_and_run (tmp_dir )
132+ targets = [TARGET_AARCH64 , TARGET_I686 , TARGET_X86_64 ]
133+
134+ for target in targets :
135+ # Create a temporary directory so that we have a writeable
136+ # workspace.
137+ with tempfile .TemporaryDirectory () as tmp_dir :
138+ build_and_run (tmp_dir , target )
93139
94140
95141if __name__ == "__main__" :
0 commit comments