@@ -23,6 +23,7 @@ def __init__(self):
2323
2424 # Properties that can be adjusted by the user or class
2525 self .cmdline = []
26+ self .efi = False
2627 self .interactive = False
2728 self .kernel = None
2829 self .kernel_dir = None
@@ -35,6 +36,8 @@ def __init__(self):
3536 self .timeout = ''
3637
3738 self ._default_kernel_path = None
39+ self ._efi_img = None
40+ self ._efi_vars = None
3841 self ._initrd_arch = None
3942 self ._kvm_cpu = 'host'
4043 self ._qemu_arch = None
@@ -142,6 +145,15 @@ def run(self):
142145 f"{ self ._default_kernel_path .name } could not be found at possible locations ('{ possible_locations } ')" ,
143146 )
144147
148+ # EFI:
149+ if self .efi :
150+ self ._qemu_args += [
151+ '-drive' , f"if=pflash,format=raw,file={ self ._efi_img } ,readonly=on" ,
152+ '-drive' , f"if=pflash,format=raw,file={ self ._efi_vars } " ,
153+ '-object' , 'rng-random,filename=/dev/urandom,id=rng0' ,
154+ '-device' , 'virtio-rng-pci' ,
155+ ] # yapf: disable
156+
145157 # Kernel options
146158 if self .interactive :
147159 self .cmdline .append ('rdinit=/bin/sh' )
@@ -187,6 +199,9 @@ def run(self):
187199 utils .red ("ERROR: QEMU did not exit cleanly!" )
188200 sys .exit (err .returncode )
189201
202+ def supports_efi (self ):
203+ return False
204+
190205
191206class X86QEMURunner (QEMURunner ):
192207
@@ -203,7 +218,10 @@ def _can_use_kvm(self):
203218 return platform .machine () == 'x86_64' and self ._have_dev_kvm_access ()
204219
205220 def run (self ):
206- if self .use_kvm :
221+ if self .use_kvm and not self .efi :
222+ # There are a lot of messages along the line of
223+ # "Invalid read at addr 0xFED40000, size 1, region '(null)', reason: rejected"
224+ # with EFI, so do not bother.
207225 self ._qemu_args += ['-d' , 'unimp,guest_errors' ]
208226
209227 super ().run ()
@@ -216,10 +234,31 @@ def __init__(self):
216234
217235 self ._initrd_arch = self ._qemu_arch = 'x86_64'
218236
237+ def supports_efi (self ):
238+ return True
239+
219240 def run (self ):
220241 if not self .use_kvm :
221242 self ._qemu_args += ['-cpu' , 'Nehalem' ]
222243
244+ if self .efi :
245+ usr_share = Path ('/usr/share' )
246+ ovmf_locations = [
247+ Path ('edk2/x64/OVMF_CODE.fd' ), # Arch Linux (current), Fedora
248+ Path ('edk2-ovmf/x64/OVMF_CODE.fd' ), # Arch Linux (old)
249+ Path ('OVMF/OVMF_CODE.fd' ), # Debian and Ubuntu
250+ ]
251+ self ._efi_img = utils .find_first_file (usr_share , ovmf_locations )
252+
253+ ovmf_vars_locations = [
254+ Path ('edk2/x64/OVMF_VARS.fd' ), # Arch Linux and Fedora
255+ Path ('OVMF/OVMF_VARS.fd' ), # Debian and Ubuntu
256+ ]
257+ ovmf_vars = utils .find_first_file (usr_share , ovmf_vars_locations )
258+ self ._efi_vars = Path (BOOT_UTILS , 'images' , self .initrd_arch ,
259+ ovmf_vars .name )
260+ shutil .copyfile (ovmf_vars , self ._efi_vars )
261+
223262 super ().run ()
224263
225264
@@ -233,6 +272,9 @@ def parse_arguments():
233272 help = 'The architecture to boot. Possible values are: %(choices)s' ,
234273 metavar = 'ARCH' ,
235274 required = True )
275+ parser .add_argument ('--efi' ,
276+ action = 'store_true' ,
277+ help = 'Boot kernel via UEFI (x86_64 only)' )
236278 parser .add_argument (
237279 '-k' ,
238280 '--kernel-location' ,
@@ -286,6 +328,13 @@ def parse_arguments():
286328 if args .append :
287329 runner .cmdline += args .append
288330
331+ if args .efi :
332+ runner .efi = runner .supports_efi ()
333+ if not runner .efi :
334+ utils .yellow (
335+ f"EFI boot requested on unsupported architecture ('{ args .architecture } '), ignoring..." ,
336+ )
337+
289338 if args .no_kvm :
290339 runner .use_kvm = False
291340
0 commit comments