blob: 1a5aca98ac78aead4f05609603f5df9373e814e5 [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
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050021
Brad Bishopd7bf8c12018-02-25 22:55:05 -050022class RunQemuError(Exception):
23 """Custom exception to raise on known errors."""
24 pass
25
26class OEPathError(RunQemuError):
Patrick Williamsc0f7c042017-02-23 20:41:17 -060027 """Custom Exception to give better guidance on missing binaries"""
28 def __init__(self, message):
Brad Bishopd7bf8c12018-02-25 22:55:05 -050029 super().__init__("In order for this script to dynamically infer paths\n \
Patrick Williamsc0f7c042017-02-23 20:41:17 -060030kernels or filesystem images, you either need bitbake in your PATH\n \
31or to source oe-init-build-env before running this script.\n\n \
32Dynamic path inference can be avoided by passing a *.qemuboot.conf to\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -050033runqemu, i.e. `runqemu /path/to/my-image-name.qemuboot.conf`\n\n %s" % message)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060034
35
36def create_logger():
37 logger = logging.getLogger('runqemu')
38 logger.setLevel(logging.INFO)
39
40 # create console handler and set level to debug
41 ch = logging.StreamHandler()
Brad Bishopd7bf8c12018-02-25 22:55:05 -050042 ch.setLevel(logging.DEBUG)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060043
44 # create formatter
45 formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
46
47 # add formatter to ch
48 ch.setFormatter(formatter)
49
50 # add ch to logger
51 logger.addHandler(ch)
52
53 return logger
54
55logger = create_logger()
56
57def print_usage():
58 print("""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050059Usage: you can run this script with any valid combination
60of the following environment variables (in any order):
61 KERNEL - the kernel image file to use
Brad Bishopc68388fc2019-08-26 01:33:31 -040062 BIOS - the bios image file to use
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050063 ROOTFS - the rootfs image file or nfsroot directory to use
Brad Bishop316dfdd2018-06-25 12:45:53 -040064 DEVICE_TREE - the device tree blob to use
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050065 MACHINE - the machine name (optional, autodetected from KERNEL filename if unspecified)
66 Simplified QEMU command-line options can be passed with:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060067 nographic - disable video console
Brad Bishopa34c0302019-09-23 22:34:48 -040068 sdl - choose the SDL UI frontend
69 gtk - choose the Gtk UI frontend
70 gl - enable virgl-based GL acceleration (also needs gtk option)
71 gl-es - enable virgl-based GL acceleration, using OpenGL ES (also needs gtk option)
Brad Bishop19323692019-04-05 15:28:33 -040072 egl-headless - enable headless EGL output; use vnc or spice to see it
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073 serial - enable a serial console on /dev/ttyS0
Brad Bishop19323692019-04-05 15:28:33 -040074 serialstdio - enable a serial console on the console (regardless of graphics mode)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060075 slirp - enable user networking, no root privileges is required
Brad Bishopa34c0302019-09-23 22:34:48 -040076 snapshot - don't write changes to back to images
Patrick Williamsc0f7c042017-02-23 20:41:17 -060077 kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
78 kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050079 publicvnc - enable a VNC server open to all hosts
Patrick Williamsc0f7c042017-02-23 20:41:17 -060080 audio - enable audio
Brad Bishop6e60e8b2018-02-01 10:27:11 -050081 [*/]ovmf* - OVMF firmware file or base name for booting with UEFI
Patrick Williamsc0f7c042017-02-23 20:41:17 -060082 tcpserial=<port> - specify tcp serial port number
Patrick Williamsc0f7c042017-02-23 20:41:17 -060083 qemuparams=<xyz> - specify custom parameters to QEMU
84 bootparams=<xyz> - specify custom kernel parameters during boot
Brad Bishop6e60e8b2018-02-01 10:27:11 -050085 help, -h, --help: print this text
Brad Bishopd7bf8c12018-02-25 22:55:05 -050086 -d, --debug: Enable debug output
Brad Bishop79641f22019-09-10 07:20:22 -040087 -q, --quiet: Hide most output except error messages
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050088
89Examples:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050090 runqemu
Patrick Williamsc0f7c042017-02-23 20:41:17 -060091 runqemu qemuarm
92 runqemu tmp/deploy/images/qemuarm
Brad Bishop6e60e8b2018-02-01 10:27:11 -050093 runqemu tmp/deploy/images/qemux86/<qemuboot.conf>
Patrick Williamsc0f7c042017-02-23 20:41:17 -060094 runqemu qemux86-64 core-image-sato ext4
95 runqemu qemux86-64 wic-image-minimal wic
96 runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
Brad Bishopd7bf8c12018-02-25 22:55:05 -050097 runqemu qemux86 iso/hddimg/wic.vmdk/wic.qcow2/wic.vdi/ramfs/cpio.gz...
Patrick Williamsc0f7c042017-02-23 20:41:17 -060098 runqemu qemux86 qemuparams="-m 256"
99 runqemu qemux86 bootparams="psplash=false"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100 runqemu path/to/<image>-<machine>.wic
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500101 runqemu path/to/<image>-<machine>.wic.vmdk
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600102""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500103
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104def check_tun():
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500105 """Check /dev/net/tun"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600106 dev_tun = '/dev/net/tun'
107 if not os.path.exists(dev_tun):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500108 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 -0500109
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600110 if not os.access(dev_tun, os.W_OK):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500111 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 -0500112
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600113def get_first_file(cmds):
114 """Return first file found in wildcard cmds"""
115 for cmd in cmds:
116 all_files = glob.glob(cmd)
117 if all_files:
118 for f in all_files:
119 if not os.path.isdir(f):
120 return f
121 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500122
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600123class BaseConfig(object):
124 def __init__(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500125 # The self.d saved vars from self.set(), part of them are from qemuboot.conf
126 self.d = {'QB_KERNEL_ROOT': '/dev/vda'}
127
128 # Supported env vars, add it here if a var can be got from env,
129 # and don't use os.getenv in the code.
130 self.env_vars = ('MACHINE',
131 'ROOTFS',
132 'KERNEL',
Brad Bishopc68388fc2019-08-26 01:33:31 -0400133 'BIOS',
Brad Bishop316dfdd2018-06-25 12:45:53 -0400134 'DEVICE_TREE',
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500135 'DEPLOY_DIR_IMAGE',
136 'OE_TMPDIR',
137 'OECORE_NATIVE_SYSROOT',
138 )
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600140 self.qemu_opt = ''
141 self.qemu_opt_script = ''
Andrew Geissler99467da2019-02-25 18:54:23 -0600142 self.qemuparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 self.clean_nfs_dir = False
144 self.nfs_server = ''
145 self.rootfs = ''
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500146 # File name(s) of a OVMF firmware file or variable store,
147 # to be added with -drive if=pflash.
148 # Found in the same places as the rootfs, with or without one of
149 # these suffices: qcow2, bin.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500150 self.ovmf_bios = []
Brad Bishop08902b02019-08-20 09:16:51 -0400151 # When enrolling default Secure Boot keys, the hypervisor
152 # must provide the Platform Key and the first Key Exchange Key
153 # certificate in the Type 11 SMBIOS table.
154 self.ovmf_secboot_pkkek1 = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600155 self.qemuboot = ''
156 self.qbconfload = False
157 self.kernel = ''
Brad Bishopc68388fc2019-08-26 01:33:31 -0400158 self.bios = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600159 self.kernel_cmdline = ''
160 self.kernel_cmdline_script = ''
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500161 self.bootparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600162 self.dtb = ''
163 self.fstype = ''
164 self.kvm_enabled = False
165 self.vhost_enabled = False
166 self.slirp_enabled = False
167 self.nfs_instance = 0
168 self.nfs_running = False
Brad Bishop19323692019-04-05 15:28:33 -0400169 self.serialconsole = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600170 self.serialstdio = False
171 self.cleantap = False
172 self.saved_stty = ''
173 self.audio_enabled = False
174 self.tcpserial_portnum = ''
Brad Bishop08902b02019-08-20 09:16:51 -0400175 self.taplock = ''
176 self.taplock_descriptor = None
177 self.portlocks = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600178 self.bitbake_e = ''
179 self.snapshot = False
Brad Bishop15ae2502019-06-18 21:44:24 -0400180 self.wictypes = ('wic', 'wic.vmdk', 'wic.qcow2', 'wic.vdi')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500181 self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
182 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz')
Brad Bishop08902b02019-08-20 09:16:51 -0400183 self.vmtypes = ('hddimg', 'iso')
Brad Bishop15ae2502019-06-18 21:44:24 -0400184 self.fsinfo = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500185 self.network_device = "-device e1000,netdev=net0,mac=@MAC@"
186 # Use different mac section for tap and slirp to avoid
187 # conflicts, e.g., when one is running with tap, the other is
188 # running with slirp.
189 # The last section is dynamic, which is for avoiding conflicts,
190 # when multiple qemus are running, e.g., when multiple tap or
191 # slirp qemus are running.
192 self.mac_tap = "52:54:00:12:34:"
193 self.mac_slirp = "52:54:00:12:35:"
Brad Bishop004d4992018-10-02 23:54:45 +0200194 # pid of the actual qemu process
195 self.qemupid = None
196 # avoid cleanup twice
197 self.cleaned = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500198
Brad Bishop08902b02019-08-20 09:16:51 -0400199 def acquire_taplock(self, error=True):
200 logger.debug("Acquiring lockfile %s..." % self.taplock)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600201 try:
Brad Bishop08902b02019-08-20 09:16:51 -0400202 self.taplock_descriptor = open(self.taplock, 'w')
203 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600204 except Exception as e:
Brad Bishop08902b02019-08-20 09:16:51 -0400205 msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500206 if error:
207 logger.error(msg)
208 else:
209 logger.info(msg)
Brad Bishop08902b02019-08-20 09:16:51 -0400210 if self.taplock_descriptor:
211 self.taplock_descriptor.close()
212 self.taplock_descriptor = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600213 return False
214 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500215
Brad Bishop08902b02019-08-20 09:16:51 -0400216 def release_taplock(self):
217 if self.taplock_descriptor:
Brad Bishopf86d0552018-12-04 14:18:15 -0800218 logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
Brad Bishop08902b02019-08-20 09:16:51 -0400219 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN)
220 self.taplock_descriptor.close()
221 os.remove(self.taplock)
222 self.taplock_descriptor = None
223
224 def check_free_port(self, host, port, lockdir):
225 """ Check whether the port is free or not """
226 import socket
227 from contextlib import closing
228
229 lockfile = os.path.join(lockdir, str(port) + '.lock')
230 if self.acquire_portlock(lockfile):
231 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
232 if sock.connect_ex((host, port)) == 0:
233 # Port is open, so not free
234 self.release_portlock(lockfile)
235 return False
236 else:
237 # Port is not open, so free
238 return True
239 else:
240 return False
241
242 def acquire_portlock(self, lockfile):
243 logger.debug("Acquiring lockfile %s..." % lockfile)
244 try:
245 portlock_descriptor = open(lockfile, 'w')
246 self.portlocks.update({lockfile: portlock_descriptor})
247 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB)
248 except Exception as e:
249 msg = "Acquiring lockfile %s failed: %s" % (lockfile, e)
250 logger.info(msg)
251 if lockfile in self.portlocks.keys() and self.portlocks[lockfile]:
252 self.portlocks[lockfile].close()
253 del self.portlocks[lockfile]
254 return False
255 return True
256
257 def release_portlock(self, lockfile=None):
258 if lockfile != None:
259 logger.debug("Releasing lockfile '%s'" % lockfile)
260 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN)
261 self.portlocks[lockfile].close()
262 os.remove(lockfile)
263 del self.portlocks[lockfile]
264 elif len(self.portlocks):
265 for lockfile, descriptor in self.portlocks.items():
266 logger.debug("Releasing lockfile '%s'" % lockfile)
267 fcntl.flock(descriptor, fcntl.LOCK_UN)
268 descriptor.close()
269 os.remove(lockfile)
270 self.portlocks = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600272 def get(self, key):
273 if key in self.d:
274 return self.d.get(key)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500275 elif os.getenv(key):
276 return os.getenv(key)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600277 else:
278 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500279
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600280 def set(self, key, value):
281 self.d[key] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500282
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600283 def is_deploy_dir_image(self, p):
284 if os.path.isdir(p):
285 if not re.search('.qemuboot.conf$', '\n'.join(os.listdir(p)), re.M):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500286 logger.debug("Can't find required *.qemuboot.conf in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600287 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500288 if not any(map(lambda name: '-image-' in name, os.listdir(p))):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500289 logger.debug("Can't find *-image-* in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600290 return False
291 return True
292 else:
293 return False
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500294
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600295 def check_arg_fstype(self, fst):
296 """Check and set FSTYPE"""
Brad Bishop15ae2502019-06-18 21:44:24 -0400297 if fst not in self.fstypes + self.vmtypes + self.wictypes:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800298 logger.warning("Maybe unsupported FSTYPE: %s" % fst)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600299 if not self.fstype or self.fstype == fst:
300 if fst == 'ramfs':
301 fst = 'cpio.gz'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500302 if fst in ('tar.bz2', 'tar.gz'):
303 fst = 'nfs'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600304 self.fstype = fst
305 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500306 raise RunQemuError("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600308 def set_machine_deploy_dir(self, machine, deploy_dir_image):
309 """Set MACHINE and DEPLOY_DIR_IMAGE"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 logger.debug('MACHINE: %s' % machine)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600311 self.set("MACHINE", machine)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500312 logger.debug('DEPLOY_DIR_IMAGE: %s' % deploy_dir_image)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600313 self.set("DEPLOY_DIR_IMAGE", deploy_dir_image)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500314
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600315 def check_arg_nfs(self, p):
316 if os.path.isdir(p):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500317 self.rootfs = p
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600318 else:
319 m = re.match('(.*):(.*)', p)
320 self.nfs_server = m.group(1)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500321 self.rootfs = m.group(2)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600322 self.check_arg_fstype('nfs')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500323
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600324 def check_arg_path(self, p):
325 """
326 - Check whether it is <image>.qemuboot.conf or contains <image>.qemuboot.conf
327 - Check whether is a kernel file
328 - Check whether is a image file
329 - Check whether it is a nfs dir
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500330 - Check whether it is a OVMF flash file
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600331 """
332 if p.endswith('.qemuboot.conf'):
333 self.qemuboot = p
334 self.qbconfload = True
335 elif re.search('\.bin$', p) or re.search('bzImage', p) or \
336 re.search('zImage', p) or re.search('vmlinux', p) or \
337 re.search('fitImage', p) or re.search('uImage', p):
338 self.kernel = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500339 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 -0600340 self.rootfs = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500341 # Check filename against self.fstypes can hanlde <file>.cpio.gz,
342 # otherwise, its type would be "gz", which is incorrect.
343 fst = ""
344 for t in self.fstypes:
345 if p.endswith(t):
346 fst = t
347 break
348 if not fst:
349 m = re.search('.*\.(.*)$', self.rootfs)
350 if m:
351 fst = m.group(1)
352 if fst:
353 self.check_arg_fstype(fst)
354 qb = re.sub('\.' + fst + "$", '', self.rootfs)
355 qb = '%s%s' % (re.sub('\.rootfs$', '', qb), '.qemuboot.conf')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600356 if os.path.exists(qb):
357 self.qemuboot = qb
358 self.qbconfload = True
359 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800360 logger.warning("%s doesn't exist" % qb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600361 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500362 raise RunQemuError("Can't find FSTYPE from: %s" % p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500363
364 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600365 if self.is_deploy_dir_image(p):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500366 logger.debug('DEPLOY_DIR_IMAGE: %s' % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600367 self.set("DEPLOY_DIR_IMAGE", p)
368 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500369 logger.debug("Assuming %s is an nfs rootfs" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600370 self.check_arg_nfs(p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500371 elif os.path.basename(p).startswith('ovmf'):
372 self.ovmf_bios.append(p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600373 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500374 raise RunQemuError("Unknown path arg %s" % p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500375
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600376 def check_arg_machine(self, arg):
377 """Check whether it is a machine"""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500378 if self.get('MACHINE') == arg:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600379 return
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500380 elif self.get('MACHINE') and self.get('MACHINE') != arg:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500381 raise RunQemuError("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500382 elif re.search('/', arg):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500383 raise RunQemuError("Unknown arg: %s" % arg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500384
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500385 logger.debug('Assuming MACHINE = %s' % arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500386
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600387 # if we're running under testimage, or similarly as a child
388 # of an existing bitbake invocation, we can't invoke bitbake
389 # to validate the MACHINE setting and must assume it's correct...
390 # FIXME: testimage.bbclass exports these two variables into env,
391 # are there other scenarios in which we need to support being
392 # invoked by bitbake?
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500393 deploy = self.get('DEPLOY_DIR_IMAGE')
394 bbchild = deploy and self.get('OE_TMPDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600395 if bbchild:
396 self.set_machine_deploy_dir(arg, deploy)
397 return
398 # also check whether we're running under a sourced toolchain
399 # environment file
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500400 if self.get('OECORE_NATIVE_SYSROOT'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600401 self.set("MACHINE", arg)
402 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600404 cmd = 'MACHINE=%s bitbake -e' % arg
405 logger.info('Running %s...' % cmd)
Brad Bishop977dc1a2019-02-06 16:01:43 -0500406 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600407 # bitbake -e doesn't report invalid MACHINE as an error, so
408 # let's check DEPLOY_DIR_IMAGE to make sure that it is a valid
409 # MACHINE.
410 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
411 if s:
412 deploy_dir_image = s.group(1)
413 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500414 raise RunQemuError("bitbake -e %s" % self.bitbake_e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600415 if self.is_deploy_dir_image(deploy_dir_image):
416 self.set_machine_deploy_dir(arg, deploy_dir_image)
417 else:
418 logger.error("%s not a directory valid DEPLOY_DIR_IMAGE" % deploy_dir_image)
419 self.set("MACHINE", arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500420
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600421 def check_args(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500422 for debug in ("-d", "--debug"):
423 if debug in sys.argv:
424 logger.setLevel(logging.DEBUG)
425 sys.argv.remove(debug)
426
427 for quiet in ("-q", "--quiet"):
428 if quiet in sys.argv:
429 logger.setLevel(logging.ERROR)
430 sys.argv.remove(quiet)
431
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600432 unknown_arg = ""
433 for arg in sys.argv[1:]:
Brad Bishop15ae2502019-06-18 21:44:24 -0400434 if arg in self.fstypes + self.vmtypes + self.wictypes:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600435 self.check_arg_fstype(arg)
436 elif arg == 'nographic':
437 self.qemu_opt_script += ' -nographic'
438 self.kernel_cmdline_script += ' console=ttyS0'
Brad Bishop19323692019-04-05 15:28:33 -0400439 elif arg == 'sdl':
440 self.qemu_opt_script += ' -display sdl'
Brad Bishopa34c0302019-09-23 22:34:48 -0400441 elif arg == 'gtk':
442 if 'gl' in sys.argv[1:]:
443 self.qemu_opt_script += ' -vga virtio -display gtk,gl=on'
444 elif 'gl-es' in sys.argv[1:]:
445 self.qemu_opt_script += ' -vga virtio -display gtk,gl=es'
446 else:
447 self.qemu_opt_script += ' -display gtk'
448 elif arg == 'gl' or arg == 'gl-es':
449 # These args are handled inside sdl or gtk blocks above
450 pass
Brad Bishop19323692019-04-05 15:28:33 -0400451 elif arg == 'egl-headless':
452 self.qemu_opt_script += ' -vga virtio -display egl-headless'
453 # As runqemu can be run within bitbake (when using testimage, for example),
454 # we need to ensure that we run host pkg-config, and that it does not
455 # get mis-directed to native build paths set by bitbake.
456 try:
457 del os.environ['PKG_CONFIG_PATH']
458 del os.environ['PKG_CONFIG_DIR']
459 del os.environ['PKG_CONFIG_LIBDIR']
460 except KeyError:
461 pass
462 try:
463 dripath = subprocess.check_output("PATH=/bin:/usr/bin:$PATH pkg-config --variable=dridriverdir dri", shell=True)
464 except subprocess.CalledProcessError as e:
465 raise RunQemuError("Could not determine the path to dri drivers on the host via pkg-config.\nPlease install Mesa development files (particularly, dri.pc) on the host machine.")
466 os.environ['LIBGL_DRIVERS_PATH'] = dripath.decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600467 elif arg == 'serial':
468 self.kernel_cmdline_script += ' console=ttyS0'
Brad Bishop19323692019-04-05 15:28:33 -0400469 self.serialconsole = True
470 elif arg == "serialstdio":
471 self.kernel_cmdline_script += ' console=ttyS0'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600472 self.serialstdio = True
473 elif arg == 'audio':
474 logger.info("Enabling audio in qemu")
475 logger.info("Please install sound drivers in linux host")
476 self.audio_enabled = True
477 elif arg == 'kvm':
478 self.kvm_enabled = True
479 elif arg == 'kvm-vhost':
480 self.vhost_enabled = True
481 elif arg == 'slirp':
482 self.slirp_enabled = True
483 elif arg == 'snapshot':
484 self.snapshot = True
485 elif arg == 'publicvnc':
486 self.qemu_opt_script += ' -vnc :0'
487 elif arg.startswith('tcpserial='):
Brad Bishop15ae2502019-06-18 21:44:24 -0400488 self.tcpserial_portnum = '%s' % arg[len('tcpserial='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600489 elif arg.startswith('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600490 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600491 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500492 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600493 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
494 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500495 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600496 # Lazy rootfs
497 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500498 elif arg.startswith('ovmf'):
499 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600500 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500501 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600502 if (not unknown_arg) or unknown_arg == arg:
503 unknown_arg = arg
504 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500505 raise RunQemuError("Can't handle two unknown args: %s %s\n"
506 "Try 'runqemu help' on how to use it" % \
507 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600508 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300509 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500510 if self.get('DEPLOY_DIR_IMAGE'):
511 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
512 if unknown_arg == machine:
513 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500514
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600515 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500516
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500517 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500518 self.load_bitbake_env()
519 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
520 if s:
521 self.set("DEPLOY_DIR_IMAGE", s.group(1))
522
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600523 def check_kvm(self):
524 """Check kvm and kvm-host"""
525 if not (self.kvm_enabled or self.vhost_enabled):
526 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU'))
527 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500528
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600529 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500530 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500531
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600532 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'))
533 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
534 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
535 dev_kvm = '/dev/kvm'
536 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400537 if self.qemu_system.endswith(('i386', 'x86_64')):
538 with open('/proc/cpuinfo', 'r') as f:
539 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
540 if not kvm_cap:
541 logger.error("You are trying to enable KVM on a cpu without VT support.")
542 logger.error("Remove kvm from the command-line, or refer:")
543 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500544
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600545 if not os.path.exists(dev_kvm):
546 logger.error("Missing KVM device. Have you inserted kvm modules?")
547 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500548 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500549
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600550 if os.access(dev_kvm, os.W_OK|os.R_OK):
551 self.qemu_opt_script += ' -enable-kvm'
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500552 if self.get('MACHINE') == "qemux86":
553 # Workaround for broken APIC window on pre 4.15 host kernels which causes boot hangs
554 # See YOCTO #12301
555 # On 64 bit we use x2apic
556 self.kernel_cmdline_script += " clocksource=kvm-clock hpet=disable noapic nolapic"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600557 else:
558 logger.error("You have no read or write permission on /dev/kvm.")
559 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500560 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500561
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600562 if self.vhost_enabled:
563 if not os.path.exists(dev_vhost):
564 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
565 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500566 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500567
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600568 if not os.access(dev_kvm, os.W_OK|os.R_OK):
569 logger.error("You have no read or write permission on /dev/vhost-net.")
570 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500571 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500572
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600573 def check_fstype(self):
574 """Check and setup FSTYPE"""
575 if not self.fstype:
576 fstype = self.get('QB_DEFAULT_FSTYPE')
577 if fstype:
578 self.fstype = fstype
579 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500580 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581
Brad Bishop15ae2502019-06-18 21:44:24 -0400582 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
583 wic_fs = False
584 qb_fsinfo = self.get('QB_FSINFO')
585 if qb_fsinfo:
586 qb_fsinfo = qb_fsinfo.split()
587 for fsinfo in qb_fsinfo:
588 try:
589 fstype, fsflag = fsinfo.split(':')
590
591 if fstype == 'wic':
592 if fsflag == 'no-kernel-in-fs':
593 wic_fs = True
594 elif fsflag == 'kernel-in-fs':
595 wic_fs = False
596 else:
597 logger.warn('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
598 continue
599 else:
600 logger.warn('QB_FSINFO is not supported for image type "%s"', fstype)
601 continue
602
603 if fstype in self.fsinfo:
604 self.fsinfo[fstype].append(fsflag)
605 else:
606 self.fsinfo[fstype] = [fsflag]
607 except Exception:
608 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
609
610 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
611 if wic_fs:
612 self.fstypes = self.fstypes + self.wictypes
613 else:
614 self.vmtypes = self.vmtypes + self.wictypes
615
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600616 def check_rootfs(self):
617 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500618
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500619 if self.fstype == "none":
620 return
621
622 if self.get('ROOTFS'):
623 if not self.rootfs:
624 self.rootfs = self.get('ROOTFS')
625 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500626 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500627
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600628 if self.fstype == 'nfs':
629 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500630
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600631 if self.rootfs and not os.path.exists(self.rootfs):
632 # Lazy rootfs
633 self.rootfs = "%s/%s-%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
634 self.rootfs, self.get('MACHINE'),
635 self.fstype)
636 elif not self.rootfs:
637 cmd_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
638 cmd_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
639 cmds = (cmd_name, cmd_link)
640 self.rootfs = get_first_file(cmds)
641 if not self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500642 raise RunQemuError("Failed to find rootfs: %s or %s" % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500643
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600644 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500645 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646
Brad Bishop08902b02019-08-20 09:16:51 -0400647 def setup_pkkek1(self):
648 """
649 Extract from PEM certificate the Platform Key and first Key
650 Exchange Key certificate string. The hypervisor needs to provide
651 it in the Type 11 SMBIOS table
652 """
653 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
654 try:
655 with open(pemcert, 'r') as pemfile:
656 key = pemfile.read().replace('\n', ''). \
657 replace('-----BEGIN CERTIFICATE-----', ''). \
658 replace('-----END CERTIFICATE-----', '')
659 self.ovmf_secboot_pkkek1 = key
660
661 except FileNotFoundError:
662 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
663
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500664 def check_ovmf(self):
665 """Check and set full path for OVMF firmware and variable file(s)."""
666
667 for index, ovmf in enumerate(self.ovmf_bios):
668 if os.path.exists(ovmf):
669 continue
670 for suffix in ('qcow2', 'bin'):
671 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
672 if os.path.exists(path):
673 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400674 if ovmf.endswith('secboot'):
675 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500676 break
677 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500678 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500679
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600680 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400681 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600682 # The vm image doesn't need a kernel
683 if self.fstype in self.vmtypes:
684 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500685
Brad Bishop316dfdd2018-06-25 12:45:53 -0400686 # See if the user supplied a KERNEL option
687 if self.get('KERNEL'):
688 self.kernel = self.get('KERNEL')
689
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500690 # QB_DEFAULT_KERNEL is always a full file path
691 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
692
693 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400694 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500695 return
696
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600697 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
698 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500699 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600700 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
701 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
702 cmds = (kernel_match_name, kernel_match_link, kernel_startswith)
703 self.kernel = get_first_file(cmds)
704 if not self.kernel:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500705 raise RunQemuError('KERNEL not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500706
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600707 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500708 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500709
Brad Bishop316dfdd2018-06-25 12:45:53 -0400710 def check_dtb(self):
711 """Check and set dtb"""
712 # Did the user specify a device tree?
713 if self.get('DEVICE_TREE'):
714 self.dtb = self.get('DEVICE_TREE')
715 if not os.path.exists(self.dtb):
716 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
717 return
718
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600719 dtb = self.get('QB_DTB')
720 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400721 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600722 cmd_match = "%s/%s" % (deploy_dir_image, dtb)
723 cmd_startswith = "%s/%s*" % (deploy_dir_image, dtb)
724 cmd_wild = "%s/*.dtb" % deploy_dir_image
725 cmds = (cmd_match, cmd_startswith, cmd_wild)
726 self.dtb = get_first_file(cmds)
727 if not os.path.exists(self.dtb):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500728 raise RunQemuError('DTB not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500729
Brad Bishopc68388fc2019-08-26 01:33:31 -0400730 def check_bios(self):
731 """Check and set bios"""
732
733 # See if the user supplied a BIOS option
734 if self.get('BIOS'):
735 self.bios = self.get('BIOS')
736
737 # QB_DEFAULT_BIOS is always a full file path
738 bios_name = os.path.basename(self.get('QB_DEFAULT_BIOS'))
739
740 # The user didn't want a bios to be loaded
741 if (bios_name == "" or bios_name == "none") and not self.bios:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600742 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500743
Brad Bishopc68388fc2019-08-26 01:33:31 -0400744 if not self.bios:
745 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
746 self.bios = "%s/%s" % (deploy_dir_image, bios_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747
Brad Bishopc68388fc2019-08-26 01:33:31 -0400748 if not self.bios:
749 raise RunQemuError('BIOS not found: %s' % bios_match_name)
750
751 if not os.path.exists(self.bios):
752 raise RunQemuError("KERNEL %s not found" % self.bios)
753
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500754
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600756 """
757 Both qemu and kernel needs memory settings, so check QB_MEM and set it
758 for both.
759 """
760 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600761 if s:
762 self.set('QB_MEM', '-m %s' % s.group(1))
763 elif not self.get('QB_MEM'):
Brad Bishop79641f22019-09-10 07:20:22 -0400764 logger.info('QB_MEM is not set, use 256M by default')
765 self.set('QB_MEM', '-m 256')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500766
Andrew Geissler99467da2019-02-25 18:54:23 -0600767 # Check and remove M or m suffix
768 qb_mem = self.get('QB_MEM')
769 if qb_mem.endswith('M') or qb_mem.endswith('m'):
770 qb_mem = qb_mem[:-1]
771
772 # Add -m prefix it not present
773 if not qb_mem.startswith('-m'):
774 qb_mem = '-m %s' % qb_mem
775
776 self.set('QB_MEM', qb_mem)
777
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800778 mach = self.get('MACHINE')
779 if not mach.startswith('qemumips'):
780 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
781
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600782 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500783
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600784 def check_tcpserial(self):
785 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400786 ports = self.tcpserial_portnum.split(':')
787 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600788 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400789 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600790 else:
Brad Bishop15ae2502019-06-18 21:44:24 -0400791 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
792
793 if len(ports) > 1:
794 for port in ports[1:]:
795 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600797 def check_and_set(self):
798 """Check configs sanity and set when needed"""
799 self.validate_paths()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500800 if not self.slirp_enabled:
801 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600802 # Check audio
803 if self.audio_enabled:
804 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500805 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600806 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800807 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600808 else:
809 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
810 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
811 else:
812 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500813
Brad Bishop15ae2502019-06-18 21:44:24 -0400814 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600815 self.check_kvm()
816 self.check_fstype()
817 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500818 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600819 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400820 self.check_dtb()
Brad Bishopc68388fc2019-08-26 01:33:31 -0400821 self.check_bios()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600822 self.check_mem()
823 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600825 def read_qemuboot(self):
826 if not self.qemuboot:
827 if self.get('DEPLOY_DIR_IMAGE'):
828 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600829 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800830 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600831 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500832
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600833 if self.rootfs and not os.path.exists(self.rootfs):
834 # Lazy rootfs
835 machine = self.get('MACHINE')
836 if not machine:
837 machine = os.path.basename(deploy_dir_image)
838 self.qemuboot = "%s/%s-%s.qemuboot.conf" % (deploy_dir_image,
839 self.rootfs, machine)
840 else:
841 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500842 logger.debug('Running %s...' % cmd)
843 try:
844 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
845 except subprocess.CalledProcessError as err:
846 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600847 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500848 for qb in qbs.split():
849 # Don't use initramfs when other choices unless fstype is ramfs
850 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
851 continue
852 self.qemuboot = qb
853 break
854 if not self.qemuboot:
855 # Use the first one when no choice
856 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600857 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500858
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600859 if not self.qemuboot:
860 # If we haven't found a .qemuboot.conf at this point it probably
861 # doesn't exist, continue without
862 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500863
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600864 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500865 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 -0500866
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500867 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500868
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600869 cf = configparser.ConfigParser()
870 cf.read(self.qemuboot)
871 for k, v in cf.items('config_bsp'):
872 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500873 if v.startswith("../"):
874 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
875 elif v == ".":
876 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600877 self.set(k_upper, v)
878
879 def validate_paths(self):
880 """Ensure all relevant path variables are set"""
881 # When we're started with a *.qemuboot.conf arg assume that image
882 # artefacts are relative to that file, rather than in whatever
883 # directory DEPLOY_DIR_IMAGE in the conf file points to.
884 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500885 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
886 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600887 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
888 self.set('DEPLOY_DIR_IMAGE', imgdir)
889
890 # If the STAGING_*_NATIVE directories from the config file don't exist
891 # and we're in a sourced OE build directory try to extract the paths
892 # from `bitbake -e`
893 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
894 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
895
896 if not havenative:
897 if not self.bitbake_e:
898 self.load_bitbake_env()
899
900 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500901 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600902 for nv in native_vars:
903 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
904 if s and s.group(1) != self.get(nv):
905 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
906 self.set(nv, s.group(1))
907 else:
908 # when we're invoked from a running bitbake instance we won't
909 # be able to call `bitbake -e`, then try:
910 # - get OE_TMPDIR from environment and guess paths based on it
911 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500912 tmpdir = self.get('OE_TMPDIR')
913 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600914 if tmpdir:
915 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
916 hostos, _, _, _, machine = os.uname()
917 buildsys = '%s-%s' % (machine, hostos.lower())
918 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
919 self.set('STAGING_DIR_NATIVE', staging_dir_native)
920 elif oecore_native_sysroot:
921 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
922 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
923 if self.get('STAGING_DIR_NATIVE'):
924 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
925 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
926 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
927 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
928
929 def print_config(self):
930 logger.info('Continuing with the following parameters:\n')
931 if not self.fstype in self.vmtypes:
932 print('KERNEL: [%s]' % self.kernel)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400933 if self.bios:
934 print('BIOS: [%s]' % self.bios)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600935 if self.dtb:
936 print('DTB: [%s]' % self.dtb)
937 print('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400938 try:
939 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
940 except KeyError:
941 fstype_flags = ''
942 print('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600943 if self.fstype == 'nfs':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500944 print('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600945 else:
946 print('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500947 if self.ovmf_bios:
948 print('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -0400949 if (self.ovmf_secboot_pkkek1):
950 print('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600951 print('CONFFILE: [%s]' % self.qemuboot)
952 print('')
953
954 def setup_nfs(self):
955 if not self.nfs_server:
956 if self.slirp_enabled:
957 self.nfs_server = '10.0.2.2'
958 else:
959 self.nfs_server = '192.168.7.1'
960
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500961 # Figure out a new nfs_instance to allow multiple qemus running.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500962 ps = subprocess.check_output(("ps", "auxww")).decode('utf-8')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500963 pattern = '/bin/unfsd .* -i .*\.pid -e .*/exports([0-9]+) '
964 all_instances = re.findall(pattern, ps, re.M)
965 if all_instances:
966 all_instances.sort(key=int)
967 self.nfs_instance = int(all_instances.pop()) + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600968
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500969 nfsd_port = 3049 + 2 * self.nfs_instance
970 mountd_port = 3048 + 2 * self.nfs_instance
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600971
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500972 # Export vars for runqemu-export-rootfs
973 export_dict = {
974 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500975 'NFSD_PORT': nfsd_port,
976 'MOUNTD_PORT': mountd_port,
977 }
978 for k, v in export_dict.items():
979 # Use '%s' since they are integers
980 os.putenv(k, '%s' % v)
981
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500982 self.unfs_opts="nfsvers=3,port=%s,udp,mountport=%s" % (nfsd_port, mountd_port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600983
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500984 # Extract .tar.bz2 or .tar.bz if no nfs dir
985 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600986 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
987 dest = "%s-nfsroot" % src_prefix
988 if os.path.exists('%s.pseudo_state' % dest):
989 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500990 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600991 else:
992 src = ""
993 src1 = '%s.tar.bz2' % src_prefix
994 src2 = '%s.tar.gz' % src_prefix
995 if os.path.exists(src1):
996 src = src1
997 elif os.path.exists(src2):
998 src = src2
999 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001000 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 -06001001 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -05001002 cmd = ('runqemu-extract-sdk', src, dest)
1003 logger.info('Running %s...' % str(cmd))
1004 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001005 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001006 self.clean_nfs_dir = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001007 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001008
1009 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001010 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1011 logger.info('Running %s...' % str(cmd))
1012 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001013 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001014
1015 self.nfs_running = True
1016
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001017 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001018 """Setup user networking"""
1019
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001020 if self.fstype == 'nfs':
1021 self.setup_nfs()
1022 self.kernel_cmdline_script += ' ip=dhcp'
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001023 # Port mapping
1024 hostfwd = ",hostfwd=tcp::2222-:22,hostfwd=tcp::2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001025 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001026 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1027 # Figure out the port
1028 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1029 ports = [int(i) for i in ports]
1030 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001031
1032 lockdir = "/tmp/qemu-port-locks"
1033 if not os.path.exists(lockdir):
1034 # There might be a race issue when multi runqemu processess are
1035 # running at the same time.
1036 try:
1037 os.mkdir(lockdir)
1038 os.chmod(lockdir, 0o777)
1039 except FileExistsError:
1040 pass
1041
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001042 # Find a free port to avoid conflicts
1043 for p in ports[:]:
1044 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001045 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001046 p_new += 1
1047 mac += 1
1048 while p_new in ports:
1049 p_new += 1
1050 mac += 1
1051 if p != p_new:
1052 ports.append(p_new)
1053 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1054 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1055 mac = "%s%02x" % (self.mac_slirp, mac)
1056 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1057 # Print out port foward
1058 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1059 if hostfwd:
1060 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001061
1062 def setup_tap(self):
1063 """Setup tap"""
1064
1065 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1066 # devices, indicating that the user should not bring up new ones using
1067 # sudo.
1068 nosudo_flag = '/etc/runqemu-nosudo'
1069 self.qemuifup = shutil.which('runqemu-ifup')
1070 self.qemuifdown = shutil.which('runqemu-ifdown')
1071 ip = shutil.which('ip')
1072 lockdir = "/tmp/qemu-tap-locks"
1073
1074 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001075 logger.error("runqemu-ifup: %s" % self.qemuifup)
1076 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1077 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001078 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1079
1080 if not os.path.exists(lockdir):
1081 # There might be a race issue when multi runqemu processess are
1082 # running at the same time.
1083 try:
1084 os.mkdir(lockdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001085 os.chmod(lockdir, 0o777)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001086 except FileExistsError:
1087 pass
1088
Brad Bishop977dc1a2019-02-06 16:01:43 -05001089 cmd = (ip, 'link')
1090 logger.debug('Running %s...' % str(cmd))
1091 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001092 # Matches line like: 6: tap0: <foo>
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001093 possibles = re.findall('^[0-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001094 tap = ""
1095 for p in possibles:
1096 lockfile = os.path.join(lockdir, p)
1097 if os.path.exists('%s.skip' % lockfile):
1098 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1099 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001100 self.taplock = lockfile + '.lock'
1101 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001102 tap = p
1103 logger.info("Using preconfigured tap device %s" % tap)
1104 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1105 break
1106
1107 if not tap:
1108 if os.path.exists(nosudo_flag):
1109 logger.error("Error: There are no available tap devices to use for networking,")
1110 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001111 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001112
1113 gid = os.getgid()
1114 uid = os.getuid()
1115 logger.info("Setting up tap interface under sudo")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001116 cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
1117 tap = subprocess.check_output(cmd).decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001118 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001119 self.taplock = lockfile + '.lock'
1120 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001121 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001122 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001123
1124 if not tap:
1125 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
1126 return 1
1127 self.tap = tap
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001128 tapnum = int(tap[3:])
1129 gateway = tapnum * 2 + 1
1130 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001131 if self.fstype == 'nfs':
1132 self.setup_nfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001133 netconf = "192.168.7.%s::192.168.7.%s:255.255.255.0" % (client, gateway)
1134 logger.info("Network configuration: %s", netconf)
1135 self.kernel_cmdline_script += " ip=%s" % netconf
1136 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001137 qb_tap_opt = self.get('QB_TAP_OPT')
1138 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001139 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001140 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001141 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001142
1143 if self.vhost_enabled:
1144 qemu_tap_opt += ',vhost=on'
1145
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001146 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001147
1148 def setup_network(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001149 if self.get('QB_NET') == 'none':
1150 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001151 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001152 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001153 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001154 if self.slirp_enabled:
1155 self.setup_slirp()
1156 else:
1157 self.setup_tap()
1158
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001159 def setup_rootfs(self):
1160 if self.get('QB_ROOTFS') == 'none':
1161 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001162 if 'wic.' in self.fstype:
1163 self.fstype = self.fstype[4:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001164 rootfs_format = self.fstype if self.fstype in ('vmdk', 'qcow2', 'vdi') else 'raw'
1165
1166 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1167 if qb_rootfs_opt:
1168 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1169 else:
1170 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1171
1172 if self.fstype in ('cpio.gz', 'cpio'):
1173 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1174 self.rootfs_options = '-initrd %s' % self.rootfs
1175 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001176 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001177 if self.fstype in self.vmtypes:
1178 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001179 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001180 elif self.get('QB_DRIVE_TYPE'):
1181 drive_type = self.get('QB_DRIVE_TYPE')
1182 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001183 logger.info('Using scsi drive')
1184 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' \
1185 % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001186 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001187 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001188 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001189 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001190 # virtio might have been selected explicitly (just use it), or
1191 # is used as fallback (then warn about that).
1192 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001193 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1194 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1195 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001196 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001197
1198 # All branches above set vm_drive.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001199 self.rootfs_options = '%s -no-reboot' % vm_drive
1200 self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('QB_KERNEL_ROOT'))
1201
1202 if self.fstype == 'nfs':
1203 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001204 k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server, os.path.abspath(self.rootfs), self.unfs_opts)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001205 self.kernel_cmdline = 'root=%s rw highres=off' % k_root
1206
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001207 if self.fstype == 'none':
1208 self.rootfs_options = ''
1209
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001210 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1211
1212 def guess_qb_system(self):
1213 """attempt to determine the appropriate qemu-system binary"""
1214 mach = self.get('MACHINE')
1215 if not mach:
1216 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
1217 if self.rootfs:
1218 match = re.match(search, self.rootfs)
1219 if match:
1220 mach = match.group(1)
1221 elif self.kernel:
1222 match = re.match(search, self.kernel)
1223 if match:
1224 mach = match.group(1)
1225
1226 if not mach:
1227 return None
1228
1229 if mach == 'qemuarm':
1230 qbsys = 'arm'
1231 elif mach == 'qemuarm64':
1232 qbsys = 'aarch64'
1233 elif mach == 'qemux86':
1234 qbsys = 'i386'
1235 elif mach == 'qemux86-64':
1236 qbsys = 'x86_64'
1237 elif mach == 'qemuppc':
1238 qbsys = 'ppc'
1239 elif mach == 'qemumips':
1240 qbsys = 'mips'
1241 elif mach == 'qemumips64':
1242 qbsys = 'mips64'
1243 elif mach == 'qemumipsel':
1244 qbsys = 'mipsel'
1245 elif mach == 'qemumips64el':
1246 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001247 elif mach == 'qemuriscv64':
1248 qbsys = 'riscv64'
1249 elif mach == 'qemuriscv32':
1250 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001251 else:
1252 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1253 logger.error("As %s is not among valid QEMU machines such as," % mach)
1254 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1255 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001256
1257 return 'qemu-system-%s' % qbsys
1258
Brad Bishop15ae2502019-06-18 21:44:24 -04001259 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001260 qemu_system = self.get('QB_SYSTEM_NAME')
1261 if not qemu_system:
1262 qemu_system = self.guess_qb_system()
1263 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001264 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001265 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001266
Brad Bishop15ae2502019-06-18 21:44:24 -04001267 def setup_final(self):
1268 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001269
1270 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1271 # find QEMU in sysroot, it needs to use host's qemu.
1272 if not os.path.exists(qemu_bin):
1273 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1274 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001275 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001276 logger.info("Trying: %s" % qemu_bin_tmp)
1277 if os.path.exists(qemu_bin_tmp):
1278 qemu_bin = qemu_bin_tmp
1279 if not os.path.isabs(qemu_bin):
1280 qemu_bin = os.path.abspath(qemu_bin)
1281 logger.info("Using host's QEMU: %s" % qemu_bin)
1282 break
1283
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001284 if not os.access(qemu_bin, os.X_OK):
1285 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
1286
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001287 self.qemu_opt = "%s %s %s %s" % (qemu_bin, self.get('NETWORK_CMD'), self.get('ROOTFS_OPTIONS'), self.get('QB_OPT_APPEND'))
1288
1289 for ovmf in self.ovmf_bios:
1290 format = ovmf.rsplit('.', 1)[-1]
1291 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001292
1293 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001294
Brad Bishop08902b02019-08-20 09:16:51 -04001295 if self.ovmf_secboot_pkkek1:
1296 # Provide the Platform Key and first Key Exchange Key certificate as an
1297 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1298 # with "application prefix" of the EnrollDefaultKeys.efi application
1299 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1300 + self.ovmf_secboot_pkkek1
1301
Andrew Geissler99467da2019-02-25 18:54:23 -06001302 # Append qemuparams to override previous settings
1303 if self.qemuparams:
1304 self.qemu_opt += ' ' + self.qemuparams
1305
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001306 if self.snapshot:
1307 self.qemu_opt += " -snapshot"
1308
Brad Bishop19323692019-04-05 15:28:33 -04001309 if self.serialconsole:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001310 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001311 subprocess.check_call(("stty", "intr", "^]"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001312 logger.info("Interrupt character is '^]'")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001313
1314 first_serial = ""
1315 if not re.search("-nographic", self.qemu_opt):
1316 first_serial = "-serial mon:vc"
1317 # We always want a ttyS1. Since qemu by default adds a serial
1318 # port when nodefaults is not specified, it seems that all that
1319 # would be needed is to make sure a "-serial" is there. However,
1320 # it appears that when "-serial" is specified, it ignores the
1321 # default serial port that is normally added. So here we make
1322 # sure to add two -serial if there are none. And only one if
1323 # there is one -serial already.
1324 serial_num = len(re.findall("-serial", self.qemu_opt))
1325 if serial_num == 0:
1326 self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
1327 elif serial_num == 1:
1328 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1329
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001330 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES),
1331 # if not serial or serialtcp options was specified only ttyS0 is created
1332 # and sysvinit shows an error trying to enable ttyS1:
1333 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1334 serial_num = len(re.findall("-serial", self.qemu_opt))
1335 if serial_num == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001336 if re.search("-nographic", self.qemu_opt) or self.serialstdio:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001337 self.qemu_opt += " -serial mon:stdio -serial null"
1338 else:
1339 self.qemu_opt += " -serial mon:vc -serial null"
1340
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001341 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001342 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001343 if self.kernel:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001344 kernel_opts = "-kernel %s -append '%s %s %s %s'" % (self.kernel, self.kernel_cmdline,
1345 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1346 self.bootparams)
Brad Bishopc68388fc2019-08-26 01:33:31 -04001347 if self.bios:
1348 kernel_opts += " -bios %s" % self.bios
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001349 if self.dtb:
1350 kernel_opts += " -dtb %s" % self.dtb
1351 else:
1352 kernel_opts = ""
1353 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001354 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001355 logger.info('Running %s\n' % cmd)
Brad Bishopf86d0552018-12-04 14:18:15 -08001356 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001357 if self.taplock_descriptor:
1358 pass_fds = [self.taplock_descriptor.fileno()]
1359 if len(self.portlocks):
1360 for descriptor in self.portlocks.values():
1361 pass_fds.append(descriptor.fileno())
Brad Bishopf86d0552018-12-04 14:18:15 -08001362 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
Brad Bishop004d4992018-10-02 23:54:45 +02001363 self.qemupid = process.pid
1364 retcode = process.wait()
1365 if retcode:
1366 if retcode == -signal.SIGTERM:
1367 logger.info("Qemu terminated by SIGTERM")
1368 else:
1369 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001370
1371 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001372 if self.cleaned:
1373 return
1374
1375 # avoid dealing with SIGTERM when cleanup function is running
1376 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1377
1378 logger.info("Cleaning up")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001379 if self.cleantap:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001380 cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
1381 logger.debug('Running %s' % str(cmd))
1382 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001383 self.release_taplock()
1384 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001385
1386 if self.nfs_running:
1387 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001388 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1389 logger.debug('Running %s' % str(cmd))
1390 subprocess.check_call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001391
1392 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001393 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001394
1395 if self.clean_nfs_dir:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001396 logger.info('Removing %s' % self.rootfs)
1397 shutil.rmtree(self.rootfs)
1398 shutil.rmtree('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001399
Brad Bishop004d4992018-10-02 23:54:45 +02001400 self.cleaned = True
1401
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001402 def load_bitbake_env(self, mach=None):
1403 if self.bitbake_e:
1404 return
1405
1406 bitbake = shutil.which('bitbake')
1407 if not bitbake:
1408 return
1409
1410 if not mach:
1411 mach = self.get('MACHINE')
1412
1413 if mach:
1414 cmd = 'MACHINE=%s bitbake -e' % mach
1415 else:
1416 cmd = 'bitbake -e'
1417
1418 logger.info('Running %s...' % cmd)
1419 try:
1420 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
1421 except subprocess.CalledProcessError as err:
1422 self.bitbake_e = ''
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001423 logger.warning("Couldn't run 'bitbake -e' to gather environment information:\n%s" % err.output.decode('utf-8'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001424
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001425 def validate_combos(self):
1426 if (self.fstype in self.vmtypes) and self.kernel:
1427 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1428
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001429 @property
1430 def bindir_native(self):
1431 result = self.get('STAGING_BINDIR_NATIVE')
1432 if result and os.path.exists(result):
1433 return result
1434
Brad Bishop977dc1a2019-02-06 16:01:43 -05001435 cmd = ('bitbake', 'qemu-helper-native', '-e')
1436 logger.info('Running %s...' % str(cmd))
1437 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001438
1439 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1440 if match:
1441 result = match.group(1)
1442 if os.path.exists(result):
1443 self.set('STAGING_BINDIR_NATIVE', result)
1444 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001445 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001446 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001447 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001448
1449
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001450def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001451 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001452 print_usage()
1453 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001454 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001455 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001456
1457 def sigterm_handler(signum, frame):
1458 logger.info("SIGTERM received")
1459 os.kill(config.qemupid, signal.SIGTERM)
1460 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001461 # Deliberately ignore the return code of 'tput smam'.
1462 subprocess.call(["tput", "smam"])
Brad Bishop004d4992018-10-02 23:54:45 +02001463 signal.signal(signal.SIGTERM, sigterm_handler)
1464
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001465 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001466 config.read_qemuboot()
1467 config.check_and_set()
1468 # Check whether the combos is valid or not
1469 config.validate_combos()
1470 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001471 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001472 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001473 config.setup_final()
1474 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001475 except RunQemuError as err:
1476 logger.error(err)
1477 return 1
1478 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001479 import traceback
1480 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001481 return 1
1482 finally:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001483 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001484 # Deliberately ignore the return code of 'tput smam'.
1485 subprocess.call(["tput", "smam"])
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001486
1487if __name__ == "__main__":
1488 sys.exit(main())