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