8
8
9
9
from pathlib import Path
10
10
11
+ TARGET_AARCH64 = 'aarch64-unknown-uefi'
12
+ TARGET_I686 = 'i686-unknown-uefi'
13
+ TARGET_X86_64 = 'x86_64-unknown-uefi'
11
14
12
- def run (* cmd , capture = False , check = True , env = None ):
15
+ def run (* cmd , capture = False , check = True , env = None , timeout = None ):
13
16
"""Print and run a command, optionally capturing the output."""
14
17
cmd = [str (p ) for p in cmd ]
15
18
print (' ' .join (cmd ))
16
19
return subprocess .run (cmd ,
17
20
capture_output = capture ,
18
21
check = check ,
19
22
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' )
22
55
23
- def build_and_run (tmp_dir ):
24
56
host_artifacts = Path ('/checkout/obj/build/x86_64-unknown-linux-gnu' )
25
57
stage0 = host_artifacts / 'stage0/bin'
26
58
stage2 = host_artifacts / 'stage2/bin'
@@ -33,7 +65,6 @@ def build_and_run(tmp_dir):
33
65
shutil .copytree ('/uefi_qemu_test' , test_crate )
34
66
35
67
# Build the UEFI executable.
36
- target = 'x86_64-unknown-uefi'
37
68
run ('cargo' ,
38
69
'build' ,
39
70
'--manifest-path' ,
@@ -49,22 +80,32 @@ def build_and_run(tmp_dir):
49
80
50
81
# Copy the executable into the ESP.
51
82
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 )
53
94
54
95
# 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'
59
96
output = run (qemu ,
97
+ '-machine' ,
98
+ machine ,
99
+ '-cpu' ,
100
+ cpu ,
60
101
'-display' ,
61
102
'none' ,
62
103
'-serial' ,
63
104
'stdio' ,
64
105
'-drive' ,
65
106
f'if=pflash,format=raw,readonly=on,file={ ovmf_code } ' ,
66
107
'-drive' ,
67
- f'if=pflash,format=raw,readonly=on ,file={ ovmf_vars } ' ,
108
+ f'if=pflash,format=raw,readonly=off ,file={ ovmf_rw_vars } ' ,
68
109
'-drive' ,
69
110
f'format=raw,file=fat:rw:{ esp } ' ,
70
111
capture = True ,
@@ -73,7 +114,9 @@ def build_and_run(tmp_dir):
73
114
# shutdown under some circumstances. That has been
74
115
# fixed in newer versions of QEMU, but for now just
75
116
# 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
77
120
78
121
if 'Hello World!' in output :
79
122
print ('VM produced expected output' )
@@ -86,10 +129,13 @@ def build_and_run(tmp_dir):
86
129
87
130
88
131
def 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 )
93
139
94
140
95
141
if __name__ == "__main__" :
0 commit comments