blob: e9b83737cbfd01178c1150f64f3ca8bb212feafd [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 Bishop19323692019-04-05 15:28:33 -040068 sdl - choose the SDL frontend instead of the Gtk+ default
69 gtk-gl - enable virgl-based GL acceleration using Gtk+ frontend
70 gtk-gl-es - enable virgl-based GL acceleration, using OpenGL ES and Gtk+ frontend
71 egl-headless - enable headless EGL output; use vnc or spice to see it
Patrick Williamsc0f7c042017-02-23 20:41:17 -060072 serial - enable a serial console on /dev/ttyS0
Brad Bishop19323692019-04-05 15:28:33 -040073 serialstdio - enable a serial console on the console (regardless of graphics mode)
Patrick Williamsc0f7c042017-02-23 20:41:17 -060074 slirp - enable user networking, no root privileges is required
75 kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
76 kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050077 publicvnc - enable a VNC server open to all hosts
Patrick Williamsc0f7c042017-02-23 20:41:17 -060078 audio - enable audio
Brad Bishop6e60e8b2018-02-01 10:27:11 -050079 [*/]ovmf* - OVMF firmware file or base name for booting with UEFI
Patrick Williamsc0f7c042017-02-23 20:41:17 -060080 tcpserial=<port> - specify tcp serial port number
Patrick Williamsc0f7c042017-02-23 20:41:17 -060081 qemuparams=<xyz> - specify custom parameters to QEMU
82 bootparams=<xyz> - specify custom kernel parameters during boot
Brad Bishop6e60e8b2018-02-01 10:27:11 -050083 help, -h, --help: print this text
Brad Bishopd7bf8c12018-02-25 22:55:05 -050084 -d, --debug: Enable debug output
85 -q, --quite: Hide most output except error messages
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050086
87Examples:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050088 runqemu
Patrick Williamsc0f7c042017-02-23 20:41:17 -060089 runqemu qemuarm
90 runqemu tmp/deploy/images/qemuarm
Brad Bishop6e60e8b2018-02-01 10:27:11 -050091 runqemu tmp/deploy/images/qemux86/<qemuboot.conf>
Patrick Williamsc0f7c042017-02-23 20:41:17 -060092 runqemu qemux86-64 core-image-sato ext4
93 runqemu qemux86-64 wic-image-minimal wic
94 runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
Brad Bishopd7bf8c12018-02-25 22:55:05 -050095 runqemu qemux86 iso/hddimg/wic.vmdk/wic.qcow2/wic.vdi/ramfs/cpio.gz...
Patrick Williamsc0f7c042017-02-23 20:41:17 -060096 runqemu qemux86 qemuparams="-m 256"
97 runqemu qemux86 bootparams="psplash=false"
Patrick Williamsc0f7c042017-02-23 20:41:17 -060098 runqemu path/to/<image>-<machine>.wic
Brad Bishopd7bf8c12018-02-25 22:55:05 -050099 runqemu path/to/<image>-<machine>.wic.vmdk
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600100""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500101
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600102def check_tun():
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500103 """Check /dev/net/tun"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600104 dev_tun = '/dev/net/tun'
105 if not os.path.exists(dev_tun):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500106 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 -0500107
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600108 if not os.access(dev_tun, os.W_OK):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500109 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 -0500110
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600111def get_first_file(cmds):
112 """Return first file found in wildcard cmds"""
113 for cmd in cmds:
114 all_files = glob.glob(cmd)
115 if all_files:
116 for f in all_files:
117 if not os.path.isdir(f):
118 return f
119 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500120
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600121class BaseConfig(object):
122 def __init__(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500123 # The self.d saved vars from self.set(), part of them are from qemuboot.conf
124 self.d = {'QB_KERNEL_ROOT': '/dev/vda'}
125
126 # Supported env vars, add it here if a var can be got from env,
127 # and don't use os.getenv in the code.
128 self.env_vars = ('MACHINE',
129 'ROOTFS',
130 'KERNEL',
Brad Bishopc68388fc2019-08-26 01:33:31 -0400131 'BIOS',
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 = ''
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'
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('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600484 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600485 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500486 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600487 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
488 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500489 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600490 # Lazy rootfs
491 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500492 elif arg.startswith('ovmf'):
493 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600494 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500495 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600496 if (not unknown_arg) or unknown_arg == arg:
497 unknown_arg = arg
498 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500499 raise RunQemuError("Can't handle two unknown args: %s %s\n"
500 "Try 'runqemu help' on how to use it" % \
501 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600502 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300503 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500504 if self.get('DEPLOY_DIR_IMAGE'):
505 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
506 if unknown_arg == machine:
507 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500508
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600509 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500510
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500511 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512 self.load_bitbake_env()
513 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
514 if s:
515 self.set("DEPLOY_DIR_IMAGE", s.group(1))
516
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600517 def check_kvm(self):
518 """Check kvm and kvm-host"""
519 if not (self.kvm_enabled or self.vhost_enabled):
520 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU'))
521 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500522
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600523 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500524 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500525
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600526 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'))
527 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
528 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
529 dev_kvm = '/dev/kvm'
530 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400531 if self.qemu_system.endswith(('i386', 'x86_64')):
532 with open('/proc/cpuinfo', 'r') as f:
533 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
534 if not kvm_cap:
535 logger.error("You are trying to enable KVM on a cpu without VT support.")
536 logger.error("Remove kvm from the command-line, or refer:")
537 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500538
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600539 if not os.path.exists(dev_kvm):
540 logger.error("Missing KVM device. Have you inserted kvm modules?")
541 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500542 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500543
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600544 if os.access(dev_kvm, os.W_OK|os.R_OK):
545 self.qemu_opt_script += ' -enable-kvm'
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500546 if self.get('MACHINE') == "qemux86":
547 # Workaround for broken APIC window on pre 4.15 host kernels which causes boot hangs
548 # See YOCTO #12301
549 # On 64 bit we use x2apic
550 self.kernel_cmdline_script += " clocksource=kvm-clock hpet=disable noapic nolapic"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600551 else:
552 logger.error("You have no read or write permission on /dev/kvm.")
553 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500554 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500555
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600556 if self.vhost_enabled:
557 if not os.path.exists(dev_vhost):
558 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
559 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500560 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500561
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600562 if not os.access(dev_kvm, os.W_OK|os.R_OK):
563 logger.error("You have no read or write permission on /dev/vhost-net.")
564 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500565 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500566
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600567 def check_fstype(self):
568 """Check and setup FSTYPE"""
569 if not self.fstype:
570 fstype = self.get('QB_DEFAULT_FSTYPE')
571 if fstype:
572 self.fstype = fstype
573 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500574 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500575
Brad Bishop15ae2502019-06-18 21:44:24 -0400576 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
577 wic_fs = False
578 qb_fsinfo = self.get('QB_FSINFO')
579 if qb_fsinfo:
580 qb_fsinfo = qb_fsinfo.split()
581 for fsinfo in qb_fsinfo:
582 try:
583 fstype, fsflag = fsinfo.split(':')
584
585 if fstype == 'wic':
586 if fsflag == 'no-kernel-in-fs':
587 wic_fs = True
588 elif fsflag == 'kernel-in-fs':
589 wic_fs = False
590 else:
591 logger.warn('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
592 continue
593 else:
594 logger.warn('QB_FSINFO is not supported for image type "%s"', fstype)
595 continue
596
597 if fstype in self.fsinfo:
598 self.fsinfo[fstype].append(fsflag)
599 else:
600 self.fsinfo[fstype] = [fsflag]
601 except Exception:
602 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
603
604 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
605 if wic_fs:
606 self.fstypes = self.fstypes + self.wictypes
607 else:
608 self.vmtypes = self.vmtypes + self.wictypes
609
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600610 def check_rootfs(self):
611 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500612
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500613 if self.fstype == "none":
614 return
615
616 if self.get('ROOTFS'):
617 if not self.rootfs:
618 self.rootfs = self.get('ROOTFS')
619 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500620 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500621
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600622 if self.fstype == 'nfs':
623 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500624
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600625 if self.rootfs and not os.path.exists(self.rootfs):
626 # Lazy rootfs
627 self.rootfs = "%s/%s-%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
628 self.rootfs, self.get('MACHINE'),
629 self.fstype)
630 elif not self.rootfs:
631 cmd_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
632 cmd_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
633 cmds = (cmd_name, cmd_link)
634 self.rootfs = get_first_file(cmds)
635 if not self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500636 raise RunQemuError("Failed to find rootfs: %s or %s" % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500637
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600638 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500639 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640
Brad Bishop08902b02019-08-20 09:16:51 -0400641 def setup_pkkek1(self):
642 """
643 Extract from PEM certificate the Platform Key and first Key
644 Exchange Key certificate string. The hypervisor needs to provide
645 it in the Type 11 SMBIOS table
646 """
647 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
648 try:
649 with open(pemcert, 'r') as pemfile:
650 key = pemfile.read().replace('\n', ''). \
651 replace('-----BEGIN CERTIFICATE-----', ''). \
652 replace('-----END CERTIFICATE-----', '')
653 self.ovmf_secboot_pkkek1 = key
654
655 except FileNotFoundError:
656 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
657
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500658 def check_ovmf(self):
659 """Check and set full path for OVMF firmware and variable file(s)."""
660
661 for index, ovmf in enumerate(self.ovmf_bios):
662 if os.path.exists(ovmf):
663 continue
664 for suffix in ('qcow2', 'bin'):
665 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
666 if os.path.exists(path):
667 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400668 if ovmf.endswith('secboot'):
669 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500670 break
671 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500672 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500673
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600674 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400675 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600676 # The vm image doesn't need a kernel
677 if self.fstype in self.vmtypes:
678 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500679
Brad Bishop316dfdd2018-06-25 12:45:53 -0400680 # See if the user supplied a KERNEL option
681 if self.get('KERNEL'):
682 self.kernel = self.get('KERNEL')
683
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500684 # QB_DEFAULT_KERNEL is always a full file path
685 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
686
687 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400688 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500689 return
690
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600691 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
692 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500693 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600694 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
695 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
696 cmds = (kernel_match_name, kernel_match_link, kernel_startswith)
697 self.kernel = get_first_file(cmds)
698 if not self.kernel:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500699 raise RunQemuError('KERNEL not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500700
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600701 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500702 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703
Brad Bishop316dfdd2018-06-25 12:45:53 -0400704 def check_dtb(self):
705 """Check and set dtb"""
706 # Did the user specify a device tree?
707 if self.get('DEVICE_TREE'):
708 self.dtb = self.get('DEVICE_TREE')
709 if not os.path.exists(self.dtb):
710 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
711 return
712
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600713 dtb = self.get('QB_DTB')
714 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400715 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600716 cmd_match = "%s/%s" % (deploy_dir_image, dtb)
717 cmd_startswith = "%s/%s*" % (deploy_dir_image, dtb)
718 cmd_wild = "%s/*.dtb" % deploy_dir_image
719 cmds = (cmd_match, cmd_startswith, cmd_wild)
720 self.dtb = get_first_file(cmds)
721 if not os.path.exists(self.dtb):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500722 raise RunQemuError('DTB not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723
Brad Bishopc68388fc2019-08-26 01:33:31 -0400724 def check_bios(self):
725 """Check and set bios"""
726
727 # See if the user supplied a BIOS option
728 if self.get('BIOS'):
729 self.bios = self.get('BIOS')
730
731 # QB_DEFAULT_BIOS is always a full file path
732 bios_name = os.path.basename(self.get('QB_DEFAULT_BIOS'))
733
734 # The user didn't want a bios to be loaded
735 if (bios_name == "" or bios_name == "none") and not self.bios:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600736 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500737
Brad Bishopc68388fc2019-08-26 01:33:31 -0400738 if not self.bios:
739 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
740 self.bios = "%s/%s" % (deploy_dir_image, bios_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500741
Brad Bishopc68388fc2019-08-26 01:33:31 -0400742 if not self.bios:
743 raise RunQemuError('BIOS not found: %s' % bios_match_name)
744
745 if not os.path.exists(self.bios):
746 raise RunQemuError("KERNEL %s not found" % self.bios)
747
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500748
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600749 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600750 """
751 Both qemu and kernel needs memory settings, so check QB_MEM and set it
752 for both.
753 """
754 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600755 if s:
756 self.set('QB_MEM', '-m %s' % s.group(1))
757 elif not self.get('QB_MEM'):
758 logger.info('QB_MEM is not set, use 512M by default')
759 self.set('QB_MEM', '-m 512')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760
Andrew Geissler99467da2019-02-25 18:54:23 -0600761 # Check and remove M or m suffix
762 qb_mem = self.get('QB_MEM')
763 if qb_mem.endswith('M') or qb_mem.endswith('m'):
764 qb_mem = qb_mem[:-1]
765
766 # Add -m prefix it not present
767 if not qb_mem.startswith('-m'):
768 qb_mem = '-m %s' % qb_mem
769
770 self.set('QB_MEM', qb_mem)
771
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800772 mach = self.get('MACHINE')
773 if not mach.startswith('qemumips'):
774 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
775
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600776 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500777
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600778 def check_tcpserial(self):
779 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400780 ports = self.tcpserial_portnum.split(':')
781 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600782 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400783 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600784 else:
Brad Bishop15ae2502019-06-18 21:44:24 -0400785 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
786
787 if len(ports) > 1:
788 for port in ports[1:]:
789 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500790
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600791 def check_and_set(self):
792 """Check configs sanity and set when needed"""
793 self.validate_paths()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500794 if not self.slirp_enabled:
795 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600796 # Check audio
797 if self.audio_enabled:
798 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500799 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600800 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800801 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600802 else:
803 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
804 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
805 else:
806 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807
Brad Bishop15ae2502019-06-18 21:44:24 -0400808 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600809 self.check_kvm()
810 self.check_fstype()
811 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500812 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600813 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400814 self.check_dtb()
Brad Bishopc68388fc2019-08-26 01:33:31 -0400815 self.check_bios()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600816 self.check_mem()
817 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500818
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600819 def read_qemuboot(self):
820 if not self.qemuboot:
821 if self.get('DEPLOY_DIR_IMAGE'):
822 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600823 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800824 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600825 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500826
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600827 if self.rootfs and not os.path.exists(self.rootfs):
828 # Lazy rootfs
829 machine = self.get('MACHINE')
830 if not machine:
831 machine = os.path.basename(deploy_dir_image)
832 self.qemuboot = "%s/%s-%s.qemuboot.conf" % (deploy_dir_image,
833 self.rootfs, machine)
834 else:
835 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500836 logger.debug('Running %s...' % cmd)
837 try:
838 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
839 except subprocess.CalledProcessError as err:
840 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600841 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500842 for qb in qbs.split():
843 # Don't use initramfs when other choices unless fstype is ramfs
844 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
845 continue
846 self.qemuboot = qb
847 break
848 if not self.qemuboot:
849 # Use the first one when no choice
850 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600851 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500852
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600853 if not self.qemuboot:
854 # If we haven't found a .qemuboot.conf at this point it probably
855 # doesn't exist, continue without
856 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500857
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600858 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500859 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 -0500860
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500861 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500862
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600863 cf = configparser.ConfigParser()
864 cf.read(self.qemuboot)
865 for k, v in cf.items('config_bsp'):
866 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500867 if v.startswith("../"):
868 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
869 elif v == ".":
870 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600871 self.set(k_upper, v)
872
873 def validate_paths(self):
874 """Ensure all relevant path variables are set"""
875 # When we're started with a *.qemuboot.conf arg assume that image
876 # artefacts are relative to that file, rather than in whatever
877 # directory DEPLOY_DIR_IMAGE in the conf file points to.
878 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500879 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
880 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600881 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
882 self.set('DEPLOY_DIR_IMAGE', imgdir)
883
884 # If the STAGING_*_NATIVE directories from the config file don't exist
885 # and we're in a sourced OE build directory try to extract the paths
886 # from `bitbake -e`
887 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
888 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
889
890 if not havenative:
891 if not self.bitbake_e:
892 self.load_bitbake_env()
893
894 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500895 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600896 for nv in native_vars:
897 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
898 if s and s.group(1) != self.get(nv):
899 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
900 self.set(nv, s.group(1))
901 else:
902 # when we're invoked from a running bitbake instance we won't
903 # be able to call `bitbake -e`, then try:
904 # - get OE_TMPDIR from environment and guess paths based on it
905 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500906 tmpdir = self.get('OE_TMPDIR')
907 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600908 if tmpdir:
909 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
910 hostos, _, _, _, machine = os.uname()
911 buildsys = '%s-%s' % (machine, hostos.lower())
912 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
913 self.set('STAGING_DIR_NATIVE', staging_dir_native)
914 elif oecore_native_sysroot:
915 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
916 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
917 if self.get('STAGING_DIR_NATIVE'):
918 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
919 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
920 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
921 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
922
923 def print_config(self):
924 logger.info('Continuing with the following parameters:\n')
925 if not self.fstype in self.vmtypes:
926 print('KERNEL: [%s]' % self.kernel)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400927 if self.bios:
928 print('BIOS: [%s]' % self.bios)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600929 if self.dtb:
930 print('DTB: [%s]' % self.dtb)
931 print('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400932 try:
933 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
934 except KeyError:
935 fstype_flags = ''
936 print('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600937 if self.fstype == 'nfs':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500938 print('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600939 else:
940 print('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500941 if self.ovmf_bios:
942 print('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -0400943 if (self.ovmf_secboot_pkkek1):
944 print('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600945 print('CONFFILE: [%s]' % self.qemuboot)
946 print('')
947
948 def setup_nfs(self):
949 if not self.nfs_server:
950 if self.slirp_enabled:
951 self.nfs_server = '10.0.2.2'
952 else:
953 self.nfs_server = '192.168.7.1'
954
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500955 # Figure out a new nfs_instance to allow multiple qemus running.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500956 ps = subprocess.check_output(("ps", "auxww")).decode('utf-8')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500957 pattern = '/bin/unfsd .* -i .*\.pid -e .*/exports([0-9]+) '
958 all_instances = re.findall(pattern, ps, re.M)
959 if all_instances:
960 all_instances.sort(key=int)
961 self.nfs_instance = int(all_instances.pop()) + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600962
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500963 nfsd_port = 3049 + 2 * self.nfs_instance
964 mountd_port = 3048 + 2 * self.nfs_instance
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600965
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500966 # Export vars for runqemu-export-rootfs
967 export_dict = {
968 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500969 'NFSD_PORT': nfsd_port,
970 'MOUNTD_PORT': mountd_port,
971 }
972 for k, v in export_dict.items():
973 # Use '%s' since they are integers
974 os.putenv(k, '%s' % v)
975
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500976 self.unfs_opts="nfsvers=3,port=%s,udp,mountport=%s" % (nfsd_port, mountd_port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600977
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500978 # Extract .tar.bz2 or .tar.bz if no nfs dir
979 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600980 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
981 dest = "%s-nfsroot" % src_prefix
982 if os.path.exists('%s.pseudo_state' % dest):
983 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500984 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600985 else:
986 src = ""
987 src1 = '%s.tar.bz2' % src_prefix
988 src2 = '%s.tar.gz' % src_prefix
989 if os.path.exists(src1):
990 src = src1
991 elif os.path.exists(src2):
992 src = src2
993 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500994 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 -0600995 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -0500996 cmd = ('runqemu-extract-sdk', src, dest)
997 logger.info('Running %s...' % str(cmd))
998 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500999 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001000 self.clean_nfs_dir = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001001 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001002
1003 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001004 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1005 logger.info('Running %s...' % str(cmd))
1006 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001007 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001008
1009 self.nfs_running = True
1010
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001011 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001012 """Setup user networking"""
1013
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001014 if self.fstype == 'nfs':
1015 self.setup_nfs()
1016 self.kernel_cmdline_script += ' ip=dhcp'
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001017 # Port mapping
1018 hostfwd = ",hostfwd=tcp::2222-:22,hostfwd=tcp::2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001019 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001020 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1021 # Figure out the port
1022 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1023 ports = [int(i) for i in ports]
1024 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001025
1026 lockdir = "/tmp/qemu-port-locks"
1027 if not os.path.exists(lockdir):
1028 # There might be a race issue when multi runqemu processess are
1029 # running at the same time.
1030 try:
1031 os.mkdir(lockdir)
1032 os.chmod(lockdir, 0o777)
1033 except FileExistsError:
1034 pass
1035
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001036 # Find a free port to avoid conflicts
1037 for p in ports[:]:
1038 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001039 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001040 p_new += 1
1041 mac += 1
1042 while p_new in ports:
1043 p_new += 1
1044 mac += 1
1045 if p != p_new:
1046 ports.append(p_new)
1047 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1048 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1049 mac = "%s%02x" % (self.mac_slirp, mac)
1050 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1051 # Print out port foward
1052 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1053 if hostfwd:
1054 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001055
1056 def setup_tap(self):
1057 """Setup tap"""
1058
1059 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1060 # devices, indicating that the user should not bring up new ones using
1061 # sudo.
1062 nosudo_flag = '/etc/runqemu-nosudo'
1063 self.qemuifup = shutil.which('runqemu-ifup')
1064 self.qemuifdown = shutil.which('runqemu-ifdown')
1065 ip = shutil.which('ip')
1066 lockdir = "/tmp/qemu-tap-locks"
1067
1068 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001069 logger.error("runqemu-ifup: %s" % self.qemuifup)
1070 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1071 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001072 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1073
1074 if not os.path.exists(lockdir):
1075 # There might be a race issue when multi runqemu processess are
1076 # running at the same time.
1077 try:
1078 os.mkdir(lockdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001079 os.chmod(lockdir, 0o777)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001080 except FileExistsError:
1081 pass
1082
Brad Bishop977dc1a2019-02-06 16:01:43 -05001083 cmd = (ip, 'link')
1084 logger.debug('Running %s...' % str(cmd))
1085 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001086 # Matches line like: 6: tap0: <foo>
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001087 possibles = re.findall('^[0-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001088 tap = ""
1089 for p in possibles:
1090 lockfile = os.path.join(lockdir, p)
1091 if os.path.exists('%s.skip' % lockfile):
1092 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1093 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001094 self.taplock = lockfile + '.lock'
1095 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001096 tap = p
1097 logger.info("Using preconfigured tap device %s" % tap)
1098 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1099 break
1100
1101 if not tap:
1102 if os.path.exists(nosudo_flag):
1103 logger.error("Error: There are no available tap devices to use for networking,")
1104 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001105 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001106
1107 gid = os.getgid()
1108 uid = os.getuid()
1109 logger.info("Setting up tap interface under sudo")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001110 cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
1111 tap = subprocess.check_output(cmd).decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001112 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001113 self.taplock = lockfile + '.lock'
1114 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001115 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001116 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001117
1118 if not tap:
1119 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
1120 return 1
1121 self.tap = tap
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001122 tapnum = int(tap[3:])
1123 gateway = tapnum * 2 + 1
1124 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001125 if self.fstype == 'nfs':
1126 self.setup_nfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001127 netconf = "192.168.7.%s::192.168.7.%s:255.255.255.0" % (client, gateway)
1128 logger.info("Network configuration: %s", netconf)
1129 self.kernel_cmdline_script += " ip=%s" % netconf
1130 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001131 qb_tap_opt = self.get('QB_TAP_OPT')
1132 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001133 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001134 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001135 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001136
1137 if self.vhost_enabled:
1138 qemu_tap_opt += ',vhost=on'
1139
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001140 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001141
1142 def setup_network(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001143 if self.get('QB_NET') == 'none':
1144 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001145 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001146 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001147 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001148 if self.slirp_enabled:
1149 self.setup_slirp()
1150 else:
1151 self.setup_tap()
1152
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001153 def setup_rootfs(self):
1154 if self.get('QB_ROOTFS') == 'none':
1155 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001156 if 'wic.' in self.fstype:
1157 self.fstype = self.fstype[4:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001158 rootfs_format = self.fstype if self.fstype in ('vmdk', 'qcow2', 'vdi') else 'raw'
1159
1160 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1161 if qb_rootfs_opt:
1162 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1163 else:
1164 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1165
1166 if self.fstype in ('cpio.gz', 'cpio'):
1167 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1168 self.rootfs_options = '-initrd %s' % self.rootfs
1169 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001170 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001171 if self.fstype in self.vmtypes:
1172 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001173 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001174 elif self.get('QB_DRIVE_TYPE'):
1175 drive_type = self.get('QB_DRIVE_TYPE')
1176 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001177 logger.info('Using scsi drive')
1178 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' \
1179 % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001180 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001181 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001182 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001183 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001184 # virtio might have been selected explicitly (just use it), or
1185 # is used as fallback (then warn about that).
1186 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001187 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1188 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1189 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001190 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001191
1192 # All branches above set vm_drive.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001193 self.rootfs_options = '%s -no-reboot' % vm_drive
1194 self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('QB_KERNEL_ROOT'))
1195
1196 if self.fstype == 'nfs':
1197 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001198 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 -06001199 self.kernel_cmdline = 'root=%s rw highres=off' % k_root
1200
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001201 if self.fstype == 'none':
1202 self.rootfs_options = ''
1203
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001204 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1205
1206 def guess_qb_system(self):
1207 """attempt to determine the appropriate qemu-system binary"""
1208 mach = self.get('MACHINE')
1209 if not mach:
1210 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
1211 if self.rootfs:
1212 match = re.match(search, self.rootfs)
1213 if match:
1214 mach = match.group(1)
1215 elif self.kernel:
1216 match = re.match(search, self.kernel)
1217 if match:
1218 mach = match.group(1)
1219
1220 if not mach:
1221 return None
1222
1223 if mach == 'qemuarm':
1224 qbsys = 'arm'
1225 elif mach == 'qemuarm64':
1226 qbsys = 'aarch64'
1227 elif mach == 'qemux86':
1228 qbsys = 'i386'
1229 elif mach == 'qemux86-64':
1230 qbsys = 'x86_64'
1231 elif mach == 'qemuppc':
1232 qbsys = 'ppc'
1233 elif mach == 'qemumips':
1234 qbsys = 'mips'
1235 elif mach == 'qemumips64':
1236 qbsys = 'mips64'
1237 elif mach == 'qemumipsel':
1238 qbsys = 'mipsel'
1239 elif mach == 'qemumips64el':
1240 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001241 elif mach == 'qemuriscv64':
1242 qbsys = 'riscv64'
1243 elif mach == 'qemuriscv32':
1244 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001245 else:
1246 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1247 logger.error("As %s is not among valid QEMU machines such as," % mach)
1248 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1249 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001250
1251 return 'qemu-system-%s' % qbsys
1252
Brad Bishop15ae2502019-06-18 21:44:24 -04001253 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001254 qemu_system = self.get('QB_SYSTEM_NAME')
1255 if not qemu_system:
1256 qemu_system = self.guess_qb_system()
1257 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001258 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001259 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001260
Brad Bishop15ae2502019-06-18 21:44:24 -04001261 def setup_final(self):
1262 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001263
1264 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1265 # find QEMU in sysroot, it needs to use host's qemu.
1266 if not os.path.exists(qemu_bin):
1267 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1268 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001269 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001270 logger.info("Trying: %s" % qemu_bin_tmp)
1271 if os.path.exists(qemu_bin_tmp):
1272 qemu_bin = qemu_bin_tmp
1273 if not os.path.isabs(qemu_bin):
1274 qemu_bin = os.path.abspath(qemu_bin)
1275 logger.info("Using host's QEMU: %s" % qemu_bin)
1276 break
1277
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001278 if not os.access(qemu_bin, os.X_OK):
1279 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
1280
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001281 self.qemu_opt = "%s %s %s %s" % (qemu_bin, self.get('NETWORK_CMD'), self.get('ROOTFS_OPTIONS'), self.get('QB_OPT_APPEND'))
1282
1283 for ovmf in self.ovmf_bios:
1284 format = ovmf.rsplit('.', 1)[-1]
1285 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
1286 if self.ovmf_bios:
1287 # OVMF only supports normal VGA, i.e. we need to override a -vga vmware
1288 # that gets added for example for normal qemux86.
1289 self.qemu_opt += ' -vga std'
1290
1291 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001292
Brad Bishop08902b02019-08-20 09:16:51 -04001293 if self.ovmf_secboot_pkkek1:
1294 # Provide the Platform Key and first Key Exchange Key certificate as an
1295 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1296 # with "application prefix" of the EnrollDefaultKeys.efi application
1297 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1298 + self.ovmf_secboot_pkkek1
1299
Andrew Geissler99467da2019-02-25 18:54:23 -06001300 # Append qemuparams to override previous settings
1301 if self.qemuparams:
1302 self.qemu_opt += ' ' + self.qemuparams
1303
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001304 if self.snapshot:
1305 self.qemu_opt += " -snapshot"
1306
Brad Bishop19323692019-04-05 15:28:33 -04001307 if self.serialconsole:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001308 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001309 subprocess.check_call(("stty", "intr", "^]"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001310 logger.info("Interrupt character is '^]'")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001311
1312 first_serial = ""
1313 if not re.search("-nographic", self.qemu_opt):
1314 first_serial = "-serial mon:vc"
1315 # We always want a ttyS1. Since qemu by default adds a serial
1316 # port when nodefaults is not specified, it seems that all that
1317 # would be needed is to make sure a "-serial" is there. However,
1318 # it appears that when "-serial" is specified, it ignores the
1319 # default serial port that is normally added. So here we make
1320 # sure to add two -serial if there are none. And only one if
1321 # there is one -serial already.
1322 serial_num = len(re.findall("-serial", self.qemu_opt))
1323 if serial_num == 0:
1324 self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
1325 elif serial_num == 1:
1326 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1327
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001328 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES),
1329 # if not serial or serialtcp options was specified only ttyS0 is created
1330 # and sysvinit shows an error trying to enable ttyS1:
1331 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1332 serial_num = len(re.findall("-serial", self.qemu_opt))
1333 if serial_num == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001334 if re.search("-nographic", self.qemu_opt) or self.serialstdio:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001335 self.qemu_opt += " -serial mon:stdio -serial null"
1336 else:
1337 self.qemu_opt += " -serial mon:vc -serial null"
1338
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001339 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001340 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001341 if self.kernel:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001342 kernel_opts = "-kernel %s -append '%s %s %s %s'" % (self.kernel, self.kernel_cmdline,
1343 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1344 self.bootparams)
Brad Bishopc68388fc2019-08-26 01:33:31 -04001345 if self.bios:
1346 kernel_opts += " -bios %s" % self.bios
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001347 if self.dtb:
1348 kernel_opts += " -dtb %s" % self.dtb
1349 else:
1350 kernel_opts = ""
1351 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001352 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001353 logger.info('Running %s\n' % cmd)
Brad Bishopf86d0552018-12-04 14:18:15 -08001354 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001355 if self.taplock_descriptor:
1356 pass_fds = [self.taplock_descriptor.fileno()]
1357 if len(self.portlocks):
1358 for descriptor in self.portlocks.values():
1359 pass_fds.append(descriptor.fileno())
Brad Bishopf86d0552018-12-04 14:18:15 -08001360 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
Brad Bishop004d4992018-10-02 23:54:45 +02001361 self.qemupid = process.pid
1362 retcode = process.wait()
1363 if retcode:
1364 if retcode == -signal.SIGTERM:
1365 logger.info("Qemu terminated by SIGTERM")
1366 else:
1367 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001368
1369 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001370 if self.cleaned:
1371 return
1372
1373 # avoid dealing with SIGTERM when cleanup function is running
1374 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1375
1376 logger.info("Cleaning up")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001377 if self.cleantap:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001378 cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
1379 logger.debug('Running %s' % str(cmd))
1380 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001381 self.release_taplock()
1382 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001383
1384 if self.nfs_running:
1385 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001386 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1387 logger.debug('Running %s' % str(cmd))
1388 subprocess.check_call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001389
1390 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001391 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001392
1393 if self.clean_nfs_dir:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001394 logger.info('Removing %s' % self.rootfs)
1395 shutil.rmtree(self.rootfs)
1396 shutil.rmtree('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001397
Brad Bishop004d4992018-10-02 23:54:45 +02001398 self.cleaned = True
1399
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001400 def load_bitbake_env(self, mach=None):
1401 if self.bitbake_e:
1402 return
1403
1404 bitbake = shutil.which('bitbake')
1405 if not bitbake:
1406 return
1407
1408 if not mach:
1409 mach = self.get('MACHINE')
1410
1411 if mach:
1412 cmd = 'MACHINE=%s bitbake -e' % mach
1413 else:
1414 cmd = 'bitbake -e'
1415
1416 logger.info('Running %s...' % cmd)
1417 try:
1418 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
1419 except subprocess.CalledProcessError as err:
1420 self.bitbake_e = ''
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001421 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 -06001422
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001423 def validate_combos(self):
1424 if (self.fstype in self.vmtypes) and self.kernel:
1425 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1426
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001427 @property
1428 def bindir_native(self):
1429 result = self.get('STAGING_BINDIR_NATIVE')
1430 if result and os.path.exists(result):
1431 return result
1432
Brad Bishop977dc1a2019-02-06 16:01:43 -05001433 cmd = ('bitbake', 'qemu-helper-native', '-e')
1434 logger.info('Running %s...' % str(cmd))
1435 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001436
1437 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1438 if match:
1439 result = match.group(1)
1440 if os.path.exists(result):
1441 self.set('STAGING_BINDIR_NATIVE', result)
1442 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001443 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001444 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001445 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001446
1447
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001448def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001449 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001450 print_usage()
1451 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001452 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001453 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001454
1455 def sigterm_handler(signum, frame):
1456 logger.info("SIGTERM received")
1457 os.kill(config.qemupid, signal.SIGTERM)
1458 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001459 # Deliberately ignore the return code of 'tput smam'.
1460 subprocess.call(["tput", "smam"])
Brad Bishop004d4992018-10-02 23:54:45 +02001461 signal.signal(signal.SIGTERM, sigterm_handler)
1462
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001463 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001464 config.read_qemuboot()
1465 config.check_and_set()
1466 # Check whether the combos is valid or not
1467 config.validate_combos()
1468 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001469 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001470 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001471 config.setup_final()
1472 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001473 except RunQemuError as err:
1474 logger.error(err)
1475 return 1
1476 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001477 import traceback
1478 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001479 return 1
1480 finally:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001481 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001482 # Deliberately ignore the return code of 'tput smam'.
1483 subprocess.call(["tput", "smam"])
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001484
1485if __name__ == "__main__":
1486 sys.exit(main())