blob: 18aeb7f5f0cf39bb3c4ff178b9ea7adddbb2cddf [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
2
Patrick Williamsc124f4f2015-09-15 14:41:29 -05003# Handle running OE images standalone with QEMU
4#
5# Copyright (C) 2006-2011 Linux Foundation
Patrick Williamsc0f7c042017-02-23 20:41:17 -06006# Copyright (c) 2016 Wind River Systems, Inc.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007#
Brad Bishopc342db32019-05-15 21:57:59 -04008# SPDX-License-Identifier: GPL-2.0-only
Patrick Williamsc124f4f2015-09-15 14:41:29 -05009#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010
Patrick Williamsc0f7c042017-02-23 20:41:17 -060011import os
12import sys
13import logging
14import subprocess
15import re
16import fcntl
17import shutil
18import glob
19import configparser
Brad Bishop004d4992018-10-02 23:54:45 +020020import signal
Andrew Geissler09036742021-06-25 14:25:14 -050021import time
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050022
Brad Bishopd7bf8c12018-02-25 22:55:05 -050023class RunQemuError(Exception):
24 """Custom exception to raise on known errors."""
25 pass
26
27class OEPathError(RunQemuError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060028 """Custom Exception to give better guidance on missing binaries"""
29 def __init__(self, message):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050030 super().__init__("In order for this script to dynamically infer paths\n \
Patrick Williamsc0f7c042017-02-23 20:41:17 -060031kernels or filesystem images, you either need bitbake in your PATH\n \
32or to source oe-init-build-env before running this script.\n\n \
33Dynamic path inference can be avoided by passing a *.qemuboot.conf to\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -050034runqemu, i.e. `runqemu /path/to/my-image-name.qemuboot.conf`\n\n %s" % message)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060035
36
37def create_logger():
38 logger = logging.getLogger('runqemu')
39 logger.setLevel(logging.INFO)
40
41 # create console handler and set level to debug
42 ch = logging.StreamHandler()
Brad Bishopd7bf8c12018-02-25 22:55:05 -050043 ch.setLevel(logging.DEBUG)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044
45 # create formatter
46 formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
47
48 # add formatter to ch
49 ch.setFormatter(formatter)
50
51 # add ch to logger
52 logger.addHandler(ch)
53
54 return logger
55
56logger = create_logger()
57
58def print_usage():
59 print("""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050060Usage: you can run this script with any valid combination
61of the following environment variables (in any order):
62 KERNEL - the kernel image file to use
Brad Bishopc68388fc2019-08-26 01:33:31 -040063 BIOS - the bios image file to use
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064 ROOTFS - the rootfs image file or nfsroot directory to use
Brad Bishop316dfdd2018-06-25 12:45:53 -040065 DEVICE_TREE - the device tree blob to use
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050066 MACHINE - the machine name (optional, autodetected from KERNEL filename if unspecified)
67 Simplified QEMU command-line options can be passed with:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060068 nographic - disable video console
Patrick Williams8e7b46e2023-05-01 14:19:06 -050069 nonetwork - disable network connectivity
Andrew Geissler90fd73c2021-03-05 15:25:55 -060070 novga - Disable VGA emulation completely
Brad Bishopa34c0302019-09-23 22:34:48 -040071 sdl - choose the SDL UI frontend
72 gtk - choose the Gtk UI frontend
Brad Bishop6dbb3162019-11-25 09:41:34 -050073 gl - enable virgl-based GL acceleration (also needs gtk or sdl options)
74 gl-es - enable virgl-based GL acceleration, using OpenGL ES (also needs gtk or sdl options)
75 egl-headless - enable headless EGL output; use vnc (via publicvnc option) or spice to see it
Andrew Geisslerd159c7f2021-09-02 21:05:58 -050076 (hint: if /dev/dri/renderD* is absent due to lack of suitable GPU, 'modprobe vgem' will create
Andrew Geissler9aee5002022-03-30 16:27:02 +000077 one suitable for mesa llvmpipe software renderer)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060078 serial - enable a serial console on /dev/ttyS0
Brad Bishop19323692019-04-05 15:28:33 -040079 serialstdio - enable a serial console on the console (regardless of graphics mode)
Andrew Geissler9aee5002022-03-30 16:27:02 +000080 slirp - enable user networking, no root privilege is required
81 snapshot - don't write changes back to images
Patrick Williamsc0f7c042017-02-23 20:41:17 -060082 kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
83 kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050084 publicvnc - enable a VNC server open to all hosts
Patrick Williamsc0f7c042017-02-23 20:41:17 -060085 audio - enable audio
Andrew Geisslerfc113ea2023-03-31 09:59:46 -050086 guestagent - enable guest agent communication
Brad Bishop6e60e8b2018-02-01 10:27:11 -050087 [*/]ovmf* - OVMF firmware file or base name for booting with UEFI
Patrick Williamsc0f7c042017-02-23 20:41:17 -060088 tcpserial=<port> - specify tcp serial port number
Patrick Williamsc0f7c042017-02-23 20:41:17 -060089 qemuparams=<xyz> - specify custom parameters to QEMU
90 bootparams=<xyz> - specify custom kernel parameters during boot
Brad Bishop6e60e8b2018-02-01 10:27:11 -050091 help, -h, --help: print this text
Brad Bishopd7bf8c12018-02-25 22:55:05 -050092 -d, --debug: Enable debug output
Brad Bishop79641f22019-09-10 07:20:22 -040093 -q, --quiet: Hide most output except error messages
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050094
95Examples:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050096 runqemu
Patrick Williamsc0f7c042017-02-23 20:41:17 -060097 runqemu qemuarm
98 runqemu tmp/deploy/images/qemuarm
Brad Bishop6e60e8b2018-02-01 10:27:11 -050099 runqemu tmp/deploy/images/qemux86/<qemuboot.conf>
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100 runqemu qemux86-64 core-image-sato ext4
101 runqemu qemux86-64 wic-image-minimal wic
102 runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600103 runqemu qemux86 iso/hddimg/wic.vmdk/wic.vhd/wic.vhdx/wic.qcow2/wic.vdi/ramfs/cpio.gz...
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104 runqemu qemux86 qemuparams="-m 256"
105 runqemu qemux86 bootparams="psplash=false"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600106 runqemu path/to/<image>-<machine>.wic
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500107 runqemu path/to/<image>-<machine>.wic.vmdk
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600108 runqemu path/to/<image>-<machine>.wic.vhdx
109 runqemu path/to/<image>-<machine>.wic.vhd
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600110""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600112def check_tun():
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500113 """Check /dev/net/tun"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600114 dev_tun = '/dev/net/tun'
115 if not os.path.exists(dev_tun):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500116 raise RunQemuError("TUN control device %s is unavailable; you may need to enable TUN (e.g. sudo modprobe tun)" % dev_tun)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600118 if not os.access(dev_tun, os.W_OK):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500119 raise RunQemuError("TUN control device %s is not writable, please fix (e.g. sudo chmod 666 %s)" % (dev_tun, dev_tun))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500121def get_first_file(globs):
122 """Return first file found in wildcard globs"""
123 for g in globs:
124 all_files = glob.glob(g)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600125 if all_files:
126 for f in all_files:
127 if not os.path.isdir(f):
128 return f
129 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500130
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600131class BaseConfig(object):
132 def __init__(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500133 # The self.d saved vars from self.set(), part of them are from qemuboot.conf
134 self.d = {'QB_KERNEL_ROOT': '/dev/vda'}
135
136 # Supported env vars, add it here if a var can be got from env,
137 # and don't use os.getenv in the code.
138 self.env_vars = ('MACHINE',
139 'ROOTFS',
140 'KERNEL',
Brad Bishopc68388fc2019-08-26 01:33:31 -0400141 'BIOS',
Brad Bishop316dfdd2018-06-25 12:45:53 -0400142 'DEVICE_TREE',
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500143 'DEPLOY_DIR_IMAGE',
144 'OE_TMPDIR',
145 'OECORE_NATIVE_SYSROOT',
Andrew Geissler82c905d2020-04-13 13:39:40 -0500146 'MULTICONFIG',
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500147 'SERIAL_CONSOLES',
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500148 )
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500149
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600150 self.qemu_opt = ''
151 self.qemu_opt_script = ''
Andrew Geissler99467da2019-02-25 18:54:23 -0600152 self.qemuparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600153 self.nfs_server = ''
154 self.rootfs = ''
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500155 # File name(s) of a OVMF firmware file or variable store,
156 # to be added with -drive if=pflash.
157 # Found in the same places as the rootfs, with or without one of
158 # these suffices: qcow2, bin.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500159 self.ovmf_bios = []
Brad Bishop08902b02019-08-20 09:16:51 -0400160 # When enrolling default Secure Boot keys, the hypervisor
161 # must provide the Platform Key and the first Key Exchange Key
162 # certificate in the Type 11 SMBIOS table.
163 self.ovmf_secboot_pkkek1 = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600164 self.qemuboot = ''
165 self.qbconfload = False
166 self.kernel = ''
Brad Bishopc68388fc2019-08-26 01:33:31 -0400167 self.bios = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 self.kernel_cmdline = ''
169 self.kernel_cmdline_script = ''
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500170 self.bootparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 self.dtb = ''
172 self.fstype = ''
173 self.kvm_enabled = False
174 self.vhost_enabled = False
175 self.slirp_enabled = False
Andrew Geissler82c905d2020-04-13 13:39:40 -0500176 self.net_bridge = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600177 self.nfs_instance = 0
178 self.nfs_running = False
Brad Bishop19323692019-04-05 15:28:33 -0400179 self.serialconsole = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600180 self.serialstdio = False
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500181 self.nographic = False
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500182 self.nonetwork = False
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500183 self.sdl = False
184 self.gtk = False
185 self.gl = False
186 self.gl_es = False
187 self.egl_headless = False
Patrick Williams03907ee2022-05-01 06:28:52 -0500188 self.publicvnc = False
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500189 self.novga = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 self.cleantap = False
191 self.saved_stty = ''
192 self.audio_enabled = False
193 self.tcpserial_portnum = ''
Brad Bishop08902b02019-08-20 09:16:51 -0400194 self.taplock = ''
195 self.taplock_descriptor = None
196 self.portlocks = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600197 self.bitbake_e = ''
198 self.snapshot = False
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600199 self.wictypes = ('wic', 'wic.vmdk', 'wic.qcow2', 'wic.vdi', "wic.vhd", "wic.vhdx")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500200 self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600201 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz',
202 'squashfs', 'squashfs-xz', 'squashfs-lzo',
203 'squashfs-lz4', 'squashfs-zst')
Brad Bishop08902b02019-08-20 09:16:51 -0400204 self.vmtypes = ('hddimg', 'iso')
Brad Bishop15ae2502019-06-18 21:44:24 -0400205 self.fsinfo = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500206 self.network_device = "-device e1000,netdev=net0,mac=@MAC@"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500207 self.cmdline_ip_slirp = "ip=dhcp"
Patrick Williams2a254922023-08-11 09:48:11 -0500208 self.cmdline_ip_tap = "ip=192.168.7.@CLIENT@::192.168.7.@GATEWAY@:255.255.255.0::eth0:off:8.8.8.8 net.ifnames=0"
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500209 # Use different mac section for tap and slirp to avoid
210 # conflicts, e.g., when one is running with tap, the other is
211 # running with slirp.
212 # The last section is dynamic, which is for avoiding conflicts,
213 # when multiple qemus are running, e.g., when multiple tap or
214 # slirp qemus are running.
215 self.mac_tap = "52:54:00:12:34:"
216 self.mac_slirp = "52:54:00:12:35:"
Brad Bishop004d4992018-10-02 23:54:45 +0200217 # pid of the actual qemu process
Patrick Williams2390b1b2022-11-03 13:47:49 -0500218 self.qemu_environ = os.environ.copy()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600219 self.qemuprocess = None
Brad Bishop004d4992018-10-02 23:54:45 +0200220 # avoid cleanup twice
221 self.cleaned = False
Andrew Geisslerc926e172021-05-07 16:11:35 -0500222 # Files to cleanup after run
223 self.cleanup_files = []
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500224 self.guest_agent = False
225 self.guest_agent_sockpath = '/tmp/qga.sock'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500226
Brad Bishop08902b02019-08-20 09:16:51 -0400227 def acquire_taplock(self, error=True):
228 logger.debug("Acquiring lockfile %s..." % self.taplock)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600229 try:
Brad Bishop08902b02019-08-20 09:16:51 -0400230 self.taplock_descriptor = open(self.taplock, 'w')
231 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600232 except Exception as e:
Brad Bishop08902b02019-08-20 09:16:51 -0400233 msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500234 if error:
235 logger.error(msg)
236 else:
237 logger.info(msg)
Brad Bishop08902b02019-08-20 09:16:51 -0400238 if self.taplock_descriptor:
239 self.taplock_descriptor.close()
240 self.taplock_descriptor = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600241 return False
242 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500243
Brad Bishop08902b02019-08-20 09:16:51 -0400244 def release_taplock(self):
245 if self.taplock_descriptor:
Brad Bishopf86d0552018-12-04 14:18:15 -0800246 logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
Andrew Geissler5f350902021-07-23 13:09:54 -0400247 # We pass the fd to the qemu process and if we unlock here, it would unlock for
248 # that too. Therefore don't unlock, just close
249 # fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN)
Brad Bishop08902b02019-08-20 09:16:51 -0400250 self.taplock_descriptor.close()
Andrew Geissler5f350902021-07-23 13:09:54 -0400251 # Removing the file is a potential race, don't do that either
252 # os.remove(self.taplock)
Brad Bishop08902b02019-08-20 09:16:51 -0400253 self.taplock_descriptor = None
254
255 def check_free_port(self, host, port, lockdir):
256 """ Check whether the port is free or not """
257 import socket
258 from contextlib import closing
259
260 lockfile = os.path.join(lockdir, str(port) + '.lock')
261 if self.acquire_portlock(lockfile):
262 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
263 if sock.connect_ex((host, port)) == 0:
264 # Port is open, so not free
265 self.release_portlock(lockfile)
266 return False
267 else:
268 # Port is not open, so free
269 return True
270 else:
271 return False
272
273 def acquire_portlock(self, lockfile):
274 logger.debug("Acquiring lockfile %s..." % lockfile)
275 try:
276 portlock_descriptor = open(lockfile, 'w')
277 self.portlocks.update({lockfile: portlock_descriptor})
278 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB)
279 except Exception as e:
280 msg = "Acquiring lockfile %s failed: %s" % (lockfile, e)
281 logger.info(msg)
282 if lockfile in self.portlocks.keys() and self.portlocks[lockfile]:
283 self.portlocks[lockfile].close()
284 del self.portlocks[lockfile]
285 return False
286 return True
287
288 def release_portlock(self, lockfile=None):
289 if lockfile != None:
Andrew Geissler5f350902021-07-23 13:09:54 -0400290 logger.debug("Releasing lockfile '%s'" % lockfile)
291 # We pass the fd to the qemu process and if we unlock here, it would unlock for
292 # that too. Therefore don't unlock, just close
293 # fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN)
294 self.portlocks[lockfile].close()
295 # Removing the file is a potential race, don't do that either
296 # os.remove(lockfile)
297 del self.portlocks[lockfile]
Brad Bishop08902b02019-08-20 09:16:51 -0400298 elif len(self.portlocks):
299 for lockfile, descriptor in self.portlocks.items():
300 logger.debug("Releasing lockfile '%s'" % lockfile)
Andrew Geissler5f350902021-07-23 13:09:54 -0400301 # We pass the fd to the qemu process and if we unlock here, it would unlock for
302 # that too. Therefore don't unlock, just close
303 # fcntl.flock(descriptor, fcntl.LOCK_UN)
Brad Bishop08902b02019-08-20 09:16:51 -0400304 descriptor.close()
Andrew Geissler5f350902021-07-23 13:09:54 -0400305 # Removing the file is a potential race, don't do that either
306 # os.remove(lockfile)
Brad Bishop08902b02019-08-20 09:16:51 -0400307 self.portlocks = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500308
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600309 def get(self, key):
310 if key in self.d:
311 return self.d.get(key)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500312 elif os.getenv(key):
313 return os.getenv(key)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600314 else:
315 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500316
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600317 def set(self, key, value):
318 self.d[key] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500319
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600320 def is_deploy_dir_image(self, p):
321 if os.path.isdir(p):
322 if not re.search('.qemuboot.conf$', '\n'.join(os.listdir(p)), re.M):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500323 logger.debug("Can't find required *.qemuboot.conf in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600324 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500325 if not any(map(lambda name: '-image-' in name, os.listdir(p))):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500326 logger.debug("Can't find *-image-* in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600327 return False
328 return True
329 else:
330 return False
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500331
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600332 def check_arg_fstype(self, fst):
333 """Check and set FSTYPE"""
Brad Bishop15ae2502019-06-18 21:44:24 -0400334 if fst not in self.fstypes + self.vmtypes + self.wictypes:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800335 logger.warning("Maybe unsupported FSTYPE: %s" % fst)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600336 if not self.fstype or self.fstype == fst:
337 if fst == 'ramfs':
338 fst = 'cpio.gz'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500339 if fst in ('tar.bz2', 'tar.gz'):
340 fst = 'nfs'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600341 self.fstype = fst
342 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500343 raise RunQemuError("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500344
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600345 def set_machine_deploy_dir(self, machine, deploy_dir_image):
346 """Set MACHINE and DEPLOY_DIR_IMAGE"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500347 logger.debug('MACHINE: %s' % machine)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600348 self.set("MACHINE", machine)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349 logger.debug('DEPLOY_DIR_IMAGE: %s' % deploy_dir_image)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600350 self.set("DEPLOY_DIR_IMAGE", deploy_dir_image)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500351
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600352 def check_arg_nfs(self, p):
353 if os.path.isdir(p):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500354 self.rootfs = p
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600355 else:
356 m = re.match('(.*):(.*)', p)
357 self.nfs_server = m.group(1)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500358 self.rootfs = m.group(2)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600359 self.check_arg_fstype('nfs')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500360
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600361 def check_arg_path(self, p):
362 """
363 - Check whether it is <image>.qemuboot.conf or contains <image>.qemuboot.conf
Andrew Geissler9aee5002022-03-30 16:27:02 +0000364 - Check whether it is a kernel file
365 - Check whether it is an image file
366 - Check whether it is an NFS dir
367 - Check whether it is an OVMF flash file
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600368 """
369 if p.endswith('.qemuboot.conf'):
370 self.qemuboot = p
371 self.qbconfload = True
372 elif re.search('\.bin$', p) or re.search('bzImage', p) or \
373 re.search('zImage', p) or re.search('vmlinux', p) or \
374 re.search('fitImage', p) or re.search('uImage', p):
375 self.kernel = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500376 elif os.path.exists(p) and (not os.path.isdir(p)) and '-image-' in os.path.basename(p):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600377 self.rootfs = p
Andrew Geissler9aee5002022-03-30 16:27:02 +0000378 # Check filename against self.fstypes can handle <file>.cpio.gz,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500379 # otherwise, its type would be "gz", which is incorrect.
380 fst = ""
381 for t in self.fstypes:
382 if p.endswith(t):
383 fst = t
384 break
385 if not fst:
386 m = re.search('.*\.(.*)$', self.rootfs)
387 if m:
388 fst = m.group(1)
389 if fst:
390 self.check_arg_fstype(fst)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500391 qb = re.sub('\.' + fst + "$", '.qemuboot.conf', self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600392 if os.path.exists(qb):
393 self.qemuboot = qb
394 self.qbconfload = True
395 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500396 logger.warning("%s doesn't exist, will try to remove '.rootfs' from filename" % qb)
397 # They to remove .rootfs (IMAGE_NAME_SUFFIX) as well
398 qb = re.sub('\.rootfs.qemuboot.conf$', '.qemuboot.conf', qb)
399 if os.path.exists(qb):
400 self.qemuboot = qb
401 self.qbconfload = True
402 else:
403 logger.warning("%s doesn't exist" % qb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600404 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500405 raise RunQemuError("Can't find FSTYPE from: %s" % p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500406
407 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600408 if self.is_deploy_dir_image(p):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500409 logger.debug('DEPLOY_DIR_IMAGE: %s' % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600410 self.set("DEPLOY_DIR_IMAGE", p)
411 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500412 logger.debug("Assuming %s is an nfs rootfs" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600413 self.check_arg_nfs(p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500414 elif os.path.basename(p).startswith('ovmf'):
415 self.ovmf_bios.append(p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600416 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500417 raise RunQemuError("Unknown path arg %s" % p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500418
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600419 def check_arg_machine(self, arg):
420 """Check whether it is a machine"""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500421 if self.get('MACHINE') == arg:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600422 return
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500423 elif self.get('MACHINE') and self.get('MACHINE') != arg:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500424 raise RunQemuError("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500425 elif re.search('/', arg):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500426 raise RunQemuError("Unknown arg: %s" % arg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500427
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500428 logger.debug('Assuming MACHINE = %s' % arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500429
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600430 # if we're running under testimage, or similarly as a child
431 # of an existing bitbake invocation, we can't invoke bitbake
432 # to validate the MACHINE setting and must assume it's correct...
433 # FIXME: testimage.bbclass exports these two variables into env,
434 # are there other scenarios in which we need to support being
435 # invoked by bitbake?
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500436 deploy = self.get('DEPLOY_DIR_IMAGE')
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500437 image_link_name = self.get('IMAGE_LINK_NAME')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500438 bbchild = deploy and self.get('OE_TMPDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600439 if bbchild:
440 self.set_machine_deploy_dir(arg, deploy)
441 return
442 # also check whether we're running under a sourced toolchain
443 # environment file
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500444 if self.get('OECORE_NATIVE_SYSROOT'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600445 self.set("MACHINE", arg)
446 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500447
Andrew Geissler82c905d2020-04-13 13:39:40 -0500448 self.bitbake_e = self.run_bitbake_env(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600449 # bitbake -e doesn't report invalid MACHINE as an error, so
450 # let's check DEPLOY_DIR_IMAGE to make sure that it is a valid
451 # MACHINE.
452 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
453 if s:
454 deploy_dir_image = s.group(1)
455 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500456 raise RunQemuError("bitbake -e %s" % self.bitbake_e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600457 if self.is_deploy_dir_image(deploy_dir_image):
458 self.set_machine_deploy_dir(arg, deploy_dir_image)
459 else:
460 logger.error("%s not a directory valid DEPLOY_DIR_IMAGE" % deploy_dir_image)
461 self.set("MACHINE", arg)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500462 if not image_link_name:
463 s = re.search('^IMAGE_LINK_NAME="(.*)"', self.bitbake_e, re.M)
464 if s:
465 image_link_name = s.group(1)
466 self.set("IMAGE_LINK_NAME", image_link_name)
467 logger.debug('Using IMAGE_LINK_NAME = "%s"' % image_link_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468
Andrew Geisslerc182c622020-05-15 14:13:32 -0500469 def set_dri_path(self):
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500470 drivers_path = os.path.join(self.bindir_native, '../lib/dri')
471 if not os.path.exists(drivers_path) or not os.listdir(drivers_path):
472 raise RunQemuError("""
473qemu has been built without opengl support and accelerated graphics support is not available.
474To enable it, add:
475DISTRO_FEATURES_NATIVE:append = " opengl"
476DISTRO_FEATURES_NATIVESDK:append = " opengl"
477to your build configuration.
478""")
479 self.qemu_environ['LIBGL_DRIVERS_PATH'] = drivers_path
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000480
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600481 def check_args(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500482 for debug in ("-d", "--debug"):
483 if debug in sys.argv:
484 logger.setLevel(logging.DEBUG)
485 sys.argv.remove(debug)
486
487 for quiet in ("-q", "--quiet"):
488 if quiet in sys.argv:
489 logger.setLevel(logging.ERROR)
490 sys.argv.remove(quiet)
491
Andrew Geisslerc182c622020-05-15 14:13:32 -0500492 if 'gl' not in sys.argv[1:] and 'gl-es' not in sys.argv[1:]:
Patrick Williams2390b1b2022-11-03 13:47:49 -0500493 self.qemu_environ['SDL_RENDER_DRIVER'] = 'software'
494 self.qemu_environ['SDL_FRAMEBUFFER_ACCELERATION'] = 'false'
Andrew Geisslerc182c622020-05-15 14:13:32 -0500495
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600496 unknown_arg = ""
497 for arg in sys.argv[1:]:
Brad Bishop15ae2502019-06-18 21:44:24 -0400498 if arg in self.fstypes + self.vmtypes + self.wictypes:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600499 self.check_arg_fstype(arg)
500 elif arg == 'nographic':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500501 self.nographic = True
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500502 elif arg == "nonetwork":
503 self.nonetwork = True
Brad Bishop19323692019-04-05 15:28:33 -0400504 elif arg == 'sdl':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500505 self.sdl = True
Brad Bishopa34c0302019-09-23 22:34:48 -0400506 elif arg == 'gtk':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500507 self.gtk = True
508 elif arg == 'gl':
509 self.gl = True
Patrick Williams2390b1b2022-11-03 13:47:49 -0500510 elif arg == 'gl-es':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500511 self.gl_es = True
Brad Bishop19323692019-04-05 15:28:33 -0400512 elif arg == 'egl-headless':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500513 self.egl_headless = True
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600514 elif arg == 'novga':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500515 self.novga = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600516 elif arg == 'serial':
Brad Bishop19323692019-04-05 15:28:33 -0400517 self.serialconsole = True
518 elif arg == "serialstdio":
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600519 self.serialstdio = True
520 elif arg == 'audio':
521 logger.info("Enabling audio in qemu")
522 logger.info("Please install sound drivers in linux host")
523 self.audio_enabled = True
524 elif arg == 'kvm':
525 self.kvm_enabled = True
526 elif arg == 'kvm-vhost':
527 self.vhost_enabled = True
528 elif arg == 'slirp':
529 self.slirp_enabled = True
Andrew Geissler82c905d2020-04-13 13:39:40 -0500530 elif arg.startswith('bridge='):
531 self.net_bridge = '%s' % arg[len('bridge='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600532 elif arg == 'snapshot':
533 self.snapshot = True
534 elif arg == 'publicvnc':
Patrick Williams03907ee2022-05-01 06:28:52 -0500535 self.publicvnc = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600536 self.qemu_opt_script += ' -vnc :0'
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500537 elif arg == 'guestagent':
538 self.guest_agent = True
539 elif arg.startswith('guestagent-sockpath='):
540 self.guest_agent_sockpath = '%s' % arg[len('guestagent-sockpath='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600541 elif arg.startswith('tcpserial='):
Brad Bishop15ae2502019-06-18 21:44:24 -0400542 self.tcpserial_portnum = '%s' % arg[len('tcpserial='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600543 elif arg.startswith('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600544 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600545 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500546 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600547 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
548 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500549 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600550 # Lazy rootfs
551 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500552 elif arg.startswith('ovmf'):
553 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600554 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500555 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600556 if (not unknown_arg) or unknown_arg == arg:
557 unknown_arg = arg
558 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500559 raise RunQemuError("Can't handle two unknown args: %s %s\n"
560 "Try 'runqemu help' on how to use it" % \
561 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600562 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300563 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500564 if self.get('DEPLOY_DIR_IMAGE'):
565 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
566 if unknown_arg == machine:
567 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500568
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600569 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500571 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500572 self.load_bitbake_env(target=self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500573 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
574 if s:
575 self.set("DEPLOY_DIR_IMAGE", s.group(1))
576
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500577 if not self.get('IMAGE_LINK_NAME') and self.rootfs:
578 s = re.search('^IMAGE_LINK_NAME="(.*)"', self.bitbake_e, re.M)
579 if s:
580 image_link_name = s.group(1)
581 self.set("IMAGE_LINK_NAME", image_link_name)
582 logger.debug('Using IMAGE_LINK_NAME = "%s"' % image_link_name)
583
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600584 def check_kvm(self):
585 """Check kvm and kvm-host"""
586 if not (self.kvm_enabled or self.vhost_enabled):
William A. Kennington IIIac69b482021-06-02 12:28:27 -0700587 self.qemu_opt_script += ' %s %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU'), self.get('QB_SMP'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600588 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500589
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600590 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500591 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500592
William A. Kennington IIIac69b482021-06-02 12:28:27 -0700593 self.qemu_opt_script += ' %s %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'), self.get('QB_SMP'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600594 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
595 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
596 dev_kvm = '/dev/kvm'
597 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400598 if self.qemu_system.endswith(('i386', 'x86_64')):
599 with open('/proc/cpuinfo', 'r') as f:
600 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
601 if not kvm_cap:
602 logger.error("You are trying to enable KVM on a cpu without VT support.")
603 logger.error("Remove kvm from the command-line, or refer:")
604 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600606 if not os.path.exists(dev_kvm):
607 logger.error("Missing KVM device. Have you inserted kvm modules?")
608 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500609 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500610
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600611 if os.access(dev_kvm, os.W_OK|os.R_OK):
612 self.qemu_opt_script += ' -enable-kvm'
613 else:
614 logger.error("You have no read or write permission on /dev/kvm.")
615 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500616 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500617
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600618 if self.vhost_enabled:
619 if not os.path.exists(dev_vhost):
620 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
621 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500622 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500623
Andrew Geissler635e0e42020-08-21 15:58:33 -0500624 if not os.access(dev_vhost, os.W_OK|os.R_OK):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600625 logger.error("You have no read or write permission on /dev/vhost-net.")
626 logger.error("Please change the ownership of this file as described at:")
Andrew Geissler635e0e42020-08-21 15:58:33 -0500627 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500628
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600629 def check_fstype(self):
630 """Check and setup FSTYPE"""
631 if not self.fstype:
632 fstype = self.get('QB_DEFAULT_FSTYPE')
633 if fstype:
634 self.fstype = fstype
635 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500636 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500637
Brad Bishop15ae2502019-06-18 21:44:24 -0400638 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
639 wic_fs = False
640 qb_fsinfo = self.get('QB_FSINFO')
641 if qb_fsinfo:
642 qb_fsinfo = qb_fsinfo.split()
643 for fsinfo in qb_fsinfo:
644 try:
645 fstype, fsflag = fsinfo.split(':')
646
647 if fstype == 'wic':
648 if fsflag == 'no-kernel-in-fs':
649 wic_fs = True
650 elif fsflag == 'kernel-in-fs':
651 wic_fs = False
652 else:
Andrew Geissler8f840682023-07-21 09:09:43 -0500653 logger.warning('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
Brad Bishop15ae2502019-06-18 21:44:24 -0400654 continue
655 else:
Andrew Geissler8f840682023-07-21 09:09:43 -0500656 logger.warning('QB_FSINFO is not supported for image type "%s"', fstype)
Brad Bishop15ae2502019-06-18 21:44:24 -0400657 continue
658
659 if fstype in self.fsinfo:
660 self.fsinfo[fstype].append(fsflag)
661 else:
662 self.fsinfo[fstype] = [fsflag]
663 except Exception:
664 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
665
666 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
667 if wic_fs:
668 self.fstypes = self.fstypes + self.wictypes
669 else:
670 self.vmtypes = self.vmtypes + self.wictypes
671
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600672 def check_rootfs(self):
673 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500675 if self.fstype == "none":
676 return
677
678 if self.get('ROOTFS'):
679 if not self.rootfs:
680 self.rootfs = self.get('ROOTFS')
681 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500682 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500683
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600684 if self.fstype == 'nfs':
685 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500686
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600687 if self.rootfs and not os.path.exists(self.rootfs):
688 # Lazy rootfs
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500689 self.rootfs = "%s/%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
690 self.get('IMAGE_LINK_NAME'),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600691 self.fstype)
692 elif not self.rootfs:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500693 glob_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
694 glob_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
695 globs = (glob_name, glob_link)
696 self.rootfs = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600697 if not self.rootfs:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500698 raise RunQemuError("Failed to find rootfs: %s or %s" % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500699
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600700 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500701 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500702
Brad Bishop08902b02019-08-20 09:16:51 -0400703 def setup_pkkek1(self):
704 """
705 Extract from PEM certificate the Platform Key and first Key
706 Exchange Key certificate string. The hypervisor needs to provide
707 it in the Type 11 SMBIOS table
708 """
709 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
710 try:
711 with open(pemcert, 'r') as pemfile:
712 key = pemfile.read().replace('\n', ''). \
713 replace('-----BEGIN CERTIFICATE-----', ''). \
714 replace('-----END CERTIFICATE-----', '')
715 self.ovmf_secboot_pkkek1 = key
716
717 except FileNotFoundError:
718 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
719
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500720 def check_ovmf(self):
721 """Check and set full path for OVMF firmware and variable file(s)."""
722
723 for index, ovmf in enumerate(self.ovmf_bios):
724 if os.path.exists(ovmf):
725 continue
726 for suffix in ('qcow2', 'bin'):
727 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
728 if os.path.exists(path):
729 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400730 if ovmf.endswith('secboot'):
731 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500732 break
733 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500734 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500735
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600736 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400737 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600738 # The vm image doesn't need a kernel
739 if self.fstype in self.vmtypes:
740 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500741
Brad Bishop316dfdd2018-06-25 12:45:53 -0400742 # See if the user supplied a KERNEL option
743 if self.get('KERNEL'):
744 self.kernel = self.get('KERNEL')
745
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500746 # QB_DEFAULT_KERNEL is always a full file path
747 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
748
749 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400750 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500751 return
752
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600753 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
754 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500755 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600756 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
757 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500758 globs = (kernel_match_name, kernel_match_link, kernel_startswith)
759 self.kernel = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600760 if not self.kernel:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500761 raise RunQemuError('KERNEL not found: %s, %s or %s' % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500762
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600763 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500764 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765
Brad Bishop316dfdd2018-06-25 12:45:53 -0400766 def check_dtb(self):
767 """Check and set dtb"""
768 # Did the user specify a device tree?
769 if self.get('DEVICE_TREE'):
770 self.dtb = self.get('DEVICE_TREE')
771 if not os.path.exists(self.dtb):
772 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
773 return
774
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600775 dtb = self.get('QB_DTB')
776 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400777 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500778 glob_match = "%s/%s" % (deploy_dir_image, dtb)
779 glob_startswith = "%s/%s*" % (deploy_dir_image, dtb)
780 glob_wild = "%s/*.dtb" % deploy_dir_image
781 globs = (glob_match, glob_startswith, glob_wild)
782 self.dtb = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600783 if not os.path.exists(self.dtb):
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500784 raise RunQemuError('DTB not found: %s, %s or %s' % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785
Brad Bishopc68388fc2019-08-26 01:33:31 -0400786 def check_bios(self):
787 """Check and set bios"""
788
789 # See if the user supplied a BIOS option
790 if self.get('BIOS'):
791 self.bios = self.get('BIOS')
792
793 # QB_DEFAULT_BIOS is always a full file path
794 bios_name = os.path.basename(self.get('QB_DEFAULT_BIOS'))
795
796 # The user didn't want a bios to be loaded
797 if (bios_name == "" or bios_name == "none") and not self.bios:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600798 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500799
Brad Bishopc68388fc2019-08-26 01:33:31 -0400800 if not self.bios:
801 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
802 self.bios = "%s/%s" % (deploy_dir_image, bios_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500803
Brad Bishopc68388fc2019-08-26 01:33:31 -0400804 if not self.bios:
805 raise RunQemuError('BIOS not found: %s' % bios_match_name)
806
807 if not os.path.exists(self.bios):
Patrick Williams213cb262021-08-07 19:21:33 -0500808 raise RunQemuError("BIOS %s not found" % self.bios)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400809
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500810
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600811 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600812 """
813 Both qemu and kernel needs memory settings, so check QB_MEM and set it
814 for both.
815 """
816 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600817 if s:
818 self.set('QB_MEM', '-m %s' % s.group(1))
819 elif not self.get('QB_MEM'):
Brad Bishop79641f22019-09-10 07:20:22 -0400820 logger.info('QB_MEM is not set, use 256M by default')
821 self.set('QB_MEM', '-m 256')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500822
Andrew Geissler99467da2019-02-25 18:54:23 -0600823 # Check and remove M or m suffix
824 qb_mem = self.get('QB_MEM')
825 if qb_mem.endswith('M') or qb_mem.endswith('m'):
826 qb_mem = qb_mem[:-1]
827
828 # Add -m prefix it not present
829 if not qb_mem.startswith('-m'):
830 qb_mem = '-m %s' % qb_mem
831
832 self.set('QB_MEM', qb_mem)
833
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800834 mach = self.get('MACHINE')
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500835 if not mach.startswith(('qemumips', 'qemux86', 'qemuloongarch64')):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800836 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
837
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600838 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500839
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600840 def check_tcpserial(self):
841 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400842 ports = self.tcpserial_portnum.split(':')
843 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600844 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400845 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600846 else:
Andrew Geissler20137392023-10-12 04:59:14 -0600847 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s,nodelay=on' % port
Brad Bishop15ae2502019-06-18 21:44:24 -0400848
849 if len(ports) > 1:
850 for port in ports[1:]:
Andrew Geissler20137392023-10-12 04:59:14 -0600851 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s,nodelay=on' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500852
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600853 def check_and_set(self):
854 """Check configs sanity and set when needed"""
855 self.validate_paths()
Andrew Geissler82c905d2020-04-13 13:39:40 -0500856 if not self.slirp_enabled and not self.net_bridge:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500857 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600858 # Check audio
859 if self.audio_enabled:
860 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500861 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600862 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800863 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600864 else:
865 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
866 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
867 else:
868 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500869
Brad Bishop15ae2502019-06-18 21:44:24 -0400870 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600871 self.check_kvm()
872 self.check_fstype()
873 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500874 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600875 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400876 self.check_dtb()
Brad Bishopc68388fc2019-08-26 01:33:31 -0400877 self.check_bios()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600878 self.check_mem()
879 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500880
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600881 def read_qemuboot(self):
882 if not self.qemuboot:
883 if self.get('DEPLOY_DIR_IMAGE'):
884 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600885 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800886 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600887 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500888
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600889 if self.rootfs and not os.path.exists(self.rootfs):
890 # Lazy rootfs
891 machine = self.get('MACHINE')
892 if not machine:
893 machine = os.path.basename(deploy_dir_image)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500894 if not self.get('IMAGE_LINK_NAME'):
895 raise RunQemuError("IMAGE_LINK_NAME wasn't set to find corresponding .qemuboot.conf file")
896 self.qemuboot = "%s/%s.qemuboot.conf" % (deploy_dir_image,
897 self.get('IMAGE_LINK_NAME'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600898 else:
899 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500900 logger.debug('Running %s...' % cmd)
901 try:
902 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
903 except subprocess.CalledProcessError as err:
904 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600905 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500906 for qb in qbs.split():
907 # Don't use initramfs when other choices unless fstype is ramfs
908 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
909 continue
910 self.qemuboot = qb
911 break
912 if not self.qemuboot:
913 # Use the first one when no choice
914 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600915 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500916
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600917 if not self.qemuboot:
918 # If we haven't found a .qemuboot.conf at this point it probably
919 # doesn't exist, continue without
920 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500921
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600922 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923 raise RunQemuError("Failed to find %s (wrong image name or BSP does not support running under qemu?)." % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500925 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500926
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600927 cf = configparser.ConfigParser()
928 cf.read(self.qemuboot)
929 for k, v in cf.items('config_bsp'):
930 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500931 if v.startswith("../"):
932 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
933 elif v == ".":
934 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600935 self.set(k_upper, v)
936
937 def validate_paths(self):
938 """Ensure all relevant path variables are set"""
939 # When we're started with a *.qemuboot.conf arg assume that image
940 # artefacts are relative to that file, rather than in whatever
941 # directory DEPLOY_DIR_IMAGE in the conf file points to.
942 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500943 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
944 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600945 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
946 self.set('DEPLOY_DIR_IMAGE', imgdir)
947
948 # If the STAGING_*_NATIVE directories from the config file don't exist
949 # and we're in a sourced OE build directory try to extract the paths
950 # from `bitbake -e`
951 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
952 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
953
954 if not havenative:
955 if not self.bitbake_e:
956 self.load_bitbake_env()
957
958 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500959 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600960 for nv in native_vars:
961 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
962 if s and s.group(1) != self.get(nv):
963 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
964 self.set(nv, s.group(1))
965 else:
966 # when we're invoked from a running bitbake instance we won't
967 # be able to call `bitbake -e`, then try:
968 # - get OE_TMPDIR from environment and guess paths based on it
969 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500970 tmpdir = self.get('OE_TMPDIR')
971 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600972 if tmpdir:
973 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
974 hostos, _, _, _, machine = os.uname()
975 buildsys = '%s-%s' % (machine, hostos.lower())
976 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
977 self.set('STAGING_DIR_NATIVE', staging_dir_native)
978 elif oecore_native_sysroot:
979 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
980 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
981 if self.get('STAGING_DIR_NATIVE'):
982 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
983 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
984 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
985 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
986
987 def print_config(self):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500988 logoutput = ['Continuing with the following parameters:']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600989 if not self.fstype in self.vmtypes:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500990 logoutput.append('KERNEL: [%s]' % self.kernel)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400991 if self.bios:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500992 logoutput.append('BIOS: [%s]' % self.bios)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600993 if self.dtb:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500994 logoutput.append('DTB: [%s]' % self.dtb)
995 logoutput.append('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400996 try:
997 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
998 except KeyError:
999 fstype_flags = ''
Andrew Geissler82c905d2020-04-13 13:39:40 -05001000 logoutput.append('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001001 if self.fstype == 'nfs':
Andrew Geissler82c905d2020-04-13 13:39:40 -05001002 logoutput.append('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001003 else:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001004 logoutput.append('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001005 if self.ovmf_bios:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001006 logoutput.append('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -04001007 if (self.ovmf_secboot_pkkek1):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001008 logoutput.append('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
1009 logoutput.append('CONFFILE: [%s]' % self.qemuboot)
1010 logoutput.append('')
1011 logger.info('\n'.join(logoutput))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001012
1013 def setup_nfs(self):
1014 if not self.nfs_server:
1015 if self.slirp_enabled:
1016 self.nfs_server = '10.0.2.2'
1017 else:
Andrew Geissler517393d2023-01-13 08:55:19 -06001018 self.nfs_server = '192.168.7.@GATEWAY@'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001019
Patrick Williams520786c2023-06-25 16:20:36 -05001020 nfsd_port = 3048 + self.nfs_instance
1021 lockdir = "/tmp/qemu-port-locks"
1022 self.make_lock_dir(lockdir)
1023 while not self.check_free_port('localhost', nfsd_port, lockdir):
1024 self.nfs_instance += 1
1025 nfsd_port += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001026
Patrick Williams520786c2023-06-25 16:20:36 -05001027 mountd_port = nfsd_port
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001028 # Export vars for runqemu-export-rootfs
1029 export_dict = {
1030 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001031 'NFSD_PORT': nfsd_port,
1032 'MOUNTD_PORT': mountd_port,
1033 }
1034 for k, v in export_dict.items():
1035 # Use '%s' since they are integers
1036 os.putenv(k, '%s' % v)
1037
Andrew Geisslerc5535c92023-01-27 16:10:19 -06001038 qb_nfsrootfs_extra_opt = self.get("QB_NFSROOTFS_EXTRA_OPT")
1039 if qb_nfsrootfs_extra_opt and not qb_nfsrootfs_extra_opt.startswith(","):
1040 qb_nfsrootfs_extra_opt = "," + qb_nfsrootfs_extra_opt
1041
1042 self.unfs_opts="nfsvers=3,port=%s,tcp,mountport=%s%s" % (nfsd_port, mountd_port, qb_nfsrootfs_extra_opt)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001043
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001044 # Extract .tar.bz2 or .tar.bz if no nfs dir
1045 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001046 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
1047 dest = "%s-nfsroot" % src_prefix
1048 if os.path.exists('%s.pseudo_state' % dest):
1049 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001050 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001051 else:
1052 src = ""
1053 src1 = '%s.tar.bz2' % src_prefix
1054 src2 = '%s.tar.gz' % src_prefix
1055 if os.path.exists(src1):
1056 src = src1
1057 elif os.path.exists(src2):
1058 src = src2
1059 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001060 raise RunQemuError("No NFS_DIR is set, and can't find %s or %s to extract" % (src1, src2))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001061 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -05001062 cmd = ('runqemu-extract-sdk', src, dest)
1063 logger.info('Running %s...' % str(cmd))
1064 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001065 raise RunQemuError('Failed to run %s' % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001066 self.rootfs = dest
Andrew Geisslerc926e172021-05-07 16:11:35 -05001067 self.cleanup_files.append(self.rootfs)
1068 self.cleanup_files.append('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001069
1070 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001071 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1072 logger.info('Running %s...' % str(cmd))
1073 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001074 raise RunQemuError('Failed to run %s' % str(cmd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001075
1076 self.nfs_running = True
1077
Andrew Geissler517393d2023-01-13 08:55:19 -06001078 def setup_cmd(self):
1079 cmd = self.get('QB_SETUP_CMD')
1080 if cmd != '':
1081 logger.info('Running setup command %s' % str(cmd))
1082 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001083 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001084
Andrew Geissler82c905d2020-04-13 13:39:40 -05001085 def setup_net_bridge(self):
1086 self.set('NETWORK_CMD', '-netdev bridge,br=%s,id=net0,helper=%s -device virtio-net-pci,netdev=net0 ' % (
1087 self.net_bridge, os.path.join(self.bindir_native, 'qemu-oe-bridge-helper')))
1088
Patrick Williams520786c2023-06-25 16:20:36 -05001089 def make_lock_dir(self, lockdir):
1090 if not os.path.exists(lockdir):
1091 # There might be a race issue when multi runqemu processess are
1092 # running at the same time.
1093 try:
1094 os.mkdir(lockdir)
1095 os.chmod(lockdir, 0o777)
1096 except FileExistsError:
1097 pass
1098 return
1099
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001100 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001101 """Setup user networking"""
1102
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001103 if self.fstype == 'nfs':
1104 self.setup_nfs()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001105 netconf = " " + self.cmdline_ip_slirp
1106 logger.info("Network configuration:%s", netconf)
1107 self.kernel_cmdline_script += netconf
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001108 # Port mapping
Andrew Geissler517393d2023-01-13 08:55:19 -06001109 hostfwd = ",hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:127.0.0.1:2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001110 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001111 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1112 # Figure out the port
1113 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1114 ports = [int(i) for i in ports]
1115 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001116
1117 lockdir = "/tmp/qemu-port-locks"
Patrick Williams520786c2023-06-25 16:20:36 -05001118 self.make_lock_dir(lockdir)
Brad Bishop08902b02019-08-20 09:16:51 -04001119
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001120 # Find a free port to avoid conflicts
1121 for p in ports[:]:
1122 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001123 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001124 p_new += 1
1125 mac += 1
1126 while p_new in ports:
1127 p_new += 1
1128 mac += 1
1129 if p != p_new:
1130 ports.append(p_new)
1131 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1132 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1133 mac = "%s%02x" % (self.mac_slirp, mac)
1134 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1135 # Print out port foward
1136 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1137 if hostfwd:
1138 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001139
1140 def setup_tap(self):
1141 """Setup tap"""
1142
1143 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1144 # devices, indicating that the user should not bring up new ones using
1145 # sudo.
1146 nosudo_flag = '/etc/runqemu-nosudo'
1147 self.qemuifup = shutil.which('runqemu-ifup')
1148 self.qemuifdown = shutil.which('runqemu-ifdown')
1149 ip = shutil.which('ip')
1150 lockdir = "/tmp/qemu-tap-locks"
1151
1152 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001153 logger.error("runqemu-ifup: %s" % self.qemuifup)
1154 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1155 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001156 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1157
Patrick Williams520786c2023-06-25 16:20:36 -05001158 self.make_lock_dir(lockdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001159
Brad Bishop977dc1a2019-02-06 16:01:43 -05001160 cmd = (ip, 'link')
1161 logger.debug('Running %s...' % str(cmd))
1162 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001163 # Matches line like: 6: tap0: <foo>
Patrick Williams520786c2023-06-25 16:20:36 -05001164 oe_tap_name = 'tap'
1165 if 'OE_TAP_NAME' in os.environ:
1166 oe_tap_name = os.environ['OE_TAP_NAME']
1167 tap_re = '^[0-9]+: +(' + oe_tap_name + '[0-9]+): <.*'
1168 possibles = re.findall(tap_re, ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001169 tap = ""
1170 for p in possibles:
1171 lockfile = os.path.join(lockdir, p)
1172 if os.path.exists('%s.skip' % lockfile):
1173 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1174 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001175 self.taplock = lockfile + '.lock'
1176 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001177 tap = p
1178 logger.info("Using preconfigured tap device %s" % tap)
1179 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1180 break
1181
1182 if not tap:
1183 if os.path.exists(nosudo_flag):
1184 logger.error("Error: There are no available tap devices to use for networking,")
1185 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001186 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001187
1188 gid = os.getgid()
1189 uid = os.getuid()
1190 logger.info("Setting up tap interface under sudo")
Andrew Geissler8f840682023-07-21 09:09:43 -05001191 cmd = ('sudo', self.qemuifup, str(gid))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001192 try:
1193 tap = subprocess.check_output(cmd).decode('utf-8').strip()
1194 except subprocess.CalledProcessError as e:
1195 logger.error('Setting up tap device failed:\n%s\nRun runqemu-gen-tapdevs to manually create one.' % str(e))
1196 sys.exit(1)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001197 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001198 self.taplock = lockfile + '.lock'
1199 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001200 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001201 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001202
1203 if not tap:
1204 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
Andrew Geissler82c905d2020-04-13 13:39:40 -05001205 sys.exit(1)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001206 self.tap = tap
Patrick Williams520786c2023-06-25 16:20:36 -05001207 tapnum = int(tap[len(oe_tap_name):])
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001208 gateway = tapnum * 2 + 1
1209 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001210 if self.fstype == 'nfs':
1211 self.setup_nfs()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001212 netconf = " " + self.cmdline_ip_tap
1213 netconf = netconf.replace('@CLIENT@', str(client))
1214 netconf = netconf.replace('@GATEWAY@', str(gateway))
Andrew Geissler517393d2023-01-13 08:55:19 -06001215 self.nfs_server = self.nfs_server.replace('@GATEWAY@', str(gateway))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001216 logger.info("Network configuration:%s", netconf)
1217 self.kernel_cmdline_script += netconf
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001218 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001219 qb_tap_opt = self.get('QB_TAP_OPT')
1220 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001221 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001222 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001223 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001224
1225 if self.vhost_enabled:
1226 qemu_tap_opt += ',vhost=on'
1227
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001228 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001229
1230 def setup_network(self):
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001231 if self.nonetwork or self.get('QB_NET') == 'none':
1232 self.set('NETWORK_CMD', '-nic none')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001233 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001234 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001235 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001236 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Andrew Geissler82c905d2020-04-13 13:39:40 -05001237 if self.net_bridge:
1238 self.setup_net_bridge()
1239 elif self.slirp_enabled:
1240 self.cmdline_ip_slirp = self.get('QB_CMDLINE_IP_SLIRP') or self.cmdline_ip_slirp
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001241 self.setup_slirp()
1242 else:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001243 self.cmdline_ip_tap = self.get('QB_CMDLINE_IP_TAP') or self.cmdline_ip_tap
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001244 self.setup_tap()
1245
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001246 def setup_rootfs(self):
1247 if self.get('QB_ROOTFS') == 'none':
1248 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001249 if 'wic.' in self.fstype:
1250 self.fstype = self.fstype[4:]
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001251 rootfs_format = self.fstype if self.fstype in ('vmdk', 'vhd', 'vhdx', 'qcow2', 'vdi') else 'raw'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001252
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001253 tmpfsdir = os.environ.get("RUNQEMU_TMPFS_DIR", None)
1254 if self.snapshot and tmpfsdir:
1255 newrootfs = os.path.join(tmpfsdir, os.path.basename(self.rootfs)) + "." + str(os.getpid())
Andrew Geissler09036742021-06-25 14:25:14 -05001256 logger.info("Copying rootfs to %s" % newrootfs)
1257 copy_start = time.time()
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001258 shutil.copyfile(self.rootfs, newrootfs)
Andrew Geissler09036742021-06-25 14:25:14 -05001259 logger.info("Copy done in %s seconds" % (time.time() - copy_start))
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001260 self.rootfs = newrootfs
1261 # Don't need a second copy now!
1262 self.snapshot = False
Andrew Geisslerc926e172021-05-07 16:11:35 -05001263 self.cleanup_files.append(newrootfs)
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001264
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001265 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1266 if qb_rootfs_opt:
1267 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1268 else:
1269 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1270
Andrew Geissler82c905d2020-04-13 13:39:40 -05001271 qb_rootfs_extra_opt = self.get("QB_ROOTFS_EXTRA_OPT")
1272 if qb_rootfs_extra_opt and not qb_rootfs_extra_opt.startswith(","):
1273 qb_rootfs_extra_opt = "," + qb_rootfs_extra_opt
1274
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001275 if self.fstype in ('cpio.gz', 'cpio'):
1276 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1277 self.rootfs_options = '-initrd %s' % self.rootfs
1278 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001279 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001280 if self.fstype in self.vmtypes:
1281 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001282 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001283 elif self.get('QB_DRIVE_TYPE'):
1284 drive_type = self.get('QB_DRIVE_TYPE')
1285 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001286 logger.info('Using scsi drive')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001287 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd%s' \
1288 % (self.rootfs, rootfs_format, qb_rootfs_extra_opt)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001289 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001290 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001291 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001292 elif drive_type.startswith("/dev/vdb"):
1293 logger.info('Using block virtio drive');
1294 vm_drive = '-drive id=disk0,file=%s,if=none,format=%s -device virtio-blk-device,drive=disk0%s' \
1295 % (self.rootfs, rootfs_format,qb_rootfs_extra_opt)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001296 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001297 # virtio might have been selected explicitly (just use it), or
1298 # is used as fallback (then warn about that).
1299 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001300 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1301 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1302 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001303 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001304
1305 # All branches above set vm_drive.
Andrew Geissler475cb722020-07-10 16:00:51 -05001306 self.rootfs_options = vm_drive
1307 if not self.fstype in self.vmtypes:
1308 self.rootfs_options += ' -no-reboot'
Andrew Geissler595f6302022-01-24 19:11:47 +00001309
1310 # By default, ' rw' is appended to QB_KERNEL_ROOT unless either ro or rw is explicitly passed.
1311 qb_kernel_root = self.get('QB_KERNEL_ROOT')
1312 qb_kernel_root_l = qb_kernel_root.split()
1313 if not ('ro' in qb_kernel_root_l or 'rw' in qb_kernel_root_l):
1314 qb_kernel_root += ' rw'
1315 self.kernel_cmdline = 'root=%s' % qb_kernel_root
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001316
1317 if self.fstype == 'nfs':
1318 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001319 k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server, os.path.abspath(self.rootfs), self.unfs_opts)
Brad Bishopf3f93bb2019-10-16 14:33:32 -04001320 self.kernel_cmdline = 'root=%s rw' % k_root
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001321
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001322 if self.fstype == 'none':
1323 self.rootfs_options = ''
1324
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001325 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1326
1327 def guess_qb_system(self):
1328 """attempt to determine the appropriate qemu-system binary"""
1329 mach = self.get('MACHINE')
1330 if not mach:
Patrick Williams864cc432023-02-09 14:54:44 -06001331 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemuloongarch64|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001332 if self.rootfs:
1333 match = re.match(search, self.rootfs)
1334 if match:
1335 mach = match.group(1)
1336 elif self.kernel:
1337 match = re.match(search, self.kernel)
1338 if match:
1339 mach = match.group(1)
1340
1341 if not mach:
1342 return None
1343
1344 if mach == 'qemuarm':
1345 qbsys = 'arm'
1346 elif mach == 'qemuarm64':
1347 qbsys = 'aarch64'
1348 elif mach == 'qemux86':
1349 qbsys = 'i386'
1350 elif mach == 'qemux86-64':
1351 qbsys = 'x86_64'
1352 elif mach == 'qemuppc':
1353 qbsys = 'ppc'
Patrick Williams864cc432023-02-09 14:54:44 -06001354 elif mach == 'qemuloongarch64':
1355 qbsys = 'loongarch64'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001356 elif mach == 'qemumips':
1357 qbsys = 'mips'
1358 elif mach == 'qemumips64':
1359 qbsys = 'mips64'
1360 elif mach == 'qemumipsel':
1361 qbsys = 'mipsel'
1362 elif mach == 'qemumips64el':
1363 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001364 elif mach == 'qemuriscv64':
1365 qbsys = 'riscv64'
1366 elif mach == 'qemuriscv32':
1367 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001368 else:
1369 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1370 logger.error("As %s is not among valid QEMU machines such as," % mach)
1371 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1372 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001373
1374 return 'qemu-system-%s' % qbsys
1375
Brad Bishop15ae2502019-06-18 21:44:24 -04001376 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001377 qemu_system = self.get('QB_SYSTEM_NAME')
1378 if not qemu_system:
1379 qemu_system = self.guess_qb_system()
1380 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001381 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001382 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001383
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001384 def check_render_nodes(self):
1385 render_hint = """If /dev/dri/renderD* is absent due to lack of suitable GPU, 'modprobe vgem' will create one suitable for mesa llvmpipe software renderer."""
1386 try:
1387 content = os.listdir("/dev/dri")
Andrew Geissler5082cc72023-09-11 08:41:39 -04001388 nodes = [i for i in content if i.startswith('renderD')]
1389 if len(nodes) == 0:
1390 raise RunQemuError("No render nodes found in /dev/dri/: %s. %s" %(content, render_hint))
1391 for n in nodes:
1392 try:
1393 with open(os.path.join("/dev/dri", n), "w") as f:
1394 f.close()
1395 break
1396 except IOError:
1397 pass
1398 else:
1399 raise RunQemuError("None of the render nodes in /dev/dri/ are accessible: %s; you may need to add yourself to 'render' group or otherwise ensure you have read-write permissions on one of them." %(nodes))
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001400 except FileNotFoundError:
1401 raise RunQemuError("/dev/dri directory does not exist; no render nodes available on this machine. %s" %(render_hint))
1402
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001403 def setup_guest_agent(self):
1404 if self.guest_agent == True:
1405 self.qemu_opt += ' -chardev socket,path=' + self.guest_agent_sockpath + ',server,nowait,id=qga0 '
1406 self.qemu_opt += ' -device virtio-serial '
1407 self.qemu_opt += ' -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 '
1408
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001409 def setup_vga(self):
1410 if self.nographic == True:
1411 if self.sdl == True:
1412 raise RunQemuError('Option nographic makes no sense alongside the sdl option.')
1413 if self.gtk == True:
1414 raise RunQemuError('Option nographic makes no sense alongside the gtk option.')
1415 self.qemu_opt += ' -nographic'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001416
1417 if self.novga == True:
1418 self.qemu_opt += ' -vga none'
1419 return
1420
1421 if (self.gl_es == True or self.gl == True) and (self.sdl == False and self.gtk == False):
1422 raise RunQemuError('Option gl/gl-es needs gtk or sdl option.')
1423
Patrick Williams03907ee2022-05-01 06:28:52 -05001424 # If we have no display option, we autodetect based upon what qemu supports. We
1425 # need our font setup and show-cusor below so we need to see what qemu --help says
1426 # is supported so we can pass our correct config in.
1427 if not self.nographic and not self.sdl and not self.gtk and not self.publicvnc and not self.egl_headless == True:
Patrick Williams2390b1b2022-11-03 13:47:49 -05001428 output = subprocess.check_output([self.qemu_bin, "--help"], universal_newlines=True, env=self.qemu_environ)
Patrick Williams03907ee2022-05-01 06:28:52 -05001429 if "-display gtk" in output:
1430 self.gtk = True
1431 elif "-display sdl" in output:
1432 self.sdl = True
Andrew Geissler595f6302022-01-24 19:11:47 +00001433 else:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001434 self.qemu_opt += ' -display none'
Andrew Geissler595f6302022-01-24 19:11:47 +00001435
Patrick Williams03907ee2022-05-01 06:28:52 -05001436 if self.sdl == True or self.gtk == True or self.egl_headless == True:
1437
1438 if self.qemu_system.endswith(('i386', 'x86_64')):
1439 if self.gl or self.gl_es or self.egl_headless:
1440 self.qemu_opt += ' -device virtio-vga-gl '
1441 else:
1442 self.qemu_opt += ' -device virtio-vga '
1443
1444 self.qemu_opt += ' -display '
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001445 if self.egl_headless == True:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001446 self.check_render_nodes()
Andrew Geissler595f6302022-01-24 19:11:47 +00001447 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001448 self.qemu_opt += 'egl-headless,'
1449 else:
1450 if self.sdl == True:
1451 self.qemu_opt += 'sdl,'
1452 elif self.gtk == True:
Patrick Williams2390b1b2022-11-03 13:47:49 -05001453 self.qemu_environ['FONTCONFIG_PATH'] = '/etc/fonts'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001454 self.qemu_opt += 'gtk,'
1455
1456 if self.gl == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001457 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001458 self.qemu_opt += 'gl=on,'
1459 elif self.gl_es == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001460 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001461 self.qemu_opt += 'gl=es,'
1462 self.qemu_opt += 'show-cursor=on'
1463
1464 self.qemu_opt += ' %s' %self.get('QB_GRAPHICS')
1465
1466 def setup_serial(self):
1467 # Setup correct kernel command line for serial
Andrew Geissler595f6302022-01-24 19:11:47 +00001468 if self.get('SERIAL_CONSOLES') and (self.serialstdio == True or self.serialconsole == True or self.nographic == True or self.tcpserial_portnum):
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001469 for entry in self.get('SERIAL_CONSOLES').split(' '):
1470 self.kernel_cmdline_script += ' console=%s' %entry.split(';')[1]
1471
Andrew Geissler220dafd2023-10-04 10:18:08 -05001472 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES).
1473 # If no serial or serialtcp options were specified, only ttyS0 is created
1474 # and sysvinit shows an error trying to enable ttyS1:
1475 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1476 serial_num = len(re.findall("-serial", self.qemu_opt))
1477
1478 # Assume if the user passed serial options, they know what they want
1479 # and pad to two devices
1480 if serial_num == 1:
1481 self.qemu_opt += " -serial null"
1482 elif serial_num >= 2:
1483 return
1484
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001485 if self.serialstdio == True or self.nographic == True:
1486 self.qemu_opt += " -serial mon:stdio"
1487 else:
1488 self.qemu_opt += " -serial mon:vc"
1489 if self.serialconsole:
1490 if sys.stdin.isatty():
1491 subprocess.check_call(("stty", "intr", "^]"))
1492 logger.info("Interrupt character is '^]'")
1493
1494 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1495
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001496 serial_num = len(re.findall("-serial", self.qemu_opt))
1497 if serial_num < 2:
1498 self.qemu_opt += " -serial null"
1499
Patrick Williams03907ee2022-05-01 06:28:52 -05001500 def find_qemu(self):
Brad Bishop15ae2502019-06-18 21:44:24 -04001501 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001502
1503 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1504 # find QEMU in sysroot, it needs to use host's qemu.
1505 if not os.path.exists(qemu_bin):
1506 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1507 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001508 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001509 logger.info("Trying: %s" % qemu_bin_tmp)
1510 if os.path.exists(qemu_bin_tmp):
1511 qemu_bin = qemu_bin_tmp
1512 if not os.path.isabs(qemu_bin):
1513 qemu_bin = os.path.abspath(qemu_bin)
1514 logger.info("Using host's QEMU: %s" % qemu_bin)
1515 break
1516
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001517 if not os.access(qemu_bin, os.X_OK):
1518 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
Patrick Williams03907ee2022-05-01 06:28:52 -05001519 self.qemu_bin = qemu_bin
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001520
Patrick Williams03907ee2022-05-01 06:28:52 -05001521 def setup_final(self):
1522
1523 self.find_qemu()
1524
1525 self.qemu_opt = "%s %s %s %s %s" % (self.qemu_bin, self.get('NETWORK_CMD'), self.get('QB_RNG'), self.get('ROOTFS_OPTIONS'), self.get('QB_OPT_APPEND').replace('@DEPLOY_DIR_IMAGE@', self.get('DEPLOY_DIR_IMAGE')))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001526
1527 for ovmf in self.ovmf_bios:
1528 format = ovmf.rsplit('.', 1)[-1]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001529 if format == "bin":
1530 format = "raw"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001531 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001532
1533 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001534
Brad Bishop08902b02019-08-20 09:16:51 -04001535 if self.ovmf_secboot_pkkek1:
1536 # Provide the Platform Key and first Key Exchange Key certificate as an
1537 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1538 # with "application prefix" of the EnrollDefaultKeys.efi application
1539 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1540 + self.ovmf_secboot_pkkek1
1541
Andrew Geissler99467da2019-02-25 18:54:23 -06001542 # Append qemuparams to override previous settings
1543 if self.qemuparams:
1544 self.qemu_opt += ' ' + self.qemuparams
1545
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001546 if self.snapshot:
1547 self.qemu_opt += " -snapshot"
1548
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001549 self.setup_guest_agent()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001550 self.setup_serial()
1551 self.setup_vga()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001552
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001553 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001554 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001555 if self.kernel:
Andrew Geissler615f2f12022-07-15 14:00:58 -05001556 kernel_opts = "-kernel %s" % (self.kernel)
1557 if self.get('QB_KERNEL_CMDLINE') == "none":
1558 if self.bootparams:
1559 kernel_opts += " -append '%s'" % (self.bootparams)
1560 else:
1561 kernel_opts += " -append '%s %s %s %s'" % (self.kernel_cmdline,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001562 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1563 self.bootparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001564 if self.dtb:
1565 kernel_opts += " -dtb %s" % self.dtb
1566 else:
1567 kernel_opts = ""
Patrick Williams213cb262021-08-07 19:21:33 -05001568
1569 if self.bios:
1570 self.qemu_opt += " -bios %s" % self.bios
1571
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001572 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001573 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001574 logger.info('Running %s\n' % cmd)
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001575 with open('/proc/uptime', 'r') as f:
1576 uptime_seconds = f.readline().split()[0]
1577 logger.info('Host uptime: %s\n' % uptime_seconds)
Brad Bishopf86d0552018-12-04 14:18:15 -08001578 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001579 if self.taplock_descriptor:
1580 pass_fds = [self.taplock_descriptor.fileno()]
1581 if len(self.portlocks):
1582 for descriptor in self.portlocks.values():
1583 pass_fds.append(descriptor.fileno())
Patrick Williams2390b1b2022-11-03 13:47:49 -05001584 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds, env=self.qemu_environ)
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001585 self.qemuprocess = process
Brad Bishop004d4992018-10-02 23:54:45 +02001586 retcode = process.wait()
1587 if retcode:
1588 if retcode == -signal.SIGTERM:
1589 logger.info("Qemu terminated by SIGTERM")
1590 else:
1591 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001592
Andrew Geissler517393d2023-01-13 08:55:19 -06001593 def cleanup_cmd(self):
1594 cmd = self.get('QB_CLEANUP_CMD')
1595 if cmd != '':
1596 logger.info('Running cleanup command %s' % str(cmd))
1597 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001598 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001599
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001600 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001601 if self.cleaned:
1602 return
1603
1604 # avoid dealing with SIGTERM when cleanup function is running
1605 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1606
1607 logger.info("Cleaning up")
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001608
1609 if self.qemuprocess:
1610 try:
1611 # give it some time to shut down, ignore return values and output
1612 self.qemuprocess.send_signal(signal.SIGTERM)
1613 self.qemuprocess.communicate(timeout=5)
1614 except subprocess.TimeoutExpired:
1615 self.qemuprocess.kill()
1616
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001617 with open('/proc/uptime', 'r') as f:
1618 uptime_seconds = f.readline().split()[0]
1619 logger.info('Host uptime: %s\n' % uptime_seconds)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001620 if self.cleantap:
Andrew Geissler8f840682023-07-21 09:09:43 -05001621 cmd = ('sudo', self.qemuifdown, self.tap)
Brad Bishop977dc1a2019-02-06 16:01:43 -05001622 logger.debug('Running %s' % str(cmd))
1623 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001624 self.release_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001625
1626 if self.nfs_running:
1627 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001628 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1629 logger.debug('Running %s' % str(cmd))
1630 subprocess.check_call(cmd)
Patrick Williams520786c2023-06-25 16:20:36 -05001631 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001632
1633 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001634 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001635
Andrew Geisslerc926e172021-05-07 16:11:35 -05001636 if self.cleanup_files:
1637 for ent in self.cleanup_files:
1638 logger.info('Removing %s' % ent)
1639 if os.path.isfile(ent):
1640 os.remove(ent)
1641 else:
1642 shutil.rmtree(ent)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001643
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001644 # Deliberately ignore the return code of 'tput smam'.
1645 subprocess.call(["tput", "smam"])
1646
Brad Bishop004d4992018-10-02 23:54:45 +02001647 self.cleaned = True
1648
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001649 def run_bitbake_env(self, mach=None, target=''):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001650 bitbake = shutil.which('bitbake')
1651 if not bitbake:
1652 return
1653
1654 if not mach:
1655 mach = self.get('MACHINE')
1656
Andrew Geissler82c905d2020-04-13 13:39:40 -05001657 multiconfig = self.get('MULTICONFIG')
1658 if multiconfig:
1659 multiconfig = "mc:%s" % multiconfig
1660
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001661 if mach:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001662 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001663 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001664 cmd = 'bitbake -e %s %s' % (multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001665
1666 logger.info('Running %s...' % cmd)
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001667 try:
1668 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1669 except subprocess.CalledProcessError as err:
1670 logger.warning("Couldn't run '%s' to gather environment information, maybe the target wasn't an image name, will retry with virtual/kernel as a target:\n%s" % (cmd, err.output.decode('utf-8')))
1671 # need something with IMAGE_NAME_SUFFIX/IMAGE_LINK_NAME defined (kernel also inherits image-artifact-names.bbclass)
1672 target = 'virtual/kernel'
1673 if mach:
1674 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
1675 else:
1676 cmd = 'bitbake -e %s %s' % (multiconfig, target)
1677 try:
1678 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1679 except subprocess.CalledProcessError as err:
1680 logger.warning("Couldn't run '%s' to gather environment information, giving up with 'bitbake -e':\n%s" % (cmd, err.output.decode('utf-8')))
1681 return ''
Andrew Geissler82c905d2020-04-13 13:39:40 -05001682
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001683
1684 def load_bitbake_env(self, mach=None, target=None):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001685 if self.bitbake_e:
1686 return
1687
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001688 self.bitbake_e = self.run_bitbake_env(mach=mach, target=target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001689
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001690 def validate_combos(self):
1691 if (self.fstype in self.vmtypes) and self.kernel:
1692 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1693
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001694 @property
1695 def bindir_native(self):
1696 result = self.get('STAGING_BINDIR_NATIVE')
1697 if result and os.path.exists(result):
1698 return result
1699
Andrew Geissler82c905d2020-04-13 13:39:40 -05001700 cmd = ['bitbake', '-e']
1701 multiconfig = self.get('MULTICONFIG')
1702 if multiconfig:
1703 cmd.append('mc:%s:qemu-helper-native' % multiconfig)
1704 else:
1705 cmd.append('qemu-helper-native')
1706
Brad Bishop977dc1a2019-02-06 16:01:43 -05001707 logger.info('Running %s...' % str(cmd))
1708 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001709
1710 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1711 if match:
1712 result = match.group(1)
1713 if os.path.exists(result):
1714 self.set('STAGING_BINDIR_NATIVE', result)
1715 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001716 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001717 else:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001718 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001719
1720
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001721def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001722 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001723 print_usage()
1724 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001725 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001726 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001727
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001728 renice = os.path.expanduser("~/bin/runqemu-renice")
1729 if os.path.exists(renice):
1730 logger.info('Using %s to renice' % renice)
1731 subprocess.check_call([renice, str(os.getpid())])
1732
Brad Bishop004d4992018-10-02 23:54:45 +02001733 def sigterm_handler(signum, frame):
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001734 logger.info("Received signal: %s" % (signum))
Brad Bishop004d4992018-10-02 23:54:45 +02001735 config.cleanup()
Brad Bishop004d4992018-10-02 23:54:45 +02001736 signal.signal(signal.SIGTERM, sigterm_handler)
1737
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001738 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001739 config.read_qemuboot()
1740 config.check_and_set()
1741 # Check whether the combos is valid or not
1742 config.validate_combos()
1743 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001744 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001745 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001746 config.setup_final()
Andrew Geissler517393d2023-01-13 08:55:19 -06001747 config.setup_cmd()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001748 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001749 except RunQemuError as err:
1750 logger.error(err)
1751 return 1
1752 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001753 import traceback
1754 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001755 return 1
1756 finally:
Andrew Geissler517393d2023-01-13 08:55:19 -06001757 config.cleanup_cmd()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001758 config.cleanup()
1759
1760if __name__ == "__main__":
1761 sys.exit(main())