blob: df3c8aad0844c1b3f3fc853b1548a699eb54d8d4 [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
62 ROOTFS - the rootfs image file or nfsroot directory to use
Brad Bishop316dfdd2018-06-25 12:45:53 -040063 DEVICE_TREE - the device tree blob to use
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064 MACHINE - the machine name (optional, autodetected from KERNEL filename if unspecified)
65 Simplified QEMU command-line options can be passed with:
Patrick Williamsc0f7c042017-02-23 20:41:17 -060066 nographic - disable video console
Brad Bishop19323692019-04-05 15:28:33 -040067 sdl - choose the SDL frontend instead of the Gtk+ default
68 gtk-gl - enable virgl-based GL acceleration using Gtk+ frontend
69 gtk-gl-es - enable virgl-based GL acceleration, using OpenGL ES and Gtk+ frontend
70 egl-headless - enable headless EGL output; use vnc or spice to see it
Patrick Williamsc0f7c042017-02-23 20:41:17 -060071 serial - enable a serial console on /dev/ttyS0
Brad Bishop19323692019-04-05 15:28:33 -040072 serialstdio - enable a serial console on the console (regardless of graphics mode)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060073 slirp - enable user networking, no root privileges is required
74 kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
75 kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050076 publicvnc - enable a VNC server open to all hosts
Patrick Williamsc0f7c042017-02-23 20:41:17 -060077 audio - enable audio
Brad Bishop6e60e8b2018-02-01 10:27:11 -050078 [*/]ovmf* - OVMF firmware file or base name for booting with UEFI
Patrick Williamsc0f7c042017-02-23 20:41:17 -060079 tcpserial=<port> - specify tcp serial port number
80 biosdir=<dir> - specify custom bios dir
81 biosfilename=<filename> - specify bios filename
82 qemuparams=<xyz> - specify custom parameters to QEMU
83 bootparams=<xyz> - specify custom kernel parameters during boot
Brad Bishop6e60e8b2018-02-01 10:27:11 -050084 help, -h, --help: print this text
Brad Bishopd7bf8c12018-02-25 22:55:05 -050085 -d, --debug: Enable debug output
86 -q, --quite: Hide most output except error messages
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050087
88Examples:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 runqemu
Patrick Williamsc0f7c042017-02-23 20:41:17 -060090 runqemu qemuarm
91 runqemu tmp/deploy/images/qemuarm
Brad Bishop6e60e8b2018-02-01 10:27:11 -050092 runqemu tmp/deploy/images/qemux86/<qemuboot.conf>
Patrick Williamsc0f7c042017-02-23 20:41:17 -060093 runqemu qemux86-64 core-image-sato ext4
94 runqemu qemux86-64 wic-image-minimal wic
95 runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
Brad Bishopd7bf8c12018-02-25 22:55:05 -050096 runqemu qemux86 iso/hddimg/wic.vmdk/wic.qcow2/wic.vdi/ramfs/cpio.gz...
Patrick Williamsc0f7c042017-02-23 20:41:17 -060097 runqemu qemux86 qemuparams="-m 256"
98 runqemu qemux86 bootparams="psplash=false"
Patrick Williamsc0f7c042017-02-23 20:41:17 -060099 runqemu path/to/<image>-<machine>.wic
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500100 runqemu path/to/<image>-<machine>.wic.vmdk
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600101""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500102
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600103def check_tun():
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500104 """Check /dev/net/tun"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600105 dev_tun = '/dev/net/tun'
106 if not os.path.exists(dev_tun):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500107 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 -0500108
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600109 if not os.access(dev_tun, os.W_OK):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500110 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 -0500111
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600112def get_first_file(cmds):
113 """Return first file found in wildcard cmds"""
114 for cmd in cmds:
115 all_files = glob.glob(cmd)
116 if all_files:
117 for f in all_files:
118 if not os.path.isdir(f):
119 return f
120 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500121
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600122class BaseConfig(object):
123 def __init__(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500124 # The self.d saved vars from self.set(), part of them are from qemuboot.conf
125 self.d = {'QB_KERNEL_ROOT': '/dev/vda'}
126
127 # Supported env vars, add it here if a var can be got from env,
128 # and don't use os.getenv in the code.
129 self.env_vars = ('MACHINE',
130 'ROOTFS',
131 'KERNEL',
Brad Bishop316dfdd2018-06-25 12:45:53 -0400132 'DEVICE_TREE',
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500133 'DEPLOY_DIR_IMAGE',
134 'OE_TMPDIR',
135 'OECORE_NATIVE_SYSROOT',
136 )
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500137
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600138 self.qemu_opt = ''
139 self.qemu_opt_script = ''
Andrew Geissler99467da2019-02-25 18:54:23 -0600140 self.qemuparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600141 self.clean_nfs_dir = False
142 self.nfs_server = ''
143 self.rootfs = ''
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 # File name(s) of a OVMF firmware file or variable store,
145 # to be added with -drive if=pflash.
146 # Found in the same places as the rootfs, with or without one of
147 # these suffices: qcow2, bin.
148 # Setting one also adds "-vga std" because that is all that
149 # OVMF supports.
150 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 = ''
158 self.kernel_cmdline = ''
159 self.kernel_cmdline_script = ''
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500160 self.bootparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600161 self.dtb = ''
162 self.fstype = ''
163 self.kvm_enabled = False
164 self.vhost_enabled = False
165 self.slirp_enabled = False
166 self.nfs_instance = 0
167 self.nfs_running = False
Brad Bishop19323692019-04-05 15:28:33 -0400168 self.serialconsole = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600169 self.serialstdio = False
170 self.cleantap = False
171 self.saved_stty = ''
172 self.audio_enabled = False
173 self.tcpserial_portnum = ''
174 self.custombiosdir = ''
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'
441 elif arg == 'gtk-gl':
442 self.qemu_opt_script += ' -vga virtio -display gtk,gl=on'
443 elif arg == 'gtk-gl-es':
444 self.qemu_opt_script += ' -vga virtio -display gtk,gl=es'
445 elif arg == 'egl-headless':
446 self.qemu_opt_script += ' -vga virtio -display egl-headless'
447 # As runqemu can be run within bitbake (when using testimage, for example),
448 # we need to ensure that we run host pkg-config, and that it does not
449 # get mis-directed to native build paths set by bitbake.
450 try:
451 del os.environ['PKG_CONFIG_PATH']
452 del os.environ['PKG_CONFIG_DIR']
453 del os.environ['PKG_CONFIG_LIBDIR']
454 except KeyError:
455 pass
456 try:
457 dripath = subprocess.check_output("PATH=/bin:/usr/bin:$PATH pkg-config --variable=dridriverdir dri", shell=True)
458 except subprocess.CalledProcessError as e:
459 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.")
460 os.environ['LIBGL_DRIVERS_PATH'] = dripath.decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600461 elif arg == 'serial':
462 self.kernel_cmdline_script += ' console=ttyS0'
Brad Bishop19323692019-04-05 15:28:33 -0400463 self.serialconsole = True
464 elif arg == "serialstdio":
465 self.kernel_cmdline_script += ' console=ttyS0'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600466 self.serialstdio = True
467 elif arg == 'audio':
468 logger.info("Enabling audio in qemu")
469 logger.info("Please install sound drivers in linux host")
470 self.audio_enabled = True
471 elif arg == 'kvm':
472 self.kvm_enabled = True
473 elif arg == 'kvm-vhost':
474 self.vhost_enabled = True
475 elif arg == 'slirp':
476 self.slirp_enabled = True
477 elif arg == 'snapshot':
478 self.snapshot = True
479 elif arg == 'publicvnc':
480 self.qemu_opt_script += ' -vnc :0'
481 elif arg.startswith('tcpserial='):
Brad Bishop15ae2502019-06-18 21:44:24 -0400482 self.tcpserial_portnum = '%s' % arg[len('tcpserial='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600483 elif arg.startswith('biosdir='):
484 self.custombiosdir = arg[len('biosdir='):]
485 elif arg.startswith('biosfilename='):
486 self.qemu_opt_script += ' -bios %s' % arg[len('biosfilename='):]
487 elif arg.startswith('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600488 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600489 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500490 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600491 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
492 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500493 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600494 # Lazy rootfs
495 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500496 elif arg.startswith('ovmf'):
497 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600498 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500499 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600500 if (not unknown_arg) or unknown_arg == arg:
501 unknown_arg = arg
502 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500503 raise RunQemuError("Can't handle two unknown args: %s %s\n"
504 "Try 'runqemu help' on how to use it" % \
505 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600506 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300507 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500508 if self.get('DEPLOY_DIR_IMAGE'):
509 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
510 if unknown_arg == machine:
511 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600513 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500514
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500515 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500516 self.load_bitbake_env()
517 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
518 if s:
519 self.set("DEPLOY_DIR_IMAGE", s.group(1))
520
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600521 def check_kvm(self):
522 """Check kvm and kvm-host"""
523 if not (self.kvm_enabled or self.vhost_enabled):
524 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU'))
525 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500526
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600527 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500528 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500529
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600530 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'))
531 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
532 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
533 dev_kvm = '/dev/kvm'
534 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400535 if self.qemu_system.endswith(('i386', 'x86_64')):
536 with open('/proc/cpuinfo', 'r') as f:
537 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
538 if not kvm_cap:
539 logger.error("You are trying to enable KVM on a cpu without VT support.")
540 logger.error("Remove kvm from the command-line, or refer:")
541 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500542
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600543 if not os.path.exists(dev_kvm):
544 logger.error("Missing KVM device. Have you inserted kvm modules?")
545 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500546 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500547
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600548 if os.access(dev_kvm, os.W_OK|os.R_OK):
549 self.qemu_opt_script += ' -enable-kvm'
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500550 if self.get('MACHINE') == "qemux86":
551 # Workaround for broken APIC window on pre 4.15 host kernels which causes boot hangs
552 # See YOCTO #12301
553 # On 64 bit we use x2apic
554 self.kernel_cmdline_script += " clocksource=kvm-clock hpet=disable noapic nolapic"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600555 else:
556 logger.error("You have no read or write permission on /dev/kvm.")
557 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500558 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500559
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600560 if self.vhost_enabled:
561 if not os.path.exists(dev_vhost):
562 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
563 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500564 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600566 if not os.access(dev_kvm, os.W_OK|os.R_OK):
567 logger.error("You have no read or write permission on /dev/vhost-net.")
568 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500569 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600571 def check_fstype(self):
572 """Check and setup FSTYPE"""
573 if not self.fstype:
574 fstype = self.get('QB_DEFAULT_FSTYPE')
575 if fstype:
576 self.fstype = fstype
577 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500578 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500579
Brad Bishop15ae2502019-06-18 21:44:24 -0400580 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
581 wic_fs = False
582 qb_fsinfo = self.get('QB_FSINFO')
583 if qb_fsinfo:
584 qb_fsinfo = qb_fsinfo.split()
585 for fsinfo in qb_fsinfo:
586 try:
587 fstype, fsflag = fsinfo.split(':')
588
589 if fstype == 'wic':
590 if fsflag == 'no-kernel-in-fs':
591 wic_fs = True
592 elif fsflag == 'kernel-in-fs':
593 wic_fs = False
594 else:
595 logger.warn('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
596 continue
597 else:
598 logger.warn('QB_FSINFO is not supported for image type "%s"', fstype)
599 continue
600
601 if fstype in self.fsinfo:
602 self.fsinfo[fstype].append(fsflag)
603 else:
604 self.fsinfo[fstype] = [fsflag]
605 except Exception:
606 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
607
608 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
609 if wic_fs:
610 self.fstypes = self.fstypes + self.wictypes
611 else:
612 self.vmtypes = self.vmtypes + self.wictypes
613
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600614 def check_rootfs(self):
615 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500616
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500617 if self.fstype == "none":
618 return
619
620 if self.get('ROOTFS'):
621 if not self.rootfs:
622 self.rootfs = self.get('ROOTFS')
623 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500624 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500625
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600626 if self.fstype == 'nfs':
627 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500628
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600629 if self.rootfs and not os.path.exists(self.rootfs):
630 # Lazy rootfs
631 self.rootfs = "%s/%s-%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
632 self.rootfs, self.get('MACHINE'),
633 self.fstype)
634 elif not self.rootfs:
635 cmd_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
636 cmd_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
637 cmds = (cmd_name, cmd_link)
638 self.rootfs = get_first_file(cmds)
639 if not self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500640 raise RunQemuError("Failed to find rootfs: %s or %s" % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600642 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500643 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644
Brad Bishop08902b02019-08-20 09:16:51 -0400645 def setup_pkkek1(self):
646 """
647 Extract from PEM certificate the Platform Key and first Key
648 Exchange Key certificate string. The hypervisor needs to provide
649 it in the Type 11 SMBIOS table
650 """
651 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
652 try:
653 with open(pemcert, 'r') as pemfile:
654 key = pemfile.read().replace('\n', ''). \
655 replace('-----BEGIN CERTIFICATE-----', ''). \
656 replace('-----END CERTIFICATE-----', '')
657 self.ovmf_secboot_pkkek1 = key
658
659 except FileNotFoundError:
660 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
661
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500662 def check_ovmf(self):
663 """Check and set full path for OVMF firmware and variable file(s)."""
664
665 for index, ovmf in enumerate(self.ovmf_bios):
666 if os.path.exists(ovmf):
667 continue
668 for suffix in ('qcow2', 'bin'):
669 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
670 if os.path.exists(path):
671 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400672 if ovmf.endswith('secboot'):
673 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500674 break
675 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500676 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500677
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600678 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400679 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600680 # The vm image doesn't need a kernel
681 if self.fstype in self.vmtypes:
682 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500683
Brad Bishop316dfdd2018-06-25 12:45:53 -0400684 # See if the user supplied a KERNEL option
685 if self.get('KERNEL'):
686 self.kernel = self.get('KERNEL')
687
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500688 # QB_DEFAULT_KERNEL is always a full file path
689 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
690
691 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400692 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500693 return
694
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600695 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
696 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500697 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600698 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
699 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
700 cmds = (kernel_match_name, kernel_match_link, kernel_startswith)
701 self.kernel = get_first_file(cmds)
702 if not self.kernel:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500703 raise RunQemuError('KERNEL not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500704
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600705 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500706 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500707
Brad Bishop316dfdd2018-06-25 12:45:53 -0400708 def check_dtb(self):
709 """Check and set dtb"""
710 # Did the user specify a device tree?
711 if self.get('DEVICE_TREE'):
712 self.dtb = self.get('DEVICE_TREE')
713 if not os.path.exists(self.dtb):
714 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
715 return
716
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600717 dtb = self.get('QB_DTB')
718 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400719 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600720 cmd_match = "%s/%s" % (deploy_dir_image, dtb)
721 cmd_startswith = "%s/%s*" % (deploy_dir_image, dtb)
722 cmd_wild = "%s/*.dtb" % deploy_dir_image
723 cmds = (cmd_match, cmd_startswith, cmd_wild)
724 self.dtb = get_first_file(cmds)
725 if not os.path.exists(self.dtb):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500726 raise RunQemuError('DTB not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500727
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600728 def check_biosdir(self):
729 """Check custombiosdir"""
730 if not self.custombiosdir:
731 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500732
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600733 biosdir = ""
734 biosdir_native = "%s/%s" % (self.get('STAGING_DIR_NATIVE'), self.custombiosdir)
735 biosdir_host = "%s/%s" % (self.get('STAGING_DIR_HOST'), self.custombiosdir)
736 for i in (self.custombiosdir, biosdir_native, biosdir_host):
737 if os.path.isdir(i):
738 biosdir = i
739 break
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500740
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600741 if biosdir:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500742 logger.debug("Assuming biosdir is: %s" % biosdir)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600743 self.qemu_opt_script += ' -L %s' % biosdir
744 else:
745 logger.error("Custom BIOS directory not found. Tried: %s, %s, and %s" % (self.custombiosdir, biosdir_native, biosdir_host))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500746 raise RunQemuError("Invalid custombiosdir: %s" % self.custombiosdir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600748 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600749 """
750 Both qemu and kernel needs memory settings, so check QB_MEM and set it
751 for both.
752 """
753 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600754 if s:
755 self.set('QB_MEM', '-m %s' % s.group(1))
756 elif not self.get('QB_MEM'):
757 logger.info('QB_MEM is not set, use 512M by default')
758 self.set('QB_MEM', '-m 512')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500759
Andrew Geissler99467da2019-02-25 18:54:23 -0600760 # Check and remove M or m suffix
761 qb_mem = self.get('QB_MEM')
762 if qb_mem.endswith('M') or qb_mem.endswith('m'):
763 qb_mem = qb_mem[:-1]
764
765 # Add -m prefix it not present
766 if not qb_mem.startswith('-m'):
767 qb_mem = '-m %s' % qb_mem
768
769 self.set('QB_MEM', qb_mem)
770
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800771 mach = self.get('MACHINE')
772 if not mach.startswith('qemumips'):
773 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
774
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600775 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600777 def check_tcpserial(self):
778 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400779 ports = self.tcpserial_portnum.split(':')
780 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600781 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400782 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600783 else:
Brad Bishop15ae2502019-06-18 21:44:24 -0400784 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
785
786 if len(ports) > 1:
787 for port in ports[1:]:
788 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500789
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600790 def check_and_set(self):
791 """Check configs sanity and set when needed"""
792 self.validate_paths()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500793 if not self.slirp_enabled:
794 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600795 # Check audio
796 if self.audio_enabled:
797 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500798 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600799 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800800 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600801 else:
802 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
803 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
804 else:
805 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500806
Brad Bishop15ae2502019-06-18 21:44:24 -0400807 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600808 self.check_kvm()
809 self.check_fstype()
810 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500811 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600812 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400813 self.check_dtb()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600814 self.check_biosdir()
815 self.check_mem()
816 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500817
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600818 def read_qemuboot(self):
819 if not self.qemuboot:
820 if self.get('DEPLOY_DIR_IMAGE'):
821 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600822 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800823 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600824 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500825
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600826 if self.rootfs and not os.path.exists(self.rootfs):
827 # Lazy rootfs
828 machine = self.get('MACHINE')
829 if not machine:
830 machine = os.path.basename(deploy_dir_image)
831 self.qemuboot = "%s/%s-%s.qemuboot.conf" % (deploy_dir_image,
832 self.rootfs, machine)
833 else:
834 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500835 logger.debug('Running %s...' % cmd)
836 try:
837 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
838 except subprocess.CalledProcessError as err:
839 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600840 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500841 for qb in qbs.split():
842 # Don't use initramfs when other choices unless fstype is ramfs
843 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
844 continue
845 self.qemuboot = qb
846 break
847 if not self.qemuboot:
848 # Use the first one when no choice
849 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600850 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600852 if not self.qemuboot:
853 # If we haven't found a .qemuboot.conf at this point it probably
854 # doesn't exist, continue without
855 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500856
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600857 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500858 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 -0500859
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500860 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500861
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600862 cf = configparser.ConfigParser()
863 cf.read(self.qemuboot)
864 for k, v in cf.items('config_bsp'):
865 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500866 if v.startswith("../"):
867 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
868 elif v == ".":
869 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600870 self.set(k_upper, v)
871
872 def validate_paths(self):
873 """Ensure all relevant path variables are set"""
874 # When we're started with a *.qemuboot.conf arg assume that image
875 # artefacts are relative to that file, rather than in whatever
876 # directory DEPLOY_DIR_IMAGE in the conf file points to.
877 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500878 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
879 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600880 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
881 self.set('DEPLOY_DIR_IMAGE', imgdir)
882
883 # If the STAGING_*_NATIVE directories from the config file don't exist
884 # and we're in a sourced OE build directory try to extract the paths
885 # from `bitbake -e`
886 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
887 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
888
889 if not havenative:
890 if not self.bitbake_e:
891 self.load_bitbake_env()
892
893 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600895 for nv in native_vars:
896 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
897 if s and s.group(1) != self.get(nv):
898 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
899 self.set(nv, s.group(1))
900 else:
901 # when we're invoked from a running bitbake instance we won't
902 # be able to call `bitbake -e`, then try:
903 # - get OE_TMPDIR from environment and guess paths based on it
904 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500905 tmpdir = self.get('OE_TMPDIR')
906 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600907 if tmpdir:
908 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
909 hostos, _, _, _, machine = os.uname()
910 buildsys = '%s-%s' % (machine, hostos.lower())
911 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
912 self.set('STAGING_DIR_NATIVE', staging_dir_native)
913 elif oecore_native_sysroot:
914 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
915 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
916 if self.get('STAGING_DIR_NATIVE'):
917 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
918 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
919 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
920 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
921
922 def print_config(self):
923 logger.info('Continuing with the following parameters:\n')
924 if not self.fstype in self.vmtypes:
925 print('KERNEL: [%s]' % self.kernel)
926 if self.dtb:
927 print('DTB: [%s]' % self.dtb)
928 print('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400929 try:
930 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
931 except KeyError:
932 fstype_flags = ''
933 print('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600934 if self.fstype == 'nfs':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500935 print('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600936 else:
937 print('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500938 if self.ovmf_bios:
939 print('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -0400940 if (self.ovmf_secboot_pkkek1):
941 print('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600942 print('CONFFILE: [%s]' % self.qemuboot)
943 print('')
944
945 def setup_nfs(self):
946 if not self.nfs_server:
947 if self.slirp_enabled:
948 self.nfs_server = '10.0.2.2'
949 else:
950 self.nfs_server = '192.168.7.1'
951
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500952 # Figure out a new nfs_instance to allow multiple qemus running.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500953 ps = subprocess.check_output(("ps", "auxww")).decode('utf-8')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500954 pattern = '/bin/unfsd .* -i .*\.pid -e .*/exports([0-9]+) '
955 all_instances = re.findall(pattern, ps, re.M)
956 if all_instances:
957 all_instances.sort(key=int)
958 self.nfs_instance = int(all_instances.pop()) + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600959
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500960 nfsd_port = 3049 + 2 * self.nfs_instance
961 mountd_port = 3048 + 2 * self.nfs_instance
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600962
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500963 # Export vars for runqemu-export-rootfs
964 export_dict = {
965 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500966 'NFSD_PORT': nfsd_port,
967 'MOUNTD_PORT': mountd_port,
968 }
969 for k, v in export_dict.items():
970 # Use '%s' since they are integers
971 os.putenv(k, '%s' % v)
972
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500973 self.unfs_opts="nfsvers=3,port=%s,udp,mountport=%s" % (nfsd_port, mountd_port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600974
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500975 # Extract .tar.bz2 or .tar.bz if no nfs dir
976 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600977 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
978 dest = "%s-nfsroot" % src_prefix
979 if os.path.exists('%s.pseudo_state' % dest):
980 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500981 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600982 else:
983 src = ""
984 src1 = '%s.tar.bz2' % src_prefix
985 src2 = '%s.tar.gz' % src_prefix
986 if os.path.exists(src1):
987 src = src1
988 elif os.path.exists(src2):
989 src = src2
990 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500991 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 -0600992 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -0500993 cmd = ('runqemu-extract-sdk', src, dest)
994 logger.info('Running %s...' % str(cmd))
995 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500996 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600997 self.clean_nfs_dir = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500998 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600999
1000 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001001 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1002 logger.info('Running %s...' % str(cmd))
1003 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001004 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001005
1006 self.nfs_running = True
1007
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001008 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001009 """Setup user networking"""
1010
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001011 if self.fstype == 'nfs':
1012 self.setup_nfs()
1013 self.kernel_cmdline_script += ' ip=dhcp'
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001014 # Port mapping
1015 hostfwd = ",hostfwd=tcp::2222-:22,hostfwd=tcp::2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001016 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001017 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1018 # Figure out the port
1019 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1020 ports = [int(i) for i in ports]
1021 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001022
1023 lockdir = "/tmp/qemu-port-locks"
1024 if not os.path.exists(lockdir):
1025 # There might be a race issue when multi runqemu processess are
1026 # running at the same time.
1027 try:
1028 os.mkdir(lockdir)
1029 os.chmod(lockdir, 0o777)
1030 except FileExistsError:
1031 pass
1032
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001033 # Find a free port to avoid conflicts
1034 for p in ports[:]:
1035 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001036 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001037 p_new += 1
1038 mac += 1
1039 while p_new in ports:
1040 p_new += 1
1041 mac += 1
1042 if p != p_new:
1043 ports.append(p_new)
1044 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1045 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1046 mac = "%s%02x" % (self.mac_slirp, mac)
1047 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1048 # Print out port foward
1049 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1050 if hostfwd:
1051 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001052
1053 def setup_tap(self):
1054 """Setup tap"""
1055
1056 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1057 # devices, indicating that the user should not bring up new ones using
1058 # sudo.
1059 nosudo_flag = '/etc/runqemu-nosudo'
1060 self.qemuifup = shutil.which('runqemu-ifup')
1061 self.qemuifdown = shutil.which('runqemu-ifdown')
1062 ip = shutil.which('ip')
1063 lockdir = "/tmp/qemu-tap-locks"
1064
1065 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001066 logger.error("runqemu-ifup: %s" % self.qemuifup)
1067 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1068 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001069 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1070
1071 if not os.path.exists(lockdir):
1072 # There might be a race issue when multi runqemu processess are
1073 # running at the same time.
1074 try:
1075 os.mkdir(lockdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001076 os.chmod(lockdir, 0o777)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001077 except FileExistsError:
1078 pass
1079
Brad Bishop977dc1a2019-02-06 16:01:43 -05001080 cmd = (ip, 'link')
1081 logger.debug('Running %s...' % str(cmd))
1082 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001083 # Matches line like: 6: tap0: <foo>
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001084 possibles = re.findall('^[0-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001085 tap = ""
1086 for p in possibles:
1087 lockfile = os.path.join(lockdir, p)
1088 if os.path.exists('%s.skip' % lockfile):
1089 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1090 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001091 self.taplock = lockfile + '.lock'
1092 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001093 tap = p
1094 logger.info("Using preconfigured tap device %s" % tap)
1095 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1096 break
1097
1098 if not tap:
1099 if os.path.exists(nosudo_flag):
1100 logger.error("Error: There are no available tap devices to use for networking,")
1101 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001102 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001103
1104 gid = os.getgid()
1105 uid = os.getuid()
1106 logger.info("Setting up tap interface under sudo")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001107 cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
1108 tap = subprocess.check_output(cmd).decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001109 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001110 self.taplock = lockfile + '.lock'
1111 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001112 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001113 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001114
1115 if not tap:
1116 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
1117 return 1
1118 self.tap = tap
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001119 tapnum = int(tap[3:])
1120 gateway = tapnum * 2 + 1
1121 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001122 if self.fstype == 'nfs':
1123 self.setup_nfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001124 netconf = "192.168.7.%s::192.168.7.%s:255.255.255.0" % (client, gateway)
1125 logger.info("Network configuration: %s", netconf)
1126 self.kernel_cmdline_script += " ip=%s" % netconf
1127 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001128 qb_tap_opt = self.get('QB_TAP_OPT')
1129 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001130 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001131 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001132 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001133
1134 if self.vhost_enabled:
1135 qemu_tap_opt += ',vhost=on'
1136
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001137 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001138
1139 def setup_network(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001140 if self.get('QB_NET') == 'none':
1141 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001142 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001143 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001144 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001145 if self.slirp_enabled:
1146 self.setup_slirp()
1147 else:
1148 self.setup_tap()
1149
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001150 def setup_rootfs(self):
1151 if self.get('QB_ROOTFS') == 'none':
1152 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001153 if 'wic.' in self.fstype:
1154 self.fstype = self.fstype[4:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001155 rootfs_format = self.fstype if self.fstype in ('vmdk', 'qcow2', 'vdi') else 'raw'
1156
1157 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1158 if qb_rootfs_opt:
1159 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1160 else:
1161 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1162
1163 if self.fstype in ('cpio.gz', 'cpio'):
1164 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1165 self.rootfs_options = '-initrd %s' % self.rootfs
1166 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001167 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001168 if self.fstype in self.vmtypes:
1169 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001170 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001171 elif self.get('QB_DRIVE_TYPE'):
1172 drive_type = self.get('QB_DRIVE_TYPE')
1173 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001174 logger.info('Using scsi drive')
1175 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' \
1176 % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001177 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001178 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001179 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001180 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001181 # virtio might have been selected explicitly (just use it), or
1182 # is used as fallback (then warn about that).
1183 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001184 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1185 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1186 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001187 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001188
1189 # All branches above set vm_drive.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001190 self.rootfs_options = '%s -no-reboot' % vm_drive
1191 self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('QB_KERNEL_ROOT'))
1192
1193 if self.fstype == 'nfs':
1194 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001195 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 -06001196 self.kernel_cmdline = 'root=%s rw highres=off' % k_root
1197
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001198 if self.fstype == 'none':
1199 self.rootfs_options = ''
1200
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001201 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1202
1203 def guess_qb_system(self):
1204 """attempt to determine the appropriate qemu-system binary"""
1205 mach = self.get('MACHINE')
1206 if not mach:
1207 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
1208 if self.rootfs:
1209 match = re.match(search, self.rootfs)
1210 if match:
1211 mach = match.group(1)
1212 elif self.kernel:
1213 match = re.match(search, self.kernel)
1214 if match:
1215 mach = match.group(1)
1216
1217 if not mach:
1218 return None
1219
1220 if mach == 'qemuarm':
1221 qbsys = 'arm'
1222 elif mach == 'qemuarm64':
1223 qbsys = 'aarch64'
1224 elif mach == 'qemux86':
1225 qbsys = 'i386'
1226 elif mach == 'qemux86-64':
1227 qbsys = 'x86_64'
1228 elif mach == 'qemuppc':
1229 qbsys = 'ppc'
1230 elif mach == 'qemumips':
1231 qbsys = 'mips'
1232 elif mach == 'qemumips64':
1233 qbsys = 'mips64'
1234 elif mach == 'qemumipsel':
1235 qbsys = 'mipsel'
1236 elif mach == 'qemumips64el':
1237 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001238 elif mach == 'qemuriscv64':
1239 qbsys = 'riscv64'
1240 elif mach == 'qemuriscv32':
1241 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001242 else:
1243 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1244 logger.error("As %s is not among valid QEMU machines such as," % mach)
1245 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1246 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001247
1248 return 'qemu-system-%s' % qbsys
1249
Brad Bishop15ae2502019-06-18 21:44:24 -04001250 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001251 qemu_system = self.get('QB_SYSTEM_NAME')
1252 if not qemu_system:
1253 qemu_system = self.guess_qb_system()
1254 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001255 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001256 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001257
Brad Bishop15ae2502019-06-18 21:44:24 -04001258 def setup_final(self):
1259 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001260
1261 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1262 # find QEMU in sysroot, it needs to use host's qemu.
1263 if not os.path.exists(qemu_bin):
1264 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1265 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001266 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001267 logger.info("Trying: %s" % qemu_bin_tmp)
1268 if os.path.exists(qemu_bin_tmp):
1269 qemu_bin = qemu_bin_tmp
1270 if not os.path.isabs(qemu_bin):
1271 qemu_bin = os.path.abspath(qemu_bin)
1272 logger.info("Using host's QEMU: %s" % qemu_bin)
1273 break
1274
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001275 if not os.access(qemu_bin, os.X_OK):
1276 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
1277
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001278 self.qemu_opt = "%s %s %s %s" % (qemu_bin, self.get('NETWORK_CMD'), self.get('ROOTFS_OPTIONS'), self.get('QB_OPT_APPEND'))
1279
1280 for ovmf in self.ovmf_bios:
1281 format = ovmf.rsplit('.', 1)[-1]
1282 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
1283 if self.ovmf_bios:
1284 # OVMF only supports normal VGA, i.e. we need to override a -vga vmware
1285 # that gets added for example for normal qemux86.
1286 self.qemu_opt += ' -vga std'
1287
1288 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001289
Brad Bishop08902b02019-08-20 09:16:51 -04001290 if self.ovmf_secboot_pkkek1:
1291 # Provide the Platform Key and first Key Exchange Key certificate as an
1292 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1293 # with "application prefix" of the EnrollDefaultKeys.efi application
1294 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1295 + self.ovmf_secboot_pkkek1
1296
Andrew Geissler99467da2019-02-25 18:54:23 -06001297 # Append qemuparams to override previous settings
1298 if self.qemuparams:
1299 self.qemu_opt += ' ' + self.qemuparams
1300
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001301 if self.snapshot:
1302 self.qemu_opt += " -snapshot"
1303
Brad Bishop19323692019-04-05 15:28:33 -04001304 if self.serialconsole:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001305 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001306 subprocess.check_call(("stty", "intr", "^]"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001307 logger.info("Interrupt character is '^]'")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001308
1309 first_serial = ""
1310 if not re.search("-nographic", self.qemu_opt):
1311 first_serial = "-serial mon:vc"
1312 # We always want a ttyS1. Since qemu by default adds a serial
1313 # port when nodefaults is not specified, it seems that all that
1314 # would be needed is to make sure a "-serial" is there. However,
1315 # it appears that when "-serial" is specified, it ignores the
1316 # default serial port that is normally added. So here we make
1317 # sure to add two -serial if there are none. And only one if
1318 # there is one -serial already.
1319 serial_num = len(re.findall("-serial", self.qemu_opt))
1320 if serial_num == 0:
1321 self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
1322 elif serial_num == 1:
1323 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1324
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001325 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES),
1326 # if not serial or serialtcp options was specified only ttyS0 is created
1327 # and sysvinit shows an error trying to enable ttyS1:
1328 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1329 serial_num = len(re.findall("-serial", self.qemu_opt))
1330 if serial_num == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001331 if re.search("-nographic", self.qemu_opt) or self.serialstdio:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001332 self.qemu_opt += " -serial mon:stdio -serial null"
1333 else:
1334 self.qemu_opt += " -serial mon:vc -serial null"
1335
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001336 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001337 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001338 if self.kernel:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001339 kernel_opts = "-kernel %s -append '%s %s %s %s'" % (self.kernel, self.kernel_cmdline,
1340 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1341 self.bootparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001342 if self.dtb:
1343 kernel_opts += " -dtb %s" % self.dtb
1344 else:
1345 kernel_opts = ""
1346 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001347 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001348 logger.info('Running %s\n' % cmd)
Brad Bishopf86d0552018-12-04 14:18:15 -08001349 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001350 if self.taplock_descriptor:
1351 pass_fds = [self.taplock_descriptor.fileno()]
1352 if len(self.portlocks):
1353 for descriptor in self.portlocks.values():
1354 pass_fds.append(descriptor.fileno())
Brad Bishopf86d0552018-12-04 14:18:15 -08001355 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
Brad Bishop004d4992018-10-02 23:54:45 +02001356 self.qemupid = process.pid
1357 retcode = process.wait()
1358 if retcode:
1359 if retcode == -signal.SIGTERM:
1360 logger.info("Qemu terminated by SIGTERM")
1361 else:
1362 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001363
1364 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001365 if self.cleaned:
1366 return
1367
1368 # avoid dealing with SIGTERM when cleanup function is running
1369 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1370
1371 logger.info("Cleaning up")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001372 if self.cleantap:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001373 cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
1374 logger.debug('Running %s' % str(cmd))
1375 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001376 self.release_taplock()
1377 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001378
1379 if self.nfs_running:
1380 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001381 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1382 logger.debug('Running %s' % str(cmd))
1383 subprocess.check_call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001384
1385 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001386 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001387
1388 if self.clean_nfs_dir:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001389 logger.info('Removing %s' % self.rootfs)
1390 shutil.rmtree(self.rootfs)
1391 shutil.rmtree('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001392
Brad Bishop004d4992018-10-02 23:54:45 +02001393 self.cleaned = True
1394
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001395 def load_bitbake_env(self, mach=None):
1396 if self.bitbake_e:
1397 return
1398
1399 bitbake = shutil.which('bitbake')
1400 if not bitbake:
1401 return
1402
1403 if not mach:
1404 mach = self.get('MACHINE')
1405
1406 if mach:
1407 cmd = 'MACHINE=%s bitbake -e' % mach
1408 else:
1409 cmd = 'bitbake -e'
1410
1411 logger.info('Running %s...' % cmd)
1412 try:
1413 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
1414 except subprocess.CalledProcessError as err:
1415 self.bitbake_e = ''
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001416 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 -06001417
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001418 def validate_combos(self):
1419 if (self.fstype in self.vmtypes) and self.kernel:
1420 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1421
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001422 @property
1423 def bindir_native(self):
1424 result = self.get('STAGING_BINDIR_NATIVE')
1425 if result and os.path.exists(result):
1426 return result
1427
Brad Bishop977dc1a2019-02-06 16:01:43 -05001428 cmd = ('bitbake', 'qemu-helper-native', '-e')
1429 logger.info('Running %s...' % str(cmd))
1430 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001431
1432 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1433 if match:
1434 result = match.group(1)
1435 if os.path.exists(result):
1436 self.set('STAGING_BINDIR_NATIVE', result)
1437 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001438 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001439 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001440 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001441
1442
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001443def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001444 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001445 print_usage()
1446 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001447 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001448 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001449
1450 def sigterm_handler(signum, frame):
1451 logger.info("SIGTERM received")
1452 os.kill(config.qemupid, signal.SIGTERM)
1453 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001454 # Deliberately ignore the return code of 'tput smam'.
1455 subprocess.call(["tput", "smam"])
Brad Bishop004d4992018-10-02 23:54:45 +02001456 signal.signal(signal.SIGTERM, sigterm_handler)
1457
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001458 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001459 config.read_qemuboot()
1460 config.check_and_set()
1461 # Check whether the combos is valid or not
1462 config.validate_combos()
1463 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001464 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001465 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001466 config.setup_final()
1467 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001468 except RunQemuError as err:
1469 logger.error(err)
1470 return 1
1471 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001472 import traceback
1473 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001474 return 1
1475 finally:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001476 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001477 # Deliberately ignore the return code of 'tput smam'.
1478 subprocess.call(["tput", "smam"])
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001479
1480if __name__ == "__main__":
1481 sys.exit(main())