blob: 56715c3e1e19fc3590f56d5a4b09c0c3e0227f8b [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',
201 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz')
Brad Bishop08902b02019-08-20 09:16:51 -0400202 self.vmtypes = ('hddimg', 'iso')
Brad Bishop15ae2502019-06-18 21:44:24 -0400203 self.fsinfo = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500204 self.network_device = "-device e1000,netdev=net0,mac=@MAC@"
Andrew Geissler82c905d2020-04-13 13:39:40 -0500205 self.cmdline_ip_slirp = "ip=dhcp"
Andrew Geissler595f6302022-01-24 19:11:47 +0000206 self.cmdline_ip_tap = "ip=192.168.7.@CLIENT@::192.168.7.@GATEWAY@:255.255.255.0::eth0:off:8.8.8.8"
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500207 # Use different mac section for tap and slirp to avoid
208 # conflicts, e.g., when one is running with tap, the other is
209 # running with slirp.
210 # The last section is dynamic, which is for avoiding conflicts,
211 # when multiple qemus are running, e.g., when multiple tap or
212 # slirp qemus are running.
213 self.mac_tap = "52:54:00:12:34:"
214 self.mac_slirp = "52:54:00:12:35:"
Brad Bishop004d4992018-10-02 23:54:45 +0200215 # pid of the actual qemu process
Patrick Williams2390b1b2022-11-03 13:47:49 -0500216 self.qemu_environ = os.environ.copy()
Andrew Geissler6aa7eec2023-03-03 12:41:14 -0600217 self.qemuprocess = None
Brad Bishop004d4992018-10-02 23:54:45 +0200218 # avoid cleanup twice
219 self.cleaned = False
Andrew Geisslerc926e172021-05-07 16:11:35 -0500220 # Files to cleanup after run
221 self.cleanup_files = []
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500222 self.guest_agent = False
223 self.guest_agent_sockpath = '/tmp/qga.sock'
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500224
Brad Bishop08902b02019-08-20 09:16:51 -0400225 def acquire_taplock(self, error=True):
226 logger.debug("Acquiring lockfile %s..." % self.taplock)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600227 try:
Brad Bishop08902b02019-08-20 09:16:51 -0400228 self.taplock_descriptor = open(self.taplock, 'w')
229 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600230 except Exception as e:
Brad Bishop08902b02019-08-20 09:16:51 -0400231 msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500232 if error:
233 logger.error(msg)
234 else:
235 logger.info(msg)
Brad Bishop08902b02019-08-20 09:16:51 -0400236 if self.taplock_descriptor:
237 self.taplock_descriptor.close()
238 self.taplock_descriptor = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 return False
240 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500241
Brad Bishop08902b02019-08-20 09:16:51 -0400242 def release_taplock(self):
243 if self.taplock_descriptor:
Brad Bishopf86d0552018-12-04 14:18:15 -0800244 logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
Andrew Geissler5f350902021-07-23 13:09:54 -0400245 # We pass the fd to the qemu process and if we unlock here, it would unlock for
246 # that too. Therefore don't unlock, just close
247 # fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN)
Brad Bishop08902b02019-08-20 09:16:51 -0400248 self.taplock_descriptor.close()
Andrew Geissler5f350902021-07-23 13:09:54 -0400249 # Removing the file is a potential race, don't do that either
250 # os.remove(self.taplock)
Brad Bishop08902b02019-08-20 09:16:51 -0400251 self.taplock_descriptor = None
252
253 def check_free_port(self, host, port, lockdir):
254 """ Check whether the port is free or not """
255 import socket
256 from contextlib import closing
257
258 lockfile = os.path.join(lockdir, str(port) + '.lock')
259 if self.acquire_portlock(lockfile):
260 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
261 if sock.connect_ex((host, port)) == 0:
262 # Port is open, so not free
263 self.release_portlock(lockfile)
264 return False
265 else:
266 # Port is not open, so free
267 return True
268 else:
269 return False
270
271 def acquire_portlock(self, lockfile):
272 logger.debug("Acquiring lockfile %s..." % lockfile)
273 try:
274 portlock_descriptor = open(lockfile, 'w')
275 self.portlocks.update({lockfile: portlock_descriptor})
276 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB)
277 except Exception as e:
278 msg = "Acquiring lockfile %s failed: %s" % (lockfile, e)
279 logger.info(msg)
280 if lockfile in self.portlocks.keys() and self.portlocks[lockfile]:
281 self.portlocks[lockfile].close()
282 del self.portlocks[lockfile]
283 return False
284 return True
285
286 def release_portlock(self, lockfile=None):
287 if lockfile != None:
Andrew Geissler5f350902021-07-23 13:09:54 -0400288 logger.debug("Releasing lockfile '%s'" % lockfile)
289 # We pass the fd to the qemu process and if we unlock here, it would unlock for
290 # that too. Therefore don't unlock, just close
291 # fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN)
292 self.portlocks[lockfile].close()
293 # Removing the file is a potential race, don't do that either
294 # os.remove(lockfile)
295 del self.portlocks[lockfile]
Brad Bishop08902b02019-08-20 09:16:51 -0400296 elif len(self.portlocks):
297 for lockfile, descriptor in self.portlocks.items():
298 logger.debug("Releasing lockfile '%s'" % lockfile)
Andrew Geissler5f350902021-07-23 13:09:54 -0400299 # We pass the fd to the qemu process and if we unlock here, it would unlock for
300 # that too. Therefore don't unlock, just close
301 # fcntl.flock(descriptor, fcntl.LOCK_UN)
Brad Bishop08902b02019-08-20 09:16:51 -0400302 descriptor.close()
Andrew Geissler5f350902021-07-23 13:09:54 -0400303 # Removing the file is a potential race, don't do that either
304 # os.remove(lockfile)
Brad Bishop08902b02019-08-20 09:16:51 -0400305 self.portlocks = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500306
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600307 def get(self, key):
308 if key in self.d:
309 return self.d.get(key)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500310 elif os.getenv(key):
311 return os.getenv(key)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600312 else:
313 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500314
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600315 def set(self, key, value):
316 self.d[key] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600318 def is_deploy_dir_image(self, p):
319 if os.path.isdir(p):
320 if not re.search('.qemuboot.conf$', '\n'.join(os.listdir(p)), re.M):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500321 logger.debug("Can't find required *.qemuboot.conf in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600322 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500323 if not any(map(lambda name: '-image-' in name, os.listdir(p))):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500324 logger.debug("Can't find *-image-* in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600325 return False
326 return True
327 else:
328 return False
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500329
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600330 def check_arg_fstype(self, fst):
331 """Check and set FSTYPE"""
Brad Bishop15ae2502019-06-18 21:44:24 -0400332 if fst not in self.fstypes + self.vmtypes + self.wictypes:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800333 logger.warning("Maybe unsupported FSTYPE: %s" % fst)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600334 if not self.fstype or self.fstype == fst:
335 if fst == 'ramfs':
336 fst = 'cpio.gz'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500337 if fst in ('tar.bz2', 'tar.gz'):
338 fst = 'nfs'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600339 self.fstype = fst
340 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500341 raise RunQemuError("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600343 def set_machine_deploy_dir(self, machine, deploy_dir_image):
344 """Set MACHINE and DEPLOY_DIR_IMAGE"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500345 logger.debug('MACHINE: %s' % machine)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600346 self.set("MACHINE", machine)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500347 logger.debug('DEPLOY_DIR_IMAGE: %s' % deploy_dir_image)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600348 self.set("DEPLOY_DIR_IMAGE", deploy_dir_image)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500349
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600350 def check_arg_nfs(self, p):
351 if os.path.isdir(p):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500352 self.rootfs = p
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600353 else:
354 m = re.match('(.*):(.*)', p)
355 self.nfs_server = m.group(1)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500356 self.rootfs = m.group(2)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600357 self.check_arg_fstype('nfs')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500358
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600359 def check_arg_path(self, p):
360 """
361 - Check whether it is <image>.qemuboot.conf or contains <image>.qemuboot.conf
Andrew Geissler9aee5002022-03-30 16:27:02 +0000362 - Check whether it is a kernel file
363 - Check whether it is an image file
364 - Check whether it is an NFS dir
365 - Check whether it is an OVMF flash file
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600366 """
367 if p.endswith('.qemuboot.conf'):
368 self.qemuboot = p
369 self.qbconfload = True
370 elif re.search('\.bin$', p) or re.search('bzImage', p) or \
371 re.search('zImage', p) or re.search('vmlinux', p) or \
372 re.search('fitImage', p) or re.search('uImage', p):
373 self.kernel = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500374 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 -0600375 self.rootfs = p
Andrew Geissler9aee5002022-03-30 16:27:02 +0000376 # Check filename against self.fstypes can handle <file>.cpio.gz,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500377 # otherwise, its type would be "gz", which is incorrect.
378 fst = ""
379 for t in self.fstypes:
380 if p.endswith(t):
381 fst = t
382 break
383 if not fst:
384 m = re.search('.*\.(.*)$', self.rootfs)
385 if m:
386 fst = m.group(1)
387 if fst:
388 self.check_arg_fstype(fst)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500389 qb = re.sub('\.' + fst + "$", '.qemuboot.conf', self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600390 if os.path.exists(qb):
391 self.qemuboot = qb
392 self.qbconfload = True
393 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500394 logger.warning("%s doesn't exist, will try to remove '.rootfs' from filename" % qb)
395 # They to remove .rootfs (IMAGE_NAME_SUFFIX) as well
396 qb = re.sub('\.rootfs.qemuboot.conf$', '.qemuboot.conf', qb)
397 if os.path.exists(qb):
398 self.qemuboot = qb
399 self.qbconfload = True
400 else:
401 logger.warning("%s doesn't exist" % qb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600402 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500403 raise RunQemuError("Can't find FSTYPE from: %s" % p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500404
405 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600406 if self.is_deploy_dir_image(p):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500407 logger.debug('DEPLOY_DIR_IMAGE: %s' % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600408 self.set("DEPLOY_DIR_IMAGE", p)
409 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500410 logger.debug("Assuming %s is an nfs rootfs" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600411 self.check_arg_nfs(p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500412 elif os.path.basename(p).startswith('ovmf'):
413 self.ovmf_bios.append(p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600414 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500415 raise RunQemuError("Unknown path arg %s" % p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500416
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600417 def check_arg_machine(self, arg):
418 """Check whether it is a machine"""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500419 if self.get('MACHINE') == arg:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600420 return
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500421 elif self.get('MACHINE') and self.get('MACHINE') != arg:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500422 raise RunQemuError("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500423 elif re.search('/', arg):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500424 raise RunQemuError("Unknown arg: %s" % arg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500425
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500426 logger.debug('Assuming MACHINE = %s' % arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500427
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600428 # if we're running under testimage, or similarly as a child
429 # of an existing bitbake invocation, we can't invoke bitbake
430 # to validate the MACHINE setting and must assume it's correct...
431 # FIXME: testimage.bbclass exports these two variables into env,
432 # are there other scenarios in which we need to support being
433 # invoked by bitbake?
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500434 deploy = self.get('DEPLOY_DIR_IMAGE')
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500435 image_link_name = self.get('IMAGE_LINK_NAME')
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500436 bbchild = deploy and self.get('OE_TMPDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600437 if bbchild:
438 self.set_machine_deploy_dir(arg, deploy)
439 return
440 # also check whether we're running under a sourced toolchain
441 # environment file
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500442 if self.get('OECORE_NATIVE_SYSROOT'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600443 self.set("MACHINE", arg)
444 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445
Andrew Geissler82c905d2020-04-13 13:39:40 -0500446 self.bitbake_e = self.run_bitbake_env(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600447 # bitbake -e doesn't report invalid MACHINE as an error, so
448 # let's check DEPLOY_DIR_IMAGE to make sure that it is a valid
449 # MACHINE.
450 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
451 if s:
452 deploy_dir_image = s.group(1)
453 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500454 raise RunQemuError("bitbake -e %s" % self.bitbake_e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600455 if self.is_deploy_dir_image(deploy_dir_image):
456 self.set_machine_deploy_dir(arg, deploy_dir_image)
457 else:
458 logger.error("%s not a directory valid DEPLOY_DIR_IMAGE" % deploy_dir_image)
459 self.set("MACHINE", arg)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500460 if not image_link_name:
461 s = re.search('^IMAGE_LINK_NAME="(.*)"', self.bitbake_e, re.M)
462 if s:
463 image_link_name = s.group(1)
464 self.set("IMAGE_LINK_NAME", image_link_name)
465 logger.debug('Using IMAGE_LINK_NAME = "%s"' % image_link_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466
Andrew Geisslerc182c622020-05-15 14:13:32 -0500467 def set_dri_path(self):
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500468 drivers_path = os.path.join(self.bindir_native, '../lib/dri')
469 if not os.path.exists(drivers_path) or not os.listdir(drivers_path):
470 raise RunQemuError("""
471qemu has been built without opengl support and accelerated graphics support is not available.
472To enable it, add:
473DISTRO_FEATURES_NATIVE:append = " opengl"
474DISTRO_FEATURES_NATIVESDK:append = " opengl"
475to your build configuration.
476""")
477 self.qemu_environ['LIBGL_DRIVERS_PATH'] = drivers_path
Andrew Geissler7e0e3c02022-02-25 20:34:39 +0000478
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600479 def check_args(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500480 for debug in ("-d", "--debug"):
481 if debug in sys.argv:
482 logger.setLevel(logging.DEBUG)
483 sys.argv.remove(debug)
484
485 for quiet in ("-q", "--quiet"):
486 if quiet in sys.argv:
487 logger.setLevel(logging.ERROR)
488 sys.argv.remove(quiet)
489
Andrew Geisslerc182c622020-05-15 14:13:32 -0500490 if 'gl' not in sys.argv[1:] and 'gl-es' not in sys.argv[1:]:
Patrick Williams2390b1b2022-11-03 13:47:49 -0500491 self.qemu_environ['SDL_RENDER_DRIVER'] = 'software'
492 self.qemu_environ['SDL_FRAMEBUFFER_ACCELERATION'] = 'false'
Andrew Geisslerc182c622020-05-15 14:13:32 -0500493
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600494 unknown_arg = ""
495 for arg in sys.argv[1:]:
Brad Bishop15ae2502019-06-18 21:44:24 -0400496 if arg in self.fstypes + self.vmtypes + self.wictypes:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600497 self.check_arg_fstype(arg)
498 elif arg == 'nographic':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500499 self.nographic = True
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500500 elif arg == "nonetwork":
501 self.nonetwork = True
Brad Bishop19323692019-04-05 15:28:33 -0400502 elif arg == 'sdl':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500503 self.sdl = True
Brad Bishopa34c0302019-09-23 22:34:48 -0400504 elif arg == 'gtk':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500505 self.gtk = True
506 elif arg == 'gl':
507 self.gl = True
Patrick Williams2390b1b2022-11-03 13:47:49 -0500508 elif arg == 'gl-es':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500509 self.gl_es = True
Brad Bishop19323692019-04-05 15:28:33 -0400510 elif arg == 'egl-headless':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500511 self.egl_headless = True
Andrew Geissler90fd73c2021-03-05 15:25:55 -0600512 elif arg == 'novga':
Andrew Geissler95ac1b82021-03-31 14:34:31 -0500513 self.novga = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600514 elif arg == 'serial':
Brad Bishop19323692019-04-05 15:28:33 -0400515 self.serialconsole = True
516 elif arg == "serialstdio":
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600517 self.serialstdio = True
518 elif arg == 'audio':
519 logger.info("Enabling audio in qemu")
520 logger.info("Please install sound drivers in linux host")
521 self.audio_enabled = True
522 elif arg == 'kvm':
523 self.kvm_enabled = True
524 elif arg == 'kvm-vhost':
525 self.vhost_enabled = True
526 elif arg == 'slirp':
527 self.slirp_enabled = True
Andrew Geissler82c905d2020-04-13 13:39:40 -0500528 elif arg.startswith('bridge='):
529 self.net_bridge = '%s' % arg[len('bridge='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600530 elif arg == 'snapshot':
531 self.snapshot = True
532 elif arg == 'publicvnc':
Patrick Williams03907ee2022-05-01 06:28:52 -0500533 self.publicvnc = True
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600534 self.qemu_opt_script += ' -vnc :0'
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500535 elif arg == 'guestagent':
536 self.guest_agent = True
537 elif arg.startswith('guestagent-sockpath='):
538 self.guest_agent_sockpath = '%s' % arg[len('guestagent-sockpath='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600539 elif arg.startswith('tcpserial='):
Brad Bishop15ae2502019-06-18 21:44:24 -0400540 self.tcpserial_portnum = '%s' % arg[len('tcpserial='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600541 elif arg.startswith('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600542 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600543 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500544 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600545 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
546 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500547 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600548 # Lazy rootfs
549 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500550 elif arg.startswith('ovmf'):
551 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600552 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500553 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600554 if (not unknown_arg) or unknown_arg == arg:
555 unknown_arg = arg
556 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500557 raise RunQemuError("Can't handle two unknown args: %s %s\n"
558 "Try 'runqemu help' on how to use it" % \
559 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600560 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300561 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500562 if self.get('DEPLOY_DIR_IMAGE'):
563 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
564 if unknown_arg == machine:
565 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500566
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600567 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500568
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500569 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500570 self.load_bitbake_env(target=self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500571 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
572 if s:
573 self.set("DEPLOY_DIR_IMAGE", s.group(1))
574
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500575 if not self.get('IMAGE_LINK_NAME') and self.rootfs:
576 s = re.search('^IMAGE_LINK_NAME="(.*)"', self.bitbake_e, re.M)
577 if s:
578 image_link_name = s.group(1)
579 self.set("IMAGE_LINK_NAME", image_link_name)
580 logger.debug('Using IMAGE_LINK_NAME = "%s"' % image_link_name)
581
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600582 def check_kvm(self):
583 """Check kvm and kvm-host"""
584 if not (self.kvm_enabled or self.vhost_enabled):
William A. Kennington IIIac69b482021-06-02 12:28:27 -0700585 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 -0600586 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500587
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600588 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500589 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500590
William A. Kennington IIIac69b482021-06-02 12:28:27 -0700591 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 -0600592 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
593 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
594 dev_kvm = '/dev/kvm'
595 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400596 if self.qemu_system.endswith(('i386', 'x86_64')):
597 with open('/proc/cpuinfo', 'r') as f:
598 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
599 if not kvm_cap:
600 logger.error("You are trying to enable KVM on a cpu without VT support.")
601 logger.error("Remove kvm from the command-line, or refer:")
602 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500603
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600604 if not os.path.exists(dev_kvm):
605 logger.error("Missing KVM device. Have you inserted kvm modules?")
606 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500607 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500608
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600609 if os.access(dev_kvm, os.W_OK|os.R_OK):
610 self.qemu_opt_script += ' -enable-kvm'
611 else:
612 logger.error("You have no read or write permission on /dev/kvm.")
613 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500614 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500615
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600616 if self.vhost_enabled:
617 if not os.path.exists(dev_vhost):
618 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
619 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500620 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500621
Andrew Geissler635e0e42020-08-21 15:58:33 -0500622 if not os.access(dev_vhost, os.W_OK|os.R_OK):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600623 logger.error("You have no read or write permission on /dev/vhost-net.")
624 logger.error("Please change the ownership of this file as described at:")
Andrew Geissler635e0e42020-08-21 15:58:33 -0500625 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500626
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600627 def check_fstype(self):
628 """Check and setup FSTYPE"""
629 if not self.fstype:
630 fstype = self.get('QB_DEFAULT_FSTYPE')
631 if fstype:
632 self.fstype = fstype
633 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500634 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500635
Brad Bishop15ae2502019-06-18 21:44:24 -0400636 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
637 wic_fs = False
638 qb_fsinfo = self.get('QB_FSINFO')
639 if qb_fsinfo:
640 qb_fsinfo = qb_fsinfo.split()
641 for fsinfo in qb_fsinfo:
642 try:
643 fstype, fsflag = fsinfo.split(':')
644
645 if fstype == 'wic':
646 if fsflag == 'no-kernel-in-fs':
647 wic_fs = True
648 elif fsflag == 'kernel-in-fs':
649 wic_fs = False
650 else:
651 logger.warn('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
652 continue
653 else:
654 logger.warn('QB_FSINFO is not supported for image type "%s"', fstype)
655 continue
656
657 if fstype in self.fsinfo:
658 self.fsinfo[fstype].append(fsflag)
659 else:
660 self.fsinfo[fstype] = [fsflag]
661 except Exception:
662 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
663
664 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
665 if wic_fs:
666 self.fstypes = self.fstypes + self.wictypes
667 else:
668 self.vmtypes = self.vmtypes + self.wictypes
669
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600670 def check_rootfs(self):
671 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500672
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500673 if self.fstype == "none":
674 return
675
676 if self.get('ROOTFS'):
677 if not self.rootfs:
678 self.rootfs = self.get('ROOTFS')
679 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500680 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500681
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600682 if self.fstype == 'nfs':
683 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600685 if self.rootfs and not os.path.exists(self.rootfs):
686 # Lazy rootfs
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500687 self.rootfs = "%s/%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
688 self.get('IMAGE_LINK_NAME'),
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600689 self.fstype)
690 elif not self.rootfs:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500691 glob_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
692 glob_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
693 globs = (glob_name, glob_link)
694 self.rootfs = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600695 if not self.rootfs:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500696 raise RunQemuError("Failed to find rootfs: %s or %s" % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500697
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600698 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500700
Brad Bishop08902b02019-08-20 09:16:51 -0400701 def setup_pkkek1(self):
702 """
703 Extract from PEM certificate the Platform Key and first Key
704 Exchange Key certificate string. The hypervisor needs to provide
705 it in the Type 11 SMBIOS table
706 """
707 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
708 try:
709 with open(pemcert, 'r') as pemfile:
710 key = pemfile.read().replace('\n', ''). \
711 replace('-----BEGIN CERTIFICATE-----', ''). \
712 replace('-----END CERTIFICATE-----', '')
713 self.ovmf_secboot_pkkek1 = key
714
715 except FileNotFoundError:
716 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
717
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500718 def check_ovmf(self):
719 """Check and set full path for OVMF firmware and variable file(s)."""
720
721 for index, ovmf in enumerate(self.ovmf_bios):
722 if os.path.exists(ovmf):
723 continue
724 for suffix in ('qcow2', 'bin'):
725 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
726 if os.path.exists(path):
727 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400728 if ovmf.endswith('secboot'):
729 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500730 break
731 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500732 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500733
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400735 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600736 # The vm image doesn't need a kernel
737 if self.fstype in self.vmtypes:
738 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500739
Brad Bishop316dfdd2018-06-25 12:45:53 -0400740 # See if the user supplied a KERNEL option
741 if self.get('KERNEL'):
742 self.kernel = self.get('KERNEL')
743
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500744 # QB_DEFAULT_KERNEL is always a full file path
745 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
746
747 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400748 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500749 return
750
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600751 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
752 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500753 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600754 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
755 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500756 globs = (kernel_match_name, kernel_match_link, kernel_startswith)
757 self.kernel = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600758 if not self.kernel:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500759 raise RunQemuError('KERNEL not found: %s, %s or %s' % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600761 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500762 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500763
Brad Bishop316dfdd2018-06-25 12:45:53 -0400764 def check_dtb(self):
765 """Check and set dtb"""
766 # Did the user specify a device tree?
767 if self.get('DEVICE_TREE'):
768 self.dtb = self.get('DEVICE_TREE')
769 if not os.path.exists(self.dtb):
770 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
771 return
772
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600773 dtb = self.get('QB_DTB')
774 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400775 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500776 glob_match = "%s/%s" % (deploy_dir_image, dtb)
777 glob_startswith = "%s/%s*" % (deploy_dir_image, dtb)
778 glob_wild = "%s/*.dtb" % deploy_dir_image
779 globs = (glob_match, glob_startswith, glob_wild)
780 self.dtb = get_first_file(globs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600781 if not os.path.exists(self.dtb):
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500782 raise RunQemuError('DTB not found: %s, %s or %s' % globs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500783
Brad Bishopc68388fc2019-08-26 01:33:31 -0400784 def check_bios(self):
785 """Check and set bios"""
786
787 # See if the user supplied a BIOS option
788 if self.get('BIOS'):
789 self.bios = self.get('BIOS')
790
791 # QB_DEFAULT_BIOS is always a full file path
792 bios_name = os.path.basename(self.get('QB_DEFAULT_BIOS'))
793
794 # The user didn't want a bios to be loaded
795 if (bios_name == "" or bios_name == "none") and not self.bios:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600796 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500797
Brad Bishopc68388fc2019-08-26 01:33:31 -0400798 if not self.bios:
799 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
800 self.bios = "%s/%s" % (deploy_dir_image, bios_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500801
Brad Bishopc68388fc2019-08-26 01:33:31 -0400802 if not self.bios:
803 raise RunQemuError('BIOS not found: %s' % bios_match_name)
804
805 if not os.path.exists(self.bios):
Patrick Williams213cb262021-08-07 19:21:33 -0500806 raise RunQemuError("BIOS %s not found" % self.bios)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400807
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500808
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600809 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600810 """
811 Both qemu and kernel needs memory settings, so check QB_MEM and set it
812 for both.
813 """
814 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600815 if s:
816 self.set('QB_MEM', '-m %s' % s.group(1))
817 elif not self.get('QB_MEM'):
Brad Bishop79641f22019-09-10 07:20:22 -0400818 logger.info('QB_MEM is not set, use 256M by default')
819 self.set('QB_MEM', '-m 256')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500820
Andrew Geissler99467da2019-02-25 18:54:23 -0600821 # Check and remove M or m suffix
822 qb_mem = self.get('QB_MEM')
823 if qb_mem.endswith('M') or qb_mem.endswith('m'):
824 qb_mem = qb_mem[:-1]
825
826 # Add -m prefix it not present
827 if not qb_mem.startswith('-m'):
828 qb_mem = '-m %s' % qb_mem
829
830 self.set('QB_MEM', qb_mem)
831
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800832 mach = self.get('MACHINE')
Andrew Geisslerfc113ea2023-03-31 09:59:46 -0500833 if not mach.startswith(('qemumips', 'qemux86', 'qemuloongarch64')):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800834 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
835
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600836 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500837
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600838 def check_tcpserial(self):
839 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400840 ports = self.tcpserial_portnum.split(':')
841 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600842 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400843 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600844 else:
Brad Bishop15ae2502019-06-18 21:44:24 -0400845 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
846
847 if len(ports) > 1:
848 for port in ports[1:]:
849 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500850
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600851 def check_and_set(self):
852 """Check configs sanity and set when needed"""
853 self.validate_paths()
Andrew Geissler82c905d2020-04-13 13:39:40 -0500854 if not self.slirp_enabled and not self.net_bridge:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500855 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600856 # Check audio
857 if self.audio_enabled:
858 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500859 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600860 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800861 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600862 else:
863 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
864 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
865 else:
866 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500867
Brad Bishop15ae2502019-06-18 21:44:24 -0400868 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600869 self.check_kvm()
870 self.check_fstype()
871 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500872 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600873 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400874 self.check_dtb()
Brad Bishopc68388fc2019-08-26 01:33:31 -0400875 self.check_bios()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600876 self.check_mem()
877 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500878
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600879 def read_qemuboot(self):
880 if not self.qemuboot:
881 if self.get('DEPLOY_DIR_IMAGE'):
882 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600883 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800884 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600885 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500886
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600887 if self.rootfs and not os.path.exists(self.rootfs):
888 # Lazy rootfs
889 machine = self.get('MACHINE')
890 if not machine:
891 machine = os.path.basename(deploy_dir_image)
Patrick Williams8e7b46e2023-05-01 14:19:06 -0500892 if not self.get('IMAGE_LINK_NAME'):
893 raise RunQemuError("IMAGE_LINK_NAME wasn't set to find corresponding .qemuboot.conf file")
894 self.qemuboot = "%s/%s.qemuboot.conf" % (deploy_dir_image,
895 self.get('IMAGE_LINK_NAME'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600896 else:
897 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500898 logger.debug('Running %s...' % cmd)
899 try:
900 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
901 except subprocess.CalledProcessError as err:
902 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600903 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500904 for qb in qbs.split():
905 # Don't use initramfs when other choices unless fstype is ramfs
906 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
907 continue
908 self.qemuboot = qb
909 break
910 if not self.qemuboot:
911 # Use the first one when no choice
912 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600913 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500914
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600915 if not self.qemuboot:
916 # If we haven't found a .qemuboot.conf at this point it probably
917 # doesn't exist, continue without
918 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500919
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600920 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500921 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 -0500922
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600925 cf = configparser.ConfigParser()
926 cf.read(self.qemuboot)
927 for k, v in cf.items('config_bsp'):
928 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500929 if v.startswith("../"):
930 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
931 elif v == ".":
932 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600933 self.set(k_upper, v)
934
935 def validate_paths(self):
936 """Ensure all relevant path variables are set"""
937 # When we're started with a *.qemuboot.conf arg assume that image
938 # artefacts are relative to that file, rather than in whatever
939 # directory DEPLOY_DIR_IMAGE in the conf file points to.
940 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500941 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
942 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600943 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
944 self.set('DEPLOY_DIR_IMAGE', imgdir)
945
946 # If the STAGING_*_NATIVE directories from the config file don't exist
947 # and we're in a sourced OE build directory try to extract the paths
948 # from `bitbake -e`
949 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
950 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
951
952 if not havenative:
953 if not self.bitbake_e:
954 self.load_bitbake_env()
955
956 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500957 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600958 for nv in native_vars:
959 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
960 if s and s.group(1) != self.get(nv):
961 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
962 self.set(nv, s.group(1))
963 else:
964 # when we're invoked from a running bitbake instance we won't
965 # be able to call `bitbake -e`, then try:
966 # - get OE_TMPDIR from environment and guess paths based on it
967 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500968 tmpdir = self.get('OE_TMPDIR')
969 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600970 if tmpdir:
971 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
972 hostos, _, _, _, machine = os.uname()
973 buildsys = '%s-%s' % (machine, hostos.lower())
974 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
975 self.set('STAGING_DIR_NATIVE', staging_dir_native)
976 elif oecore_native_sysroot:
977 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
978 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
979 if self.get('STAGING_DIR_NATIVE'):
980 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
981 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
982 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
983 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
984
985 def print_config(self):
Andrew Geissler82c905d2020-04-13 13:39:40 -0500986 logoutput = ['Continuing with the following parameters:']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600987 if not self.fstype in self.vmtypes:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500988 logoutput.append('KERNEL: [%s]' % self.kernel)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400989 if self.bios:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500990 logoutput.append('BIOS: [%s]' % self.bios)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600991 if self.dtb:
Andrew Geissler82c905d2020-04-13 13:39:40 -0500992 logoutput.append('DTB: [%s]' % self.dtb)
993 logoutput.append('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400994 try:
995 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
996 except KeyError:
997 fstype_flags = ''
Andrew Geissler82c905d2020-04-13 13:39:40 -0500998 logoutput.append('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600999 if self.fstype == 'nfs':
Andrew Geissler82c905d2020-04-13 13:39:40 -05001000 logoutput.append('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001001 else:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001002 logoutput.append('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001003 if self.ovmf_bios:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001004 logoutput.append('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -04001005 if (self.ovmf_secboot_pkkek1):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001006 logoutput.append('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
1007 logoutput.append('CONFFILE: [%s]' % self.qemuboot)
1008 logoutput.append('')
1009 logger.info('\n'.join(logoutput))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001010
1011 def setup_nfs(self):
1012 if not self.nfs_server:
1013 if self.slirp_enabled:
1014 self.nfs_server = '10.0.2.2'
1015 else:
Andrew Geissler517393d2023-01-13 08:55:19 -06001016 self.nfs_server = '192.168.7.@GATEWAY@'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001017
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001018 # Figure out a new nfs_instance to allow multiple qemus running.
Brad Bishop977dc1a2019-02-06 16:01:43 -05001019 ps = subprocess.check_output(("ps", "auxww")).decode('utf-8')
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001020 pattern = '/bin/unfsd .* -i .*\.pid -e .*/exports([0-9]+) '
1021 all_instances = re.findall(pattern, ps, re.M)
1022 if all_instances:
1023 all_instances.sort(key=int)
1024 self.nfs_instance = int(all_instances.pop()) + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001025
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001026 nfsd_port = 3049 + 2 * self.nfs_instance
1027 mountd_port = 3048 + 2 * self.nfs_instance
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001028
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001029 # Export vars for runqemu-export-rootfs
1030 export_dict = {
1031 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001032 'NFSD_PORT': nfsd_port,
1033 'MOUNTD_PORT': mountd_port,
1034 }
1035 for k, v in export_dict.items():
1036 # Use '%s' since they are integers
1037 os.putenv(k, '%s' % v)
1038
Andrew Geisslerc5535c92023-01-27 16:10:19 -06001039 qb_nfsrootfs_extra_opt = self.get("QB_NFSROOTFS_EXTRA_OPT")
1040 if qb_nfsrootfs_extra_opt and not qb_nfsrootfs_extra_opt.startswith(","):
1041 qb_nfsrootfs_extra_opt = "," + qb_nfsrootfs_extra_opt
1042
1043 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 -06001044
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001045 # Extract .tar.bz2 or .tar.bz if no nfs dir
1046 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001047 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
1048 dest = "%s-nfsroot" % src_prefix
1049 if os.path.exists('%s.pseudo_state' % dest):
1050 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001051 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001052 else:
1053 src = ""
1054 src1 = '%s.tar.bz2' % src_prefix
1055 src2 = '%s.tar.gz' % src_prefix
1056 if os.path.exists(src1):
1057 src = src1
1058 elif os.path.exists(src2):
1059 src = src2
1060 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001061 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 -06001062 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -05001063 cmd = ('runqemu-extract-sdk', src, dest)
1064 logger.info('Running %s...' % str(cmd))
1065 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001066 raise RunQemuError('Failed to run %s' % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001067 self.rootfs = dest
Andrew Geisslerc926e172021-05-07 16:11:35 -05001068 self.cleanup_files.append(self.rootfs)
1069 self.cleanup_files.append('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001070
1071 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001072 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1073 logger.info('Running %s...' % str(cmd))
1074 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001075 raise RunQemuError('Failed to run %s' % str(cmd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001076
1077 self.nfs_running = True
1078
Andrew Geissler517393d2023-01-13 08:55:19 -06001079 def setup_cmd(self):
1080 cmd = self.get('QB_SETUP_CMD')
1081 if cmd != '':
1082 logger.info('Running setup command %s' % str(cmd))
1083 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001084 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001085
Andrew Geissler82c905d2020-04-13 13:39:40 -05001086 def setup_net_bridge(self):
1087 self.set('NETWORK_CMD', '-netdev bridge,br=%s,id=net0,helper=%s -device virtio-net-pci,netdev=net0 ' % (
1088 self.net_bridge, os.path.join(self.bindir_native, 'qemu-oe-bridge-helper')))
1089
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001090 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001091 """Setup user networking"""
1092
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001093 if self.fstype == 'nfs':
1094 self.setup_nfs()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001095 netconf = " " + self.cmdline_ip_slirp
1096 logger.info("Network configuration:%s", netconf)
1097 self.kernel_cmdline_script += netconf
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001098 # Port mapping
Andrew Geissler517393d2023-01-13 08:55:19 -06001099 hostfwd = ",hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:127.0.0.1:2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001100 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001101 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1102 # Figure out the port
1103 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1104 ports = [int(i) for i in ports]
1105 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001106
1107 lockdir = "/tmp/qemu-port-locks"
1108 if not os.path.exists(lockdir):
1109 # There might be a race issue when multi runqemu processess are
1110 # running at the same time.
1111 try:
1112 os.mkdir(lockdir)
1113 os.chmod(lockdir, 0o777)
1114 except FileExistsError:
1115 pass
1116
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001117 # Find a free port to avoid conflicts
1118 for p in ports[:]:
1119 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001120 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001121 p_new += 1
1122 mac += 1
1123 while p_new in ports:
1124 p_new += 1
1125 mac += 1
1126 if p != p_new:
1127 ports.append(p_new)
1128 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1129 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1130 mac = "%s%02x" % (self.mac_slirp, mac)
1131 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1132 # Print out port foward
1133 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1134 if hostfwd:
1135 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001136
1137 def setup_tap(self):
1138 """Setup tap"""
1139
1140 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1141 # devices, indicating that the user should not bring up new ones using
1142 # sudo.
1143 nosudo_flag = '/etc/runqemu-nosudo'
1144 self.qemuifup = shutil.which('runqemu-ifup')
1145 self.qemuifdown = shutil.which('runqemu-ifdown')
1146 ip = shutil.which('ip')
1147 lockdir = "/tmp/qemu-tap-locks"
1148
1149 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001150 logger.error("runqemu-ifup: %s" % self.qemuifup)
1151 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1152 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001153 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1154
1155 if not os.path.exists(lockdir):
1156 # There might be a race issue when multi runqemu processess are
1157 # running at the same time.
1158 try:
1159 os.mkdir(lockdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001160 os.chmod(lockdir, 0o777)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001161 except FileExistsError:
1162 pass
1163
Brad Bishop977dc1a2019-02-06 16:01:43 -05001164 cmd = (ip, 'link')
1165 logger.debug('Running %s...' % str(cmd))
1166 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001167 # Matches line like: 6: tap0: <foo>
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001168 possibles = re.findall('^[0-9]+: +(tap[0-9]+): <.*', 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")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001191 cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
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
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001207 tapnum = int(tap[3:])
1208 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")
1388 if len([i for i in content if i.startswith('render')]) == 0:
1389 raise RunQemuError("No render nodes found in /dev/dri: %s. %s" %(content, render_hint))
1390 except FileNotFoundError:
1391 raise RunQemuError("/dev/dri directory does not exist; no render nodes available on this machine. %s" %(render_hint))
1392
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001393 def setup_guest_agent(self):
1394 if self.guest_agent == True:
1395 self.qemu_opt += ' -chardev socket,path=' + self.guest_agent_sockpath + ',server,nowait,id=qga0 '
1396 self.qemu_opt += ' -device virtio-serial '
1397 self.qemu_opt += ' -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 '
1398
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001399 def setup_vga(self):
1400 if self.nographic == True:
1401 if self.sdl == True:
1402 raise RunQemuError('Option nographic makes no sense alongside the sdl option.')
1403 if self.gtk == True:
1404 raise RunQemuError('Option nographic makes no sense alongside the gtk option.')
1405 self.qemu_opt += ' -nographic'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001406
1407 if self.novga == True:
1408 self.qemu_opt += ' -vga none'
1409 return
1410
1411 if (self.gl_es == True or self.gl == True) and (self.sdl == False and self.gtk == False):
1412 raise RunQemuError('Option gl/gl-es needs gtk or sdl option.')
1413
Patrick Williams03907ee2022-05-01 06:28:52 -05001414 # If we have no display option, we autodetect based upon what qemu supports. We
1415 # need our font setup and show-cusor below so we need to see what qemu --help says
1416 # is supported so we can pass our correct config in.
1417 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 -05001418 output = subprocess.check_output([self.qemu_bin, "--help"], universal_newlines=True, env=self.qemu_environ)
Patrick Williams03907ee2022-05-01 06:28:52 -05001419 if "-display gtk" in output:
1420 self.gtk = True
1421 elif "-display sdl" in output:
1422 self.sdl = True
Andrew Geissler595f6302022-01-24 19:11:47 +00001423 else:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001424 self.qemu_opt += ' -display none'
Andrew Geissler595f6302022-01-24 19:11:47 +00001425
Patrick Williams03907ee2022-05-01 06:28:52 -05001426 if self.sdl == True or self.gtk == True or self.egl_headless == True:
1427
1428 if self.qemu_system.endswith(('i386', 'x86_64')):
1429 if self.gl or self.gl_es or self.egl_headless:
1430 self.qemu_opt += ' -device virtio-vga-gl '
1431 else:
1432 self.qemu_opt += ' -device virtio-vga '
1433
1434 self.qemu_opt += ' -display '
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001435 if self.egl_headless == True:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001436 self.check_render_nodes()
Andrew Geissler595f6302022-01-24 19:11:47 +00001437 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001438 self.qemu_opt += 'egl-headless,'
1439 else:
1440 if self.sdl == True:
1441 self.qemu_opt += 'sdl,'
1442 elif self.gtk == True:
Patrick Williams2390b1b2022-11-03 13:47:49 -05001443 self.qemu_environ['FONTCONFIG_PATH'] = '/etc/fonts'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001444 self.qemu_opt += 'gtk,'
1445
1446 if self.gl == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001447 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001448 self.qemu_opt += 'gl=on,'
1449 elif self.gl_es == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001450 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001451 self.qemu_opt += 'gl=es,'
1452 self.qemu_opt += 'show-cursor=on'
1453
1454 self.qemu_opt += ' %s' %self.get('QB_GRAPHICS')
1455
1456 def setup_serial(self):
1457 # Setup correct kernel command line for serial
Andrew Geissler595f6302022-01-24 19:11:47 +00001458 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 -05001459 for entry in self.get('SERIAL_CONSOLES').split(' '):
1460 self.kernel_cmdline_script += ' console=%s' %entry.split(';')[1]
1461
1462 if self.serialstdio == True or self.nographic == True:
1463 self.qemu_opt += " -serial mon:stdio"
1464 else:
1465 self.qemu_opt += " -serial mon:vc"
1466 if self.serialconsole:
1467 if sys.stdin.isatty():
1468 subprocess.check_call(("stty", "intr", "^]"))
1469 logger.info("Interrupt character is '^]'")
1470
1471 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1472
1473 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES).
1474 # If no serial or serialtcp options were specified, only ttyS0 is created
1475 # and sysvinit shows an error trying to enable ttyS1:
1476 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1477 serial_num = len(re.findall("-serial", self.qemu_opt))
1478 if serial_num < 2:
1479 self.qemu_opt += " -serial null"
1480
Patrick Williams03907ee2022-05-01 06:28:52 -05001481 def find_qemu(self):
Brad Bishop15ae2502019-06-18 21:44:24 -04001482 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001483
1484 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1485 # find QEMU in sysroot, it needs to use host's qemu.
1486 if not os.path.exists(qemu_bin):
1487 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1488 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001489 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001490 logger.info("Trying: %s" % qemu_bin_tmp)
1491 if os.path.exists(qemu_bin_tmp):
1492 qemu_bin = qemu_bin_tmp
1493 if not os.path.isabs(qemu_bin):
1494 qemu_bin = os.path.abspath(qemu_bin)
1495 logger.info("Using host's QEMU: %s" % qemu_bin)
1496 break
1497
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001498 if not os.access(qemu_bin, os.X_OK):
1499 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
Patrick Williams03907ee2022-05-01 06:28:52 -05001500 self.qemu_bin = qemu_bin
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001501
Patrick Williams03907ee2022-05-01 06:28:52 -05001502 def setup_final(self):
1503
1504 self.find_qemu()
1505
1506 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 -05001507
1508 for ovmf in self.ovmf_bios:
1509 format = ovmf.rsplit('.', 1)[-1]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001510 if format == "bin":
1511 format = "raw"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001512 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001513
1514 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001515
Brad Bishop08902b02019-08-20 09:16:51 -04001516 if self.ovmf_secboot_pkkek1:
1517 # Provide the Platform Key and first Key Exchange Key certificate as an
1518 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1519 # with "application prefix" of the EnrollDefaultKeys.efi application
1520 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1521 + self.ovmf_secboot_pkkek1
1522
Andrew Geissler99467da2019-02-25 18:54:23 -06001523 # Append qemuparams to override previous settings
1524 if self.qemuparams:
1525 self.qemu_opt += ' ' + self.qemuparams
1526
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001527 if self.snapshot:
1528 self.qemu_opt += " -snapshot"
1529
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001530 self.setup_guest_agent()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001531 self.setup_serial()
1532 self.setup_vga()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001533
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001534 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001535 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001536 if self.kernel:
Andrew Geissler615f2f12022-07-15 14:00:58 -05001537 kernel_opts = "-kernel %s" % (self.kernel)
1538 if self.get('QB_KERNEL_CMDLINE') == "none":
1539 if self.bootparams:
1540 kernel_opts += " -append '%s'" % (self.bootparams)
1541 else:
1542 kernel_opts += " -append '%s %s %s %s'" % (self.kernel_cmdline,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001543 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1544 self.bootparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001545 if self.dtb:
1546 kernel_opts += " -dtb %s" % self.dtb
1547 else:
1548 kernel_opts = ""
Patrick Williams213cb262021-08-07 19:21:33 -05001549
1550 if self.bios:
1551 self.qemu_opt += " -bios %s" % self.bios
1552
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001553 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001554 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001555 logger.info('Running %s\n' % cmd)
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001556 with open('/proc/uptime', 'r') as f:
1557 uptime_seconds = f.readline().split()[0]
1558 logger.info('Host uptime: %s\n' % uptime_seconds)
Brad Bishopf86d0552018-12-04 14:18:15 -08001559 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001560 if self.taplock_descriptor:
1561 pass_fds = [self.taplock_descriptor.fileno()]
1562 if len(self.portlocks):
1563 for descriptor in self.portlocks.values():
1564 pass_fds.append(descriptor.fileno())
Patrick Williams2390b1b2022-11-03 13:47:49 -05001565 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds, env=self.qemu_environ)
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001566 self.qemuprocess = process
Brad Bishop004d4992018-10-02 23:54:45 +02001567 retcode = process.wait()
1568 if retcode:
1569 if retcode == -signal.SIGTERM:
1570 logger.info("Qemu terminated by SIGTERM")
1571 else:
1572 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001573
Andrew Geissler517393d2023-01-13 08:55:19 -06001574 def cleanup_cmd(self):
1575 cmd = self.get('QB_CLEANUP_CMD')
1576 if cmd != '':
1577 logger.info('Running cleanup command %s' % str(cmd))
1578 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001579 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001580
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001581 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001582 if self.cleaned:
1583 return
1584
1585 # avoid dealing with SIGTERM when cleanup function is running
1586 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1587
1588 logger.info("Cleaning up")
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001589
1590 if self.qemuprocess:
1591 try:
1592 # give it some time to shut down, ignore return values and output
1593 self.qemuprocess.send_signal(signal.SIGTERM)
1594 self.qemuprocess.communicate(timeout=5)
1595 except subprocess.TimeoutExpired:
1596 self.qemuprocess.kill()
1597
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001598 with open('/proc/uptime', 'r') as f:
1599 uptime_seconds = f.readline().split()[0]
1600 logger.info('Host uptime: %s\n' % uptime_seconds)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001601 if self.cleantap:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001602 cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
1603 logger.debug('Running %s' % str(cmd))
1604 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001605 self.release_taplock()
1606 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001607
1608 if self.nfs_running:
1609 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001610 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1611 logger.debug('Running %s' % str(cmd))
1612 subprocess.check_call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001613
1614 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001615 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001616
Andrew Geisslerc926e172021-05-07 16:11:35 -05001617 if self.cleanup_files:
1618 for ent in self.cleanup_files:
1619 logger.info('Removing %s' % ent)
1620 if os.path.isfile(ent):
1621 os.remove(ent)
1622 else:
1623 shutil.rmtree(ent)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001624
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001625 # Deliberately ignore the return code of 'tput smam'.
1626 subprocess.call(["tput", "smam"])
1627
Brad Bishop004d4992018-10-02 23:54:45 +02001628 self.cleaned = True
1629
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001630 def run_bitbake_env(self, mach=None, target=''):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001631 bitbake = shutil.which('bitbake')
1632 if not bitbake:
1633 return
1634
1635 if not mach:
1636 mach = self.get('MACHINE')
1637
Andrew Geissler82c905d2020-04-13 13:39:40 -05001638 multiconfig = self.get('MULTICONFIG')
1639 if multiconfig:
1640 multiconfig = "mc:%s" % multiconfig
1641
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001642 if mach:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001643 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001644 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001645 cmd = 'bitbake -e %s %s' % (multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001646
1647 logger.info('Running %s...' % cmd)
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001648 try:
1649 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1650 except subprocess.CalledProcessError as err:
1651 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')))
1652 # need something with IMAGE_NAME_SUFFIX/IMAGE_LINK_NAME defined (kernel also inherits image-artifact-names.bbclass)
1653 target = 'virtual/kernel'
1654 if mach:
1655 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
1656 else:
1657 cmd = 'bitbake -e %s %s' % (multiconfig, target)
1658 try:
1659 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1660 except subprocess.CalledProcessError as err:
1661 logger.warning("Couldn't run '%s' to gather environment information, giving up with 'bitbake -e':\n%s" % (cmd, err.output.decode('utf-8')))
1662 return ''
Andrew Geissler82c905d2020-04-13 13:39:40 -05001663
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001664
1665 def load_bitbake_env(self, mach=None, target=None):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001666 if self.bitbake_e:
1667 return
1668
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001669 self.bitbake_e = self.run_bitbake_env(mach=mach, target=target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001670
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001671 def validate_combos(self):
1672 if (self.fstype in self.vmtypes) and self.kernel:
1673 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1674
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001675 @property
1676 def bindir_native(self):
1677 result = self.get('STAGING_BINDIR_NATIVE')
1678 if result and os.path.exists(result):
1679 return result
1680
Andrew Geissler82c905d2020-04-13 13:39:40 -05001681 cmd = ['bitbake', '-e']
1682 multiconfig = self.get('MULTICONFIG')
1683 if multiconfig:
1684 cmd.append('mc:%s:qemu-helper-native' % multiconfig)
1685 else:
1686 cmd.append('qemu-helper-native')
1687
Brad Bishop977dc1a2019-02-06 16:01:43 -05001688 logger.info('Running %s...' % str(cmd))
1689 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001690
1691 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1692 if match:
1693 result = match.group(1)
1694 if os.path.exists(result):
1695 self.set('STAGING_BINDIR_NATIVE', result)
1696 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001697 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001698 else:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001699 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001700
1701
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001702def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001703 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001704 print_usage()
1705 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001706 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001707 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001708
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001709 renice = os.path.expanduser("~/bin/runqemu-renice")
1710 if os.path.exists(renice):
1711 logger.info('Using %s to renice' % renice)
1712 subprocess.check_call([renice, str(os.getpid())])
1713
Brad Bishop004d4992018-10-02 23:54:45 +02001714 def sigterm_handler(signum, frame):
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001715 logger.info("Received signal: %s" % (signum))
Brad Bishop004d4992018-10-02 23:54:45 +02001716 config.cleanup()
Brad Bishop004d4992018-10-02 23:54:45 +02001717 signal.signal(signal.SIGTERM, sigterm_handler)
1718
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001719 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001720 config.read_qemuboot()
1721 config.check_and_set()
1722 # Check whether the combos is valid or not
1723 config.validate_combos()
1724 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001725 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001726 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001727 config.setup_final()
Andrew Geissler517393d2023-01-13 08:55:19 -06001728 config.setup_cmd()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001729 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001730 except RunQemuError as err:
1731 logger.error(err)
1732 return 1
1733 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001734 import traceback
1735 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001736 return 1
1737 finally:
Andrew Geissler517393d2023-01-13 08:55:19 -06001738 config.cleanup_cmd()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001739 config.cleanup()
1740
1741if __name__ == "__main__":
1742 sys.exit(main())