blob: 3a1703326892c22c524ef7fa30a2a1fe5c5d812a [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"
Patrick Williams2a254922023-08-11 09:48:11 -0500206 self.cmdline_ip_tap = "ip=192.168.7.@CLIENT@::192.168.7.@GATEWAY@:255.255.255.0::eth0:off:8.8.8.8 net.ifnames=0"
Brad Bishop6e60e8b2018-02-01 10:27:11 -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:
Andrew Geissler8f840682023-07-21 09:09:43 -0500651 logger.warning('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
Brad Bishop15ae2502019-06-18 21:44:24 -0400652 continue
653 else:
Andrew Geissler8f840682023-07-21 09:09:43 -0500654 logger.warning('QB_FSINFO is not supported for image type "%s"', fstype)
Brad Bishop15ae2502019-06-18 21:44:24 -0400655 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
Patrick Williams520786c2023-06-25 16:20:36 -05001018 nfsd_port = 3048 + self.nfs_instance
1019 lockdir = "/tmp/qemu-port-locks"
1020 self.make_lock_dir(lockdir)
1021 while not self.check_free_port('localhost', nfsd_port, lockdir):
1022 self.nfs_instance += 1
1023 nfsd_port += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001024
Patrick Williams520786c2023-06-25 16:20:36 -05001025 mountd_port = nfsd_port
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001026 # Export vars for runqemu-export-rootfs
1027 export_dict = {
1028 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001029 'NFSD_PORT': nfsd_port,
1030 'MOUNTD_PORT': mountd_port,
1031 }
1032 for k, v in export_dict.items():
1033 # Use '%s' since they are integers
1034 os.putenv(k, '%s' % v)
1035
Andrew Geisslerc5535c92023-01-27 16:10:19 -06001036 qb_nfsrootfs_extra_opt = self.get("QB_NFSROOTFS_EXTRA_OPT")
1037 if qb_nfsrootfs_extra_opt and not qb_nfsrootfs_extra_opt.startswith(","):
1038 qb_nfsrootfs_extra_opt = "," + qb_nfsrootfs_extra_opt
1039
1040 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 -06001041
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001042 # Extract .tar.bz2 or .tar.bz if no nfs dir
1043 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001044 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
1045 dest = "%s-nfsroot" % src_prefix
1046 if os.path.exists('%s.pseudo_state' % dest):
1047 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001048 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001049 else:
1050 src = ""
1051 src1 = '%s.tar.bz2' % src_prefix
1052 src2 = '%s.tar.gz' % src_prefix
1053 if os.path.exists(src1):
1054 src = src1
1055 elif os.path.exists(src2):
1056 src = src2
1057 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001058 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 -06001059 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -05001060 cmd = ('runqemu-extract-sdk', src, dest)
1061 logger.info('Running %s...' % str(cmd))
1062 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001063 raise RunQemuError('Failed to run %s' % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001064 self.rootfs = dest
Andrew Geisslerc926e172021-05-07 16:11:35 -05001065 self.cleanup_files.append(self.rootfs)
1066 self.cleanup_files.append('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001067
1068 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001069 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1070 logger.info('Running %s...' % str(cmd))
1071 if subprocess.call(cmd) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001072 raise RunQemuError('Failed to run %s' % str(cmd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001073
1074 self.nfs_running = True
1075
Andrew Geissler517393d2023-01-13 08:55:19 -06001076 def setup_cmd(self):
1077 cmd = self.get('QB_SETUP_CMD')
1078 if cmd != '':
1079 logger.info('Running setup command %s' % str(cmd))
1080 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001081 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001082
Andrew Geissler82c905d2020-04-13 13:39:40 -05001083 def setup_net_bridge(self):
1084 self.set('NETWORK_CMD', '-netdev bridge,br=%s,id=net0,helper=%s -device virtio-net-pci,netdev=net0 ' % (
1085 self.net_bridge, os.path.join(self.bindir_native, 'qemu-oe-bridge-helper')))
1086
Patrick Williams520786c2023-06-25 16:20:36 -05001087 def make_lock_dir(self, lockdir):
1088 if not os.path.exists(lockdir):
1089 # There might be a race issue when multi runqemu processess are
1090 # running at the same time.
1091 try:
1092 os.mkdir(lockdir)
1093 os.chmod(lockdir, 0o777)
1094 except FileExistsError:
1095 pass
1096 return
1097
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001098 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001099 """Setup user networking"""
1100
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001101 if self.fstype == 'nfs':
1102 self.setup_nfs()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001103 netconf = " " + self.cmdline_ip_slirp
1104 logger.info("Network configuration:%s", netconf)
1105 self.kernel_cmdline_script += netconf
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001106 # Port mapping
Andrew Geissler517393d2023-01-13 08:55:19 -06001107 hostfwd = ",hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:127.0.0.1:2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001108 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001109 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1110 # Figure out the port
1111 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1112 ports = [int(i) for i in ports]
1113 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001114
1115 lockdir = "/tmp/qemu-port-locks"
Patrick Williams520786c2023-06-25 16:20:36 -05001116 self.make_lock_dir(lockdir)
Brad Bishop08902b02019-08-20 09:16:51 -04001117
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001118 # Find a free port to avoid conflicts
1119 for p in ports[:]:
1120 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001121 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001122 p_new += 1
1123 mac += 1
1124 while p_new in ports:
1125 p_new += 1
1126 mac += 1
1127 if p != p_new:
1128 ports.append(p_new)
1129 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1130 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1131 mac = "%s%02x" % (self.mac_slirp, mac)
1132 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1133 # Print out port foward
1134 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1135 if hostfwd:
1136 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001137
1138 def setup_tap(self):
1139 """Setup tap"""
1140
1141 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1142 # devices, indicating that the user should not bring up new ones using
1143 # sudo.
1144 nosudo_flag = '/etc/runqemu-nosudo'
1145 self.qemuifup = shutil.which('runqemu-ifup')
1146 self.qemuifdown = shutil.which('runqemu-ifdown')
1147 ip = shutil.which('ip')
1148 lockdir = "/tmp/qemu-tap-locks"
1149
1150 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001151 logger.error("runqemu-ifup: %s" % self.qemuifup)
1152 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1153 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001154 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1155
Patrick Williams520786c2023-06-25 16:20:36 -05001156 self.make_lock_dir(lockdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001157
Brad Bishop977dc1a2019-02-06 16:01:43 -05001158 cmd = (ip, 'link')
1159 logger.debug('Running %s...' % str(cmd))
1160 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001161 # Matches line like: 6: tap0: <foo>
Patrick Williams520786c2023-06-25 16:20:36 -05001162 oe_tap_name = 'tap'
1163 if 'OE_TAP_NAME' in os.environ:
1164 oe_tap_name = os.environ['OE_TAP_NAME']
1165 tap_re = '^[0-9]+: +(' + oe_tap_name + '[0-9]+): <.*'
1166 possibles = re.findall(tap_re, ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001167 tap = ""
1168 for p in possibles:
1169 lockfile = os.path.join(lockdir, p)
1170 if os.path.exists('%s.skip' % lockfile):
1171 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1172 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001173 self.taplock = lockfile + '.lock'
1174 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001175 tap = p
1176 logger.info("Using preconfigured tap device %s" % tap)
1177 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1178 break
1179
1180 if not tap:
1181 if os.path.exists(nosudo_flag):
1182 logger.error("Error: There are no available tap devices to use for networking,")
1183 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001184 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001185
1186 gid = os.getgid()
1187 uid = os.getuid()
1188 logger.info("Setting up tap interface under sudo")
Andrew Geissler8f840682023-07-21 09:09:43 -05001189 cmd = ('sudo', self.qemuifup, str(gid))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001190 try:
1191 tap = subprocess.check_output(cmd).decode('utf-8').strip()
1192 except subprocess.CalledProcessError as e:
1193 logger.error('Setting up tap device failed:\n%s\nRun runqemu-gen-tapdevs to manually create one.' % str(e))
1194 sys.exit(1)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001195 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001196 self.taplock = lockfile + '.lock'
1197 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001198 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001199 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001200
1201 if not tap:
1202 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
Andrew Geissler82c905d2020-04-13 13:39:40 -05001203 sys.exit(1)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001204 self.tap = tap
Patrick Williams520786c2023-06-25 16:20:36 -05001205 tapnum = int(tap[len(oe_tap_name):])
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001206 gateway = tapnum * 2 + 1
1207 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001208 if self.fstype == 'nfs':
1209 self.setup_nfs()
Andrew Geissler82c905d2020-04-13 13:39:40 -05001210 netconf = " " + self.cmdline_ip_tap
1211 netconf = netconf.replace('@CLIENT@', str(client))
1212 netconf = netconf.replace('@GATEWAY@', str(gateway))
Andrew Geissler517393d2023-01-13 08:55:19 -06001213 self.nfs_server = self.nfs_server.replace('@GATEWAY@', str(gateway))
Andrew Geissler82c905d2020-04-13 13:39:40 -05001214 logger.info("Network configuration:%s", netconf)
1215 self.kernel_cmdline_script += netconf
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001216 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001217 qb_tap_opt = self.get('QB_TAP_OPT')
1218 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001219 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001220 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001221 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001222
1223 if self.vhost_enabled:
1224 qemu_tap_opt += ',vhost=on'
1225
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001226 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001227
1228 def setup_network(self):
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001229 if self.nonetwork or self.get('QB_NET') == 'none':
1230 self.set('NETWORK_CMD', '-nic none')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001231 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001232 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001233 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001234 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Andrew Geissler82c905d2020-04-13 13:39:40 -05001235 if self.net_bridge:
1236 self.setup_net_bridge()
1237 elif self.slirp_enabled:
1238 self.cmdline_ip_slirp = self.get('QB_CMDLINE_IP_SLIRP') or self.cmdline_ip_slirp
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001239 self.setup_slirp()
1240 else:
Andrew Geissler82c905d2020-04-13 13:39:40 -05001241 self.cmdline_ip_tap = self.get('QB_CMDLINE_IP_TAP') or self.cmdline_ip_tap
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001242 self.setup_tap()
1243
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001244 def setup_rootfs(self):
1245 if self.get('QB_ROOTFS') == 'none':
1246 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001247 if 'wic.' in self.fstype:
1248 self.fstype = self.fstype[4:]
Andrew Geisslerd1e89492021-02-12 15:35:20 -06001249 rootfs_format = self.fstype if self.fstype in ('vmdk', 'vhd', 'vhdx', 'qcow2', 'vdi') else 'raw'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001250
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001251 tmpfsdir = os.environ.get("RUNQEMU_TMPFS_DIR", None)
1252 if self.snapshot and tmpfsdir:
1253 newrootfs = os.path.join(tmpfsdir, os.path.basename(self.rootfs)) + "." + str(os.getpid())
Andrew Geissler09036742021-06-25 14:25:14 -05001254 logger.info("Copying rootfs to %s" % newrootfs)
1255 copy_start = time.time()
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001256 shutil.copyfile(self.rootfs, newrootfs)
Andrew Geissler09036742021-06-25 14:25:14 -05001257 logger.info("Copy done in %s seconds" % (time.time() - copy_start))
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001258 self.rootfs = newrootfs
1259 # Don't need a second copy now!
1260 self.snapshot = False
Andrew Geisslerc926e172021-05-07 16:11:35 -05001261 self.cleanup_files.append(newrootfs)
Andrew Geissler3b8a17c2021-04-15 15:55:55 -05001262
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001263 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1264 if qb_rootfs_opt:
1265 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1266 else:
1267 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1268
Andrew Geissler82c905d2020-04-13 13:39:40 -05001269 qb_rootfs_extra_opt = self.get("QB_ROOTFS_EXTRA_OPT")
1270 if qb_rootfs_extra_opt and not qb_rootfs_extra_opt.startswith(","):
1271 qb_rootfs_extra_opt = "," + qb_rootfs_extra_opt
1272
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001273 if self.fstype in ('cpio.gz', 'cpio'):
1274 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1275 self.rootfs_options = '-initrd %s' % self.rootfs
1276 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001277 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001278 if self.fstype in self.vmtypes:
1279 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001280 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001281 elif self.get('QB_DRIVE_TYPE'):
1282 drive_type = self.get('QB_DRIVE_TYPE')
1283 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001284 logger.info('Using scsi drive')
Andrew Geissler82c905d2020-04-13 13:39:40 -05001285 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd%s' \
1286 % (self.rootfs, rootfs_format, qb_rootfs_extra_opt)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001287 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001288 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001289 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Andrew Geissler82c905d2020-04-13 13:39:40 -05001290 elif drive_type.startswith("/dev/vdb"):
1291 logger.info('Using block virtio drive');
1292 vm_drive = '-drive id=disk0,file=%s,if=none,format=%s -device virtio-blk-device,drive=disk0%s' \
1293 % (self.rootfs, rootfs_format,qb_rootfs_extra_opt)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001294 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001295 # virtio might have been selected explicitly (just use it), or
1296 # is used as fallback (then warn about that).
1297 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001298 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1299 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1300 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001301 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001302
1303 # All branches above set vm_drive.
Andrew Geissler475cb722020-07-10 16:00:51 -05001304 self.rootfs_options = vm_drive
1305 if not self.fstype in self.vmtypes:
1306 self.rootfs_options += ' -no-reboot'
Andrew Geissler595f6302022-01-24 19:11:47 +00001307
1308 # By default, ' rw' is appended to QB_KERNEL_ROOT unless either ro or rw is explicitly passed.
1309 qb_kernel_root = self.get('QB_KERNEL_ROOT')
1310 qb_kernel_root_l = qb_kernel_root.split()
1311 if not ('ro' in qb_kernel_root_l or 'rw' in qb_kernel_root_l):
1312 qb_kernel_root += ' rw'
1313 self.kernel_cmdline = 'root=%s' % qb_kernel_root
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001314
1315 if self.fstype == 'nfs':
1316 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001317 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 -04001318 self.kernel_cmdline = 'root=%s rw' % k_root
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001319
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001320 if self.fstype == 'none':
1321 self.rootfs_options = ''
1322
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001323 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1324
1325 def guess_qb_system(self):
1326 """attempt to determine the appropriate qemu-system binary"""
1327 mach = self.get('MACHINE')
1328 if not mach:
Patrick Williams864cc432023-02-09 14:54:44 -06001329 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemuloongarch64|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001330 if self.rootfs:
1331 match = re.match(search, self.rootfs)
1332 if match:
1333 mach = match.group(1)
1334 elif self.kernel:
1335 match = re.match(search, self.kernel)
1336 if match:
1337 mach = match.group(1)
1338
1339 if not mach:
1340 return None
1341
1342 if mach == 'qemuarm':
1343 qbsys = 'arm'
1344 elif mach == 'qemuarm64':
1345 qbsys = 'aarch64'
1346 elif mach == 'qemux86':
1347 qbsys = 'i386'
1348 elif mach == 'qemux86-64':
1349 qbsys = 'x86_64'
1350 elif mach == 'qemuppc':
1351 qbsys = 'ppc'
Patrick Williams864cc432023-02-09 14:54:44 -06001352 elif mach == 'qemuloongarch64':
1353 qbsys = 'loongarch64'
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001354 elif mach == 'qemumips':
1355 qbsys = 'mips'
1356 elif mach == 'qemumips64':
1357 qbsys = 'mips64'
1358 elif mach == 'qemumipsel':
1359 qbsys = 'mipsel'
1360 elif mach == 'qemumips64el':
1361 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001362 elif mach == 'qemuriscv64':
1363 qbsys = 'riscv64'
1364 elif mach == 'qemuriscv32':
1365 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001366 else:
1367 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1368 logger.error("As %s is not among valid QEMU machines such as," % mach)
1369 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1370 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001371
1372 return 'qemu-system-%s' % qbsys
1373
Brad Bishop15ae2502019-06-18 21:44:24 -04001374 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001375 qemu_system = self.get('QB_SYSTEM_NAME')
1376 if not qemu_system:
1377 qemu_system = self.guess_qb_system()
1378 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001379 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001380 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001381
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001382 def check_render_nodes(self):
1383 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."""
1384 try:
1385 content = os.listdir("/dev/dri")
Andrew Geissler5082cc72023-09-11 08:41:39 -04001386 nodes = [i for i in content if i.startswith('renderD')]
1387 if len(nodes) == 0:
1388 raise RunQemuError("No render nodes found in /dev/dri/: %s. %s" %(content, render_hint))
1389 for n in nodes:
1390 try:
1391 with open(os.path.join("/dev/dri", n), "w") as f:
1392 f.close()
1393 break
1394 except IOError:
1395 pass
1396 else:
1397 raise RunQemuError("None of the render nodes in /dev/dri/ are accessible: %s; you may need to add yourself to 'render' group or otherwise ensure you have read-write permissions on one of them." %(nodes))
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001398 except FileNotFoundError:
1399 raise RunQemuError("/dev/dri directory does not exist; no render nodes available on this machine. %s" %(render_hint))
1400
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001401 def setup_guest_agent(self):
1402 if self.guest_agent == True:
1403 self.qemu_opt += ' -chardev socket,path=' + self.guest_agent_sockpath + ',server,nowait,id=qga0 '
1404 self.qemu_opt += ' -device virtio-serial '
1405 self.qemu_opt += ' -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0 '
1406
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001407 def setup_vga(self):
1408 if self.nographic == True:
1409 if self.sdl == True:
1410 raise RunQemuError('Option nographic makes no sense alongside the sdl option.')
1411 if self.gtk == True:
1412 raise RunQemuError('Option nographic makes no sense alongside the gtk option.')
1413 self.qemu_opt += ' -nographic'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001414
1415 if self.novga == True:
1416 self.qemu_opt += ' -vga none'
1417 return
1418
1419 if (self.gl_es == True or self.gl == True) and (self.sdl == False and self.gtk == False):
1420 raise RunQemuError('Option gl/gl-es needs gtk or sdl option.')
1421
Patrick Williams03907ee2022-05-01 06:28:52 -05001422 # If we have no display option, we autodetect based upon what qemu supports. We
1423 # need our font setup and show-cusor below so we need to see what qemu --help says
1424 # is supported so we can pass our correct config in.
1425 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 -05001426 output = subprocess.check_output([self.qemu_bin, "--help"], universal_newlines=True, env=self.qemu_environ)
Patrick Williams03907ee2022-05-01 06:28:52 -05001427 if "-display gtk" in output:
1428 self.gtk = True
1429 elif "-display sdl" in output:
1430 self.sdl = True
Andrew Geissler595f6302022-01-24 19:11:47 +00001431 else:
Patrick Williamsdb4c27e2022-08-05 08:10:29 -05001432 self.qemu_opt += ' -display none'
Andrew Geissler595f6302022-01-24 19:11:47 +00001433
Patrick Williams03907ee2022-05-01 06:28:52 -05001434 if self.sdl == True or self.gtk == True or self.egl_headless == True:
1435
1436 if self.qemu_system.endswith(('i386', 'x86_64')):
1437 if self.gl or self.gl_es or self.egl_headless:
1438 self.qemu_opt += ' -device virtio-vga-gl '
1439 else:
1440 self.qemu_opt += ' -device virtio-vga '
1441
1442 self.qemu_opt += ' -display '
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001443 if self.egl_headless == True:
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001444 self.check_render_nodes()
Andrew Geissler595f6302022-01-24 19:11:47 +00001445 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001446 self.qemu_opt += 'egl-headless,'
1447 else:
1448 if self.sdl == True:
1449 self.qemu_opt += 'sdl,'
1450 elif self.gtk == True:
Patrick Williams2390b1b2022-11-03 13:47:49 -05001451 self.qemu_environ['FONTCONFIG_PATH'] = '/etc/fonts'
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001452 self.qemu_opt += 'gtk,'
1453
1454 if self.gl == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001455 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001456 self.qemu_opt += 'gl=on,'
1457 elif self.gl_es == True:
Andrew Geissler595f6302022-01-24 19:11:47 +00001458 self.set_dri_path()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001459 self.qemu_opt += 'gl=es,'
1460 self.qemu_opt += 'show-cursor=on'
1461
1462 self.qemu_opt += ' %s' %self.get('QB_GRAPHICS')
1463
1464 def setup_serial(self):
1465 # Setup correct kernel command line for serial
Andrew Geissler595f6302022-01-24 19:11:47 +00001466 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 -05001467 for entry in self.get('SERIAL_CONSOLES').split(' '):
1468 self.kernel_cmdline_script += ' console=%s' %entry.split(';')[1]
1469
1470 if self.serialstdio == True or self.nographic == True:
1471 self.qemu_opt += " -serial mon:stdio"
1472 else:
1473 self.qemu_opt += " -serial mon:vc"
1474 if self.serialconsole:
1475 if sys.stdin.isatty():
1476 subprocess.check_call(("stty", "intr", "^]"))
1477 logger.info("Interrupt character is '^]'")
1478
1479 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1480
1481 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES).
1482 # If no serial or serialtcp options were specified, only ttyS0 is created
1483 # and sysvinit shows an error trying to enable ttyS1:
1484 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1485 serial_num = len(re.findall("-serial", self.qemu_opt))
1486 if serial_num < 2:
1487 self.qemu_opt += " -serial null"
1488
Patrick Williams03907ee2022-05-01 06:28:52 -05001489 def find_qemu(self):
Brad Bishop15ae2502019-06-18 21:44:24 -04001490 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001491
1492 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1493 # find QEMU in sysroot, it needs to use host's qemu.
1494 if not os.path.exists(qemu_bin):
1495 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1496 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001497 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001498 logger.info("Trying: %s" % qemu_bin_tmp)
1499 if os.path.exists(qemu_bin_tmp):
1500 qemu_bin = qemu_bin_tmp
1501 if not os.path.isabs(qemu_bin):
1502 qemu_bin = os.path.abspath(qemu_bin)
1503 logger.info("Using host's QEMU: %s" % qemu_bin)
1504 break
1505
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001506 if not os.access(qemu_bin, os.X_OK):
1507 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
Patrick Williams03907ee2022-05-01 06:28:52 -05001508 self.qemu_bin = qemu_bin
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001509
Patrick Williams03907ee2022-05-01 06:28:52 -05001510 def setup_final(self):
1511
1512 self.find_qemu()
1513
1514 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 -05001515
1516 for ovmf in self.ovmf_bios:
1517 format = ovmf.rsplit('.', 1)[-1]
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001518 if format == "bin":
1519 format = "raw"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001520 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001521
1522 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001523
Brad Bishop08902b02019-08-20 09:16:51 -04001524 if self.ovmf_secboot_pkkek1:
1525 # Provide the Platform Key and first Key Exchange Key certificate as an
1526 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1527 # with "application prefix" of the EnrollDefaultKeys.efi application
1528 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1529 + self.ovmf_secboot_pkkek1
1530
Andrew Geissler99467da2019-02-25 18:54:23 -06001531 # Append qemuparams to override previous settings
1532 if self.qemuparams:
1533 self.qemu_opt += ' ' + self.qemuparams
1534
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001535 if self.snapshot:
1536 self.qemu_opt += " -snapshot"
1537
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001538 self.setup_guest_agent()
Andrew Geissler95ac1b82021-03-31 14:34:31 -05001539 self.setup_serial()
1540 self.setup_vga()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001541
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001542 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001543 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001544 if self.kernel:
Andrew Geissler615f2f12022-07-15 14:00:58 -05001545 kernel_opts = "-kernel %s" % (self.kernel)
1546 if self.get('QB_KERNEL_CMDLINE') == "none":
1547 if self.bootparams:
1548 kernel_opts += " -append '%s'" % (self.bootparams)
1549 else:
1550 kernel_opts += " -append '%s %s %s %s'" % (self.kernel_cmdline,
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001551 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1552 self.bootparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001553 if self.dtb:
1554 kernel_opts += " -dtb %s" % self.dtb
1555 else:
1556 kernel_opts = ""
Patrick Williams213cb262021-08-07 19:21:33 -05001557
1558 if self.bios:
1559 self.qemu_opt += " -bios %s" % self.bios
1560
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001561 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001562 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001563 logger.info('Running %s\n' % cmd)
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001564 with open('/proc/uptime', 'r') as f:
1565 uptime_seconds = f.readline().split()[0]
1566 logger.info('Host uptime: %s\n' % uptime_seconds)
Brad Bishopf86d0552018-12-04 14:18:15 -08001567 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001568 if self.taplock_descriptor:
1569 pass_fds = [self.taplock_descriptor.fileno()]
1570 if len(self.portlocks):
1571 for descriptor in self.portlocks.values():
1572 pass_fds.append(descriptor.fileno())
Patrick Williams2390b1b2022-11-03 13:47:49 -05001573 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds, env=self.qemu_environ)
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001574 self.qemuprocess = process
Brad Bishop004d4992018-10-02 23:54:45 +02001575 retcode = process.wait()
1576 if retcode:
1577 if retcode == -signal.SIGTERM:
1578 logger.info("Qemu terminated by SIGTERM")
1579 else:
1580 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001581
Andrew Geissler517393d2023-01-13 08:55:19 -06001582 def cleanup_cmd(self):
1583 cmd = self.get('QB_CLEANUP_CMD')
1584 if cmd != '':
1585 logger.info('Running cleanup command %s' % str(cmd))
1586 if subprocess.call(cmd, shell=True) != 0:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001587 raise RunQemuError('Failed to run %s' % str(cmd))
Andrew Geissler517393d2023-01-13 08:55:19 -06001588
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001589 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001590 if self.cleaned:
1591 return
1592
1593 # avoid dealing with SIGTERM when cleanup function is running
1594 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1595
1596 logger.info("Cleaning up")
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001597
1598 if self.qemuprocess:
1599 try:
1600 # give it some time to shut down, ignore return values and output
1601 self.qemuprocess.send_signal(signal.SIGTERM)
1602 self.qemuprocess.communicate(timeout=5)
1603 except subprocess.TimeoutExpired:
1604 self.qemuprocess.kill()
1605
Andrew Geissler87f5cff2022-09-30 13:13:31 -05001606 with open('/proc/uptime', 'r') as f:
1607 uptime_seconds = f.readline().split()[0]
1608 logger.info('Host uptime: %s\n' % uptime_seconds)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001609 if self.cleantap:
Andrew Geissler8f840682023-07-21 09:09:43 -05001610 cmd = ('sudo', self.qemuifdown, self.tap)
Brad Bishop977dc1a2019-02-06 16:01:43 -05001611 logger.debug('Running %s' % str(cmd))
1612 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001613 self.release_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001614
1615 if self.nfs_running:
1616 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001617 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1618 logger.debug('Running %s' % str(cmd))
1619 subprocess.check_call(cmd)
Patrick Williams520786c2023-06-25 16:20:36 -05001620 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001621
1622 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001623 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001624
Andrew Geisslerc926e172021-05-07 16:11:35 -05001625 if self.cleanup_files:
1626 for ent in self.cleanup_files:
1627 logger.info('Removing %s' % ent)
1628 if os.path.isfile(ent):
1629 os.remove(ent)
1630 else:
1631 shutil.rmtree(ent)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001632
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001633 # Deliberately ignore the return code of 'tput smam'.
1634 subprocess.call(["tput", "smam"])
1635
Brad Bishop004d4992018-10-02 23:54:45 +02001636 self.cleaned = True
1637
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001638 def run_bitbake_env(self, mach=None, target=''):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001639 bitbake = shutil.which('bitbake')
1640 if not bitbake:
1641 return
1642
1643 if not mach:
1644 mach = self.get('MACHINE')
1645
Andrew Geissler82c905d2020-04-13 13:39:40 -05001646 multiconfig = self.get('MULTICONFIG')
1647 if multiconfig:
1648 multiconfig = "mc:%s" % multiconfig
1649
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001650 if mach:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001651 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001652 else:
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001653 cmd = 'bitbake -e %s %s' % (multiconfig, target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001654
1655 logger.info('Running %s...' % cmd)
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001656 try:
1657 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1658 except subprocess.CalledProcessError as err:
1659 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')))
1660 # need something with IMAGE_NAME_SUFFIX/IMAGE_LINK_NAME defined (kernel also inherits image-artifact-names.bbclass)
1661 target = 'virtual/kernel'
1662 if mach:
1663 cmd = 'MACHINE=%s bitbake -e %s %s' % (mach, multiconfig, target)
1664 else:
1665 cmd = 'bitbake -e %s %s' % (multiconfig, target)
1666 try:
1667 return subprocess.check_output(cmd, shell=True).decode('utf-8')
1668 except subprocess.CalledProcessError as err:
1669 logger.warning("Couldn't run '%s' to gather environment information, giving up with 'bitbake -e':\n%s" % (cmd, err.output.decode('utf-8')))
1670 return ''
Andrew Geissler82c905d2020-04-13 13:39:40 -05001671
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001672
1673 def load_bitbake_env(self, mach=None, target=None):
Andrew Geissler82c905d2020-04-13 13:39:40 -05001674 if self.bitbake_e:
1675 return
1676
Patrick Williams8e7b46e2023-05-01 14:19:06 -05001677 self.bitbake_e = self.run_bitbake_env(mach=mach, target=target)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001678
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001679 def validate_combos(self):
1680 if (self.fstype in self.vmtypes) and self.kernel:
1681 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1682
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001683 @property
1684 def bindir_native(self):
1685 result = self.get('STAGING_BINDIR_NATIVE')
1686 if result and os.path.exists(result):
1687 return result
1688
Andrew Geissler82c905d2020-04-13 13:39:40 -05001689 cmd = ['bitbake', '-e']
1690 multiconfig = self.get('MULTICONFIG')
1691 if multiconfig:
1692 cmd.append('mc:%s:qemu-helper-native' % multiconfig)
1693 else:
1694 cmd.append('qemu-helper-native')
1695
Brad Bishop977dc1a2019-02-06 16:01:43 -05001696 logger.info('Running %s...' % str(cmd))
1697 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001698
1699 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1700 if match:
1701 result = match.group(1)
1702 if os.path.exists(result):
1703 self.set('STAGING_BINDIR_NATIVE', result)
1704 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001705 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001706 else:
Andrew Geisslerfc113ea2023-03-31 09:59:46 -05001707 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % str(cmd))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001708
1709
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001710def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001711 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001712 print_usage()
1713 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001714 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001715 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001716
Andrew Geisslerc9f78652020-09-18 14:11:35 -05001717 renice = os.path.expanduser("~/bin/runqemu-renice")
1718 if os.path.exists(renice):
1719 logger.info('Using %s to renice' % renice)
1720 subprocess.check_call([renice, str(os.getpid())])
1721
Brad Bishop004d4992018-10-02 23:54:45 +02001722 def sigterm_handler(signum, frame):
Andrew Geissler6aa7eec2023-03-03 12:41:14 -06001723 logger.info("Received signal: %s" % (signum))
Brad Bishop004d4992018-10-02 23:54:45 +02001724 config.cleanup()
Brad Bishop004d4992018-10-02 23:54:45 +02001725 signal.signal(signal.SIGTERM, sigterm_handler)
1726
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001727 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001728 config.read_qemuboot()
1729 config.check_and_set()
1730 # Check whether the combos is valid or not
1731 config.validate_combos()
1732 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001733 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001734 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001735 config.setup_final()
Andrew Geissler517393d2023-01-13 08:55:19 -06001736 config.setup_cmd()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001737 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001738 except RunQemuError as err:
1739 logger.error(err)
1740 return 1
1741 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001742 import traceback
1743 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001744 return 1
1745 finally:
Andrew Geissler517393d2023-01-13 08:55:19 -06001746 config.cleanup_cmd()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001747 config.cleanup()
1748
1749if __name__ == "__main__":
1750 sys.exit(main())