blob: 4415e9b69f888dfd19d0fc509d0a57da8466f129 [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
Brad Bishop79641f22019-09-10 07:20:22 -040085 -q, --quiet: 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.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500148 self.ovmf_bios = []
Brad Bishop08902b02019-08-20 09:16:51 -0400149 # When enrolling default Secure Boot keys, the hypervisor
150 # must provide the Platform Key and the first Key Exchange Key
151 # certificate in the Type 11 SMBIOS table.
152 self.ovmf_secboot_pkkek1 = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600153 self.qemuboot = ''
154 self.qbconfload = False
155 self.kernel = ''
Brad Bishopc68388fc2019-08-26 01:33:31 -0400156 self.bios = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600157 self.kernel_cmdline = ''
158 self.kernel_cmdline_script = ''
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500159 self.bootparams = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600160 self.dtb = ''
161 self.fstype = ''
162 self.kvm_enabled = False
163 self.vhost_enabled = False
164 self.slirp_enabled = False
165 self.nfs_instance = 0
166 self.nfs_running = False
Brad Bishop19323692019-04-05 15:28:33 -0400167 self.serialconsole = False
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600168 self.serialstdio = False
169 self.cleantap = False
170 self.saved_stty = ''
171 self.audio_enabled = False
172 self.tcpserial_portnum = ''
Brad Bishop08902b02019-08-20 09:16:51 -0400173 self.taplock = ''
174 self.taplock_descriptor = None
175 self.portlocks = {}
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600176 self.bitbake_e = ''
177 self.snapshot = False
Brad Bishop15ae2502019-06-18 21:44:24 -0400178 self.wictypes = ('wic', 'wic.vmdk', 'wic.qcow2', 'wic.vdi')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500179 self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs',
180 'cpio.gz', 'cpio', 'ramfs', 'tar.bz2', 'tar.gz')
Brad Bishop08902b02019-08-20 09:16:51 -0400181 self.vmtypes = ('hddimg', 'iso')
Brad Bishop15ae2502019-06-18 21:44:24 -0400182 self.fsinfo = {}
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500183 self.network_device = "-device e1000,netdev=net0,mac=@MAC@"
184 # Use different mac section for tap and slirp to avoid
185 # conflicts, e.g., when one is running with tap, the other is
186 # running with slirp.
187 # The last section is dynamic, which is for avoiding conflicts,
188 # when multiple qemus are running, e.g., when multiple tap or
189 # slirp qemus are running.
190 self.mac_tap = "52:54:00:12:34:"
191 self.mac_slirp = "52:54:00:12:35:"
Brad Bishop004d4992018-10-02 23:54:45 +0200192 # pid of the actual qemu process
193 self.qemupid = None
194 # avoid cleanup twice
195 self.cleaned = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500196
Brad Bishop08902b02019-08-20 09:16:51 -0400197 def acquire_taplock(self, error=True):
198 logger.debug("Acquiring lockfile %s..." % self.taplock)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600199 try:
Brad Bishop08902b02019-08-20 09:16:51 -0400200 self.taplock_descriptor = open(self.taplock, 'w')
201 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_EX|fcntl.LOCK_NB)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600202 except Exception as e:
Brad Bishop08902b02019-08-20 09:16:51 -0400203 msg = "Acquiring lockfile %s failed: %s" % (self.taplock, e)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500204 if error:
205 logger.error(msg)
206 else:
207 logger.info(msg)
Brad Bishop08902b02019-08-20 09:16:51 -0400208 if self.taplock_descriptor:
209 self.taplock_descriptor.close()
210 self.taplock_descriptor = None
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600211 return False
212 return True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500213
Brad Bishop08902b02019-08-20 09:16:51 -0400214 def release_taplock(self):
215 if self.taplock_descriptor:
Brad Bishopf86d0552018-12-04 14:18:15 -0800216 logger.debug("Releasing lockfile for tap device '%s'" % self.tap)
Brad Bishop08902b02019-08-20 09:16:51 -0400217 fcntl.flock(self.taplock_descriptor, fcntl.LOCK_UN)
218 self.taplock_descriptor.close()
219 os.remove(self.taplock)
220 self.taplock_descriptor = None
221
222 def check_free_port(self, host, port, lockdir):
223 """ Check whether the port is free or not """
224 import socket
225 from contextlib import closing
226
227 lockfile = os.path.join(lockdir, str(port) + '.lock')
228 if self.acquire_portlock(lockfile):
229 with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock:
230 if sock.connect_ex((host, port)) == 0:
231 # Port is open, so not free
232 self.release_portlock(lockfile)
233 return False
234 else:
235 # Port is not open, so free
236 return True
237 else:
238 return False
239
240 def acquire_portlock(self, lockfile):
241 logger.debug("Acquiring lockfile %s..." % lockfile)
242 try:
243 portlock_descriptor = open(lockfile, 'w')
244 self.portlocks.update({lockfile: portlock_descriptor})
245 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_EX|fcntl.LOCK_NB)
246 except Exception as e:
247 msg = "Acquiring lockfile %s failed: %s" % (lockfile, e)
248 logger.info(msg)
249 if lockfile in self.portlocks.keys() and self.portlocks[lockfile]:
250 self.portlocks[lockfile].close()
251 del self.portlocks[lockfile]
252 return False
253 return True
254
255 def release_portlock(self, lockfile=None):
256 if lockfile != None:
257 logger.debug("Releasing lockfile '%s'" % lockfile)
258 fcntl.flock(self.portlocks[lockfile], fcntl.LOCK_UN)
259 self.portlocks[lockfile].close()
260 os.remove(lockfile)
261 del self.portlocks[lockfile]
262 elif len(self.portlocks):
263 for lockfile, descriptor in self.portlocks.items():
264 logger.debug("Releasing lockfile '%s'" % lockfile)
265 fcntl.flock(descriptor, fcntl.LOCK_UN)
266 descriptor.close()
267 os.remove(lockfile)
268 self.portlocks = {}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500269
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600270 def get(self, key):
271 if key in self.d:
272 return self.d.get(key)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500273 elif os.getenv(key):
274 return os.getenv(key)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600275 else:
276 return ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600278 def set(self, key, value):
279 self.d[key] = value
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600281 def is_deploy_dir_image(self, p):
282 if os.path.isdir(p):
283 if not re.search('.qemuboot.conf$', '\n'.join(os.listdir(p)), re.M):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500284 logger.debug("Can't find required *.qemuboot.conf in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600285 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500286 if not any(map(lambda name: '-image-' in name, os.listdir(p))):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500287 logger.debug("Can't find *-image-* in %s" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600288 return False
289 return True
290 else:
291 return False
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500292
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600293 def check_arg_fstype(self, fst):
294 """Check and set FSTYPE"""
Brad Bishop15ae2502019-06-18 21:44:24 -0400295 if fst not in self.fstypes + self.vmtypes + self.wictypes:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800296 logger.warning("Maybe unsupported FSTYPE: %s" % fst)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 if not self.fstype or self.fstype == fst:
298 if fst == 'ramfs':
299 fst = 'cpio.gz'
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500300 if fst in ('tar.bz2', 'tar.gz'):
301 fst = 'nfs'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600302 self.fstype = fst
303 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500304 raise RunQemuError("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500305
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600306 def set_machine_deploy_dir(self, machine, deploy_dir_image):
307 """Set MACHINE and DEPLOY_DIR_IMAGE"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500308 logger.debug('MACHINE: %s' % machine)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600309 self.set("MACHINE", machine)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500310 logger.debug('DEPLOY_DIR_IMAGE: %s' % deploy_dir_image)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600311 self.set("DEPLOY_DIR_IMAGE", deploy_dir_image)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500312
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600313 def check_arg_nfs(self, p):
314 if os.path.isdir(p):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500315 self.rootfs = p
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600316 else:
317 m = re.match('(.*):(.*)', p)
318 self.nfs_server = m.group(1)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500319 self.rootfs = m.group(2)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600320 self.check_arg_fstype('nfs')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500321
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600322 def check_arg_path(self, p):
323 """
324 - Check whether it is <image>.qemuboot.conf or contains <image>.qemuboot.conf
325 - Check whether is a kernel file
326 - Check whether is a image file
327 - Check whether it is a nfs dir
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500328 - Check whether it is a OVMF flash file
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600329 """
330 if p.endswith('.qemuboot.conf'):
331 self.qemuboot = p
332 self.qbconfload = True
333 elif re.search('\.bin$', p) or re.search('bzImage', p) or \
334 re.search('zImage', p) or re.search('vmlinux', p) or \
335 re.search('fitImage', p) or re.search('uImage', p):
336 self.kernel = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500337 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 -0600338 self.rootfs = p
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500339 # Check filename against self.fstypes can hanlde <file>.cpio.gz,
340 # otherwise, its type would be "gz", which is incorrect.
341 fst = ""
342 for t in self.fstypes:
343 if p.endswith(t):
344 fst = t
345 break
346 if not fst:
347 m = re.search('.*\.(.*)$', self.rootfs)
348 if m:
349 fst = m.group(1)
350 if fst:
351 self.check_arg_fstype(fst)
352 qb = re.sub('\.' + fst + "$", '', self.rootfs)
353 qb = '%s%s' % (re.sub('\.rootfs$', '', qb), '.qemuboot.conf')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600354 if os.path.exists(qb):
355 self.qemuboot = qb
356 self.qbconfload = True
357 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800358 logger.warning("%s doesn't exist" % qb)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600359 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500360 raise RunQemuError("Can't find FSTYPE from: %s" % p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500361
362 elif os.path.isdir(p) or re.search(':', p) and re.search('/', p):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600363 if self.is_deploy_dir_image(p):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500364 logger.debug('DEPLOY_DIR_IMAGE: %s' % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600365 self.set("DEPLOY_DIR_IMAGE", p)
366 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500367 logger.debug("Assuming %s is an nfs rootfs" % p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600368 self.check_arg_nfs(p)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500369 elif os.path.basename(p).startswith('ovmf'):
370 self.ovmf_bios.append(p)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600371 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500372 raise RunQemuError("Unknown path arg %s" % p)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500373
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600374 def check_arg_machine(self, arg):
375 """Check whether it is a machine"""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500376 if self.get('MACHINE') == arg:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600377 return
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500378 elif self.get('MACHINE') and self.get('MACHINE') != arg:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500379 raise RunQemuError("Maybe conflicted MACHINE: %s vs %s" % (self.get('MACHINE'), arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500380 elif re.search('/', arg):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500381 raise RunQemuError("Unknown arg: %s" % arg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500382
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500383 logger.debug('Assuming MACHINE = %s' % arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500384
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600385 # if we're running under testimage, or similarly as a child
386 # of an existing bitbake invocation, we can't invoke bitbake
387 # to validate the MACHINE setting and must assume it's correct...
388 # FIXME: testimage.bbclass exports these two variables into env,
389 # are there other scenarios in which we need to support being
390 # invoked by bitbake?
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500391 deploy = self.get('DEPLOY_DIR_IMAGE')
392 bbchild = deploy and self.get('OE_TMPDIR')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600393 if bbchild:
394 self.set_machine_deploy_dir(arg, deploy)
395 return
396 # also check whether we're running under a sourced toolchain
397 # environment file
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500398 if self.get('OECORE_NATIVE_SYSROOT'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600399 self.set("MACHINE", arg)
400 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500401
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600402 cmd = 'MACHINE=%s bitbake -e' % arg
403 logger.info('Running %s...' % cmd)
Brad Bishop977dc1a2019-02-06 16:01:43 -0500404 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600405 # bitbake -e doesn't report invalid MACHINE as an error, so
406 # let's check DEPLOY_DIR_IMAGE to make sure that it is a valid
407 # MACHINE.
408 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
409 if s:
410 deploy_dir_image = s.group(1)
411 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500412 raise RunQemuError("bitbake -e %s" % self.bitbake_e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600413 if self.is_deploy_dir_image(deploy_dir_image):
414 self.set_machine_deploy_dir(arg, deploy_dir_image)
415 else:
416 logger.error("%s not a directory valid DEPLOY_DIR_IMAGE" % deploy_dir_image)
417 self.set("MACHINE", arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500418
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600419 def check_args(self):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500420 for debug in ("-d", "--debug"):
421 if debug in sys.argv:
422 logger.setLevel(logging.DEBUG)
423 sys.argv.remove(debug)
424
425 for quiet in ("-q", "--quiet"):
426 if quiet in sys.argv:
427 logger.setLevel(logging.ERROR)
428 sys.argv.remove(quiet)
429
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600430 unknown_arg = ""
431 for arg in sys.argv[1:]:
Brad Bishop15ae2502019-06-18 21:44:24 -0400432 if arg in self.fstypes + self.vmtypes + self.wictypes:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600433 self.check_arg_fstype(arg)
434 elif arg == 'nographic':
435 self.qemu_opt_script += ' -nographic'
436 self.kernel_cmdline_script += ' console=ttyS0'
Brad Bishop19323692019-04-05 15:28:33 -0400437 elif arg == 'sdl':
438 self.qemu_opt_script += ' -display sdl'
439 elif arg == 'gtk-gl':
440 self.qemu_opt_script += ' -vga virtio -display gtk,gl=on'
441 elif arg == 'gtk-gl-es':
442 self.qemu_opt_script += ' -vga virtio -display gtk,gl=es'
443 elif arg == 'egl-headless':
444 self.qemu_opt_script += ' -vga virtio -display egl-headless'
445 # As runqemu can be run within bitbake (when using testimage, for example),
446 # we need to ensure that we run host pkg-config, and that it does not
447 # get mis-directed to native build paths set by bitbake.
448 try:
449 del os.environ['PKG_CONFIG_PATH']
450 del os.environ['PKG_CONFIG_DIR']
451 del os.environ['PKG_CONFIG_LIBDIR']
452 except KeyError:
453 pass
454 try:
455 dripath = subprocess.check_output("PATH=/bin:/usr/bin:$PATH pkg-config --variable=dridriverdir dri", shell=True)
456 except subprocess.CalledProcessError as e:
457 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.")
458 os.environ['LIBGL_DRIVERS_PATH'] = dripath.decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600459 elif arg == 'serial':
460 self.kernel_cmdline_script += ' console=ttyS0'
Brad Bishop19323692019-04-05 15:28:33 -0400461 self.serialconsole = True
462 elif arg == "serialstdio":
463 self.kernel_cmdline_script += ' console=ttyS0'
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600464 self.serialstdio = True
465 elif arg == 'audio':
466 logger.info("Enabling audio in qemu")
467 logger.info("Please install sound drivers in linux host")
468 self.audio_enabled = True
469 elif arg == 'kvm':
470 self.kvm_enabled = True
471 elif arg == 'kvm-vhost':
472 self.vhost_enabled = True
473 elif arg == 'slirp':
474 self.slirp_enabled = True
475 elif arg == 'snapshot':
476 self.snapshot = True
477 elif arg == 'publicvnc':
478 self.qemu_opt_script += ' -vnc :0'
479 elif arg.startswith('tcpserial='):
Brad Bishop15ae2502019-06-18 21:44:24 -0400480 self.tcpserial_portnum = '%s' % arg[len('tcpserial='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600481 elif arg.startswith('qemuparams='):
Andrew Geissler99467da2019-02-25 18:54:23 -0600482 self.qemuparams = ' %s' % arg[len('qemuparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600483 elif arg.startswith('bootparams='):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500484 self.bootparams = arg[len('bootparams='):]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600485 elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
486 self.check_arg_path(os.path.abspath(arg))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500487 elif re.search(r'-image-|-image$', arg):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600488 # Lazy rootfs
489 self.rootfs = arg
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500490 elif arg.startswith('ovmf'):
491 self.ovmf_bios.append(arg)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600492 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500493 # At last, assume it is the MACHINE
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600494 if (not unknown_arg) or unknown_arg == arg:
495 unknown_arg = arg
496 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500497 raise RunQemuError("Can't handle two unknown args: %s %s\n"
498 "Try 'runqemu help' on how to use it" % \
499 (unknown_arg, arg))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600500 # Check to make sure it is a valid machine
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300501 if unknown_arg and self.get('MACHINE') != unknown_arg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500502 if self.get('DEPLOY_DIR_IMAGE'):
503 machine = os.path.basename(self.get('DEPLOY_DIR_IMAGE'))
504 if unknown_arg == machine:
505 self.set("MACHINE", machine)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500506
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600507 self.check_arg_machine(unknown_arg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500508
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500509 if not (self.get('DEPLOY_DIR_IMAGE') or self.qbconfload):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500510 self.load_bitbake_env()
511 s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', self.bitbake_e, re.M)
512 if s:
513 self.set("DEPLOY_DIR_IMAGE", s.group(1))
514
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600515 def check_kvm(self):
516 """Check kvm and kvm-host"""
517 if not (self.kvm_enabled or self.vhost_enabled):
518 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU'))
519 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500520
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600521 if not self.get('QB_CPU_KVM'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500522 raise RunQemuError("QB_CPU_KVM is NULL, this board doesn't support kvm")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500523
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600524 self.qemu_opt_script += ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM'))
525 yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
526 yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
527 dev_kvm = '/dev/kvm'
528 dev_vhost = '/dev/vhost-net'
Brad Bishop15ae2502019-06-18 21:44:24 -0400529 if self.qemu_system.endswith(('i386', 'x86_64')):
530 with open('/proc/cpuinfo', 'r') as f:
531 kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
532 if not kvm_cap:
533 logger.error("You are trying to enable KVM on a cpu without VT support.")
534 logger.error("Remove kvm from the command-line, or refer:")
535 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500536
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600537 if not os.path.exists(dev_kvm):
538 logger.error("Missing KVM device. Have you inserted kvm modules?")
539 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500540 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600542 if os.access(dev_kvm, os.W_OK|os.R_OK):
543 self.qemu_opt_script += ' -enable-kvm'
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500544 if self.get('MACHINE') == "qemux86":
545 # Workaround for broken APIC window on pre 4.15 host kernels which causes boot hangs
546 # See YOCTO #12301
547 # On 64 bit we use x2apic
548 self.kernel_cmdline_script += " clocksource=kvm-clock hpet=disable noapic nolapic"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600549 else:
550 logger.error("You have no read or write permission on /dev/kvm.")
551 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500552 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500553
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600554 if self.vhost_enabled:
555 if not os.path.exists(dev_vhost):
556 logger.error("Missing virtio net device. Have you inserted vhost-net module?")
557 logger.error("For further help see:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500558 raise RunQemuError(yocto_paravirt_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500559
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600560 if not os.access(dev_kvm, os.W_OK|os.R_OK):
561 logger.error("You have no read or write permission on /dev/vhost-net.")
562 logger.error("Please change the ownership of this file as described at:")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500563 raise RunQemuError(yocto_kvm_wiki)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600565 def check_fstype(self):
566 """Check and setup FSTYPE"""
567 if not self.fstype:
568 fstype = self.get('QB_DEFAULT_FSTYPE')
569 if fstype:
570 self.fstype = fstype
571 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500572 raise RunQemuError("FSTYPE is NULL!")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500573
Brad Bishop15ae2502019-06-18 21:44:24 -0400574 # parse QB_FSINFO into dict, e.g. { 'wic': ['no-kernel-in-fs', 'a-flag'], 'ext4': ['another-flag']}
575 wic_fs = False
576 qb_fsinfo = self.get('QB_FSINFO')
577 if qb_fsinfo:
578 qb_fsinfo = qb_fsinfo.split()
579 for fsinfo in qb_fsinfo:
580 try:
581 fstype, fsflag = fsinfo.split(':')
582
583 if fstype == 'wic':
584 if fsflag == 'no-kernel-in-fs':
585 wic_fs = True
586 elif fsflag == 'kernel-in-fs':
587 wic_fs = False
588 else:
589 logger.warn('Unknown flag "%s:%s" in QB_FSINFO', fstype, fsflag)
590 continue
591 else:
592 logger.warn('QB_FSINFO is not supported for image type "%s"', fstype)
593 continue
594
595 if fstype in self.fsinfo:
596 self.fsinfo[fstype].append(fsflag)
597 else:
598 self.fsinfo[fstype] = [fsflag]
599 except Exception:
600 logger.error('Invalid parameter "%s" in QB_FSINFO', fsinfo)
601
602 # treat wic images as vmimages (with kernel) or as fsimages (rootfs only)
603 if wic_fs:
604 self.fstypes = self.fstypes + self.wictypes
605 else:
606 self.vmtypes = self.vmtypes + self.wictypes
607
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600608 def check_rootfs(self):
609 """Check and set rootfs"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500610
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500611 if self.fstype == "none":
612 return
613
614 if self.get('ROOTFS'):
615 if not self.rootfs:
616 self.rootfs = self.get('ROOTFS')
617 elif self.get('ROOTFS') != self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500618 raise RunQemuError("Maybe conflicted ROOTFS: %s vs %s" % (self.get('ROOTFS'), self.rootfs))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500619
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600620 if self.fstype == 'nfs':
621 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500622
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600623 if self.rootfs and not os.path.exists(self.rootfs):
624 # Lazy rootfs
625 self.rootfs = "%s/%s-%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
626 self.rootfs, self.get('MACHINE'),
627 self.fstype)
628 elif not self.rootfs:
629 cmd_name = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_NAME'), self.fstype)
630 cmd_link = '%s/%s*.%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'), self.fstype)
631 cmds = (cmd_name, cmd_link)
632 self.rootfs = get_first_file(cmds)
633 if not self.rootfs:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500634 raise RunQemuError("Failed to find rootfs: %s or %s" % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500635
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600636 if not os.path.exists(self.rootfs):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500637 raise RunQemuError("Can't find rootfs: %s" % self.rootfs)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638
Brad Bishop08902b02019-08-20 09:16:51 -0400639 def setup_pkkek1(self):
640 """
641 Extract from PEM certificate the Platform Key and first Key
642 Exchange Key certificate string. The hypervisor needs to provide
643 it in the Type 11 SMBIOS table
644 """
645 pemcert = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), 'OvmfPkKek1.pem')
646 try:
647 with open(pemcert, 'r') as pemfile:
648 key = pemfile.read().replace('\n', ''). \
649 replace('-----BEGIN CERTIFICATE-----', ''). \
650 replace('-----END CERTIFICATE-----', '')
651 self.ovmf_secboot_pkkek1 = key
652
653 except FileNotFoundError:
654 raise RunQemuError("Can't open PEM certificate %s " % pemcert)
655
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500656 def check_ovmf(self):
657 """Check and set full path for OVMF firmware and variable file(s)."""
658
659 for index, ovmf in enumerate(self.ovmf_bios):
660 if os.path.exists(ovmf):
661 continue
662 for suffix in ('qcow2', 'bin'):
663 path = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'), ovmf, suffix)
664 if os.path.exists(path):
665 self.ovmf_bios[index] = path
Brad Bishop08902b02019-08-20 09:16:51 -0400666 if ovmf.endswith('secboot'):
667 self.setup_pkkek1()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500668 break
669 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500670 raise RunQemuError("Can't find OVMF firmware: %s" % ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500671
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600672 def check_kernel(self):
Brad Bishop316dfdd2018-06-25 12:45:53 -0400673 """Check and set kernel"""
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600674 # The vm image doesn't need a kernel
675 if self.fstype in self.vmtypes:
676 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677
Brad Bishop316dfdd2018-06-25 12:45:53 -0400678 # See if the user supplied a KERNEL option
679 if self.get('KERNEL'):
680 self.kernel = self.get('KERNEL')
681
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500682 # QB_DEFAULT_KERNEL is always a full file path
683 kernel_name = os.path.basename(self.get('QB_DEFAULT_KERNEL'))
684
685 # The user didn't want a kernel to be loaded
Brad Bishop316dfdd2018-06-25 12:45:53 -0400686 if kernel_name == "none" and not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500687 return
688
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600689 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
690 if not self.kernel:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500691 kernel_match_name = "%s/%s" % (deploy_dir_image, kernel_name)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600692 kernel_match_link = "%s/%s" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
693 kernel_startswith = "%s/%s*" % (deploy_dir_image, self.get('KERNEL_IMAGETYPE'))
694 cmds = (kernel_match_name, kernel_match_link, kernel_startswith)
695 self.kernel = get_first_file(cmds)
696 if not self.kernel:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500697 raise RunQemuError('KERNEL not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500698
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600699 if not os.path.exists(self.kernel):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500700 raise RunQemuError("KERNEL %s not found" % self.kernel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500701
Brad Bishop316dfdd2018-06-25 12:45:53 -0400702 def check_dtb(self):
703 """Check and set dtb"""
704 # Did the user specify a device tree?
705 if self.get('DEVICE_TREE'):
706 self.dtb = self.get('DEVICE_TREE')
707 if not os.path.exists(self.dtb):
708 raise RunQemuError('Specified DTB not found: %s' % self.dtb)
709 return
710
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600711 dtb = self.get('QB_DTB')
712 if dtb:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400713 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600714 cmd_match = "%s/%s" % (deploy_dir_image, dtb)
715 cmd_startswith = "%s/%s*" % (deploy_dir_image, dtb)
716 cmd_wild = "%s/*.dtb" % deploy_dir_image
717 cmds = (cmd_match, cmd_startswith, cmd_wild)
718 self.dtb = get_first_file(cmds)
719 if not os.path.exists(self.dtb):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500720 raise RunQemuError('DTB not found: %s, %s or %s' % cmds)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500721
Brad Bishopc68388fc2019-08-26 01:33:31 -0400722 def check_bios(self):
723 """Check and set bios"""
724
725 # See if the user supplied a BIOS option
726 if self.get('BIOS'):
727 self.bios = self.get('BIOS')
728
729 # QB_DEFAULT_BIOS is always a full file path
730 bios_name = os.path.basename(self.get('QB_DEFAULT_BIOS'))
731
732 # The user didn't want a bios to be loaded
733 if (bios_name == "" or bios_name == "none") and not self.bios:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600734 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500735
Brad Bishopc68388fc2019-08-26 01:33:31 -0400736 if not self.bios:
737 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
738 self.bios = "%s/%s" % (deploy_dir_image, bios_name)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500739
Brad Bishopc68388fc2019-08-26 01:33:31 -0400740 if not self.bios:
741 raise RunQemuError('BIOS not found: %s' % bios_match_name)
742
743 if not os.path.exists(self.bios):
744 raise RunQemuError("KERNEL %s not found" % self.bios)
745
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500746
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600747 def check_mem(self):
Andrew Geissler99467da2019-02-25 18:54:23 -0600748 """
749 Both qemu and kernel needs memory settings, so check QB_MEM and set it
750 for both.
751 """
752 s = re.search('-m +([0-9]+)', self.qemuparams)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600753 if s:
754 self.set('QB_MEM', '-m %s' % s.group(1))
755 elif not self.get('QB_MEM'):
Brad Bishop79641f22019-09-10 07:20:22 -0400756 logger.info('QB_MEM is not set, use 256M by default')
757 self.set('QB_MEM', '-m 256')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500758
Andrew Geissler99467da2019-02-25 18:54:23 -0600759 # Check and remove M or m suffix
760 qb_mem = self.get('QB_MEM')
761 if qb_mem.endswith('M') or qb_mem.endswith('m'):
762 qb_mem = qb_mem[:-1]
763
764 # Add -m prefix it not present
765 if not qb_mem.startswith('-m'):
766 qb_mem = '-m %s' % qb_mem
767
768 self.set('QB_MEM', qb_mem)
769
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800770 mach = self.get('MACHINE')
771 if not mach.startswith('qemumips'):
772 self.kernel_cmdline_script += ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M'
773
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600774 self.qemu_opt_script += ' %s' % self.get('QB_MEM')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500775
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600776 def check_tcpserial(self):
777 if self.tcpserial_portnum:
Brad Bishop15ae2502019-06-18 21:44:24 -0400778 ports = self.tcpserial_portnum.split(':')
779 port = ports[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600780 if self.get('QB_TCPSERIAL_OPT'):
Brad Bishop15ae2502019-06-18 21:44:24 -0400781 self.qemu_opt_script += ' ' + self.get('QB_TCPSERIAL_OPT').replace('@PORT@', port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600782 else:
Brad Bishop15ae2502019-06-18 21:44:24 -0400783 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
784
785 if len(ports) > 1:
786 for port in ports[1:]:
787 self.qemu_opt_script += ' -serial tcp:127.0.0.1:%s' % port
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500788
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600789 def check_and_set(self):
790 """Check configs sanity and set when needed"""
791 self.validate_paths()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500792 if not self.slirp_enabled:
793 check_tun()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600794 # Check audio
795 if self.audio_enabled:
796 if not self.get('QB_AUDIO_DRV'):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500797 raise RunQemuError("QB_AUDIO_DRV is NULL, this board doesn't support audio")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600798 if not self.get('QB_AUDIO_OPT'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800799 logger.warning('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600800 else:
801 self.qemu_opt_script += ' %s' % self.get('QB_AUDIO_OPT')
802 os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
803 else:
804 os.putenv('QEMU_AUDIO_DRV', 'none')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500805
Brad Bishop15ae2502019-06-18 21:44:24 -0400806 self.check_qemu_system()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600807 self.check_kvm()
808 self.check_fstype()
809 self.check_rootfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500810 self.check_ovmf()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600811 self.check_kernel()
Brad Bishop316dfdd2018-06-25 12:45:53 -0400812 self.check_dtb()
Brad Bishopc68388fc2019-08-26 01:33:31 -0400813 self.check_bios()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600814 self.check_mem()
815 self.check_tcpserial()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500816
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600817 def read_qemuboot(self):
818 if not self.qemuboot:
819 if self.get('DEPLOY_DIR_IMAGE'):
820 deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600821 else:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800822 logger.warning("Can't find qemuboot conf file, DEPLOY_DIR_IMAGE is NULL!")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600823 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600825 if self.rootfs and not os.path.exists(self.rootfs):
826 # Lazy rootfs
827 machine = self.get('MACHINE')
828 if not machine:
829 machine = os.path.basename(deploy_dir_image)
830 self.qemuboot = "%s/%s-%s.qemuboot.conf" % (deploy_dir_image,
831 self.rootfs, machine)
832 else:
833 cmd = 'ls -t %s/*.qemuboot.conf' % deploy_dir_image
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500834 logger.debug('Running %s...' % cmd)
835 try:
836 qbs = subprocess.check_output(cmd, shell=True).decode('utf-8')
837 except subprocess.CalledProcessError as err:
838 raise RunQemuError(err)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600839 if qbs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500840 for qb in qbs.split():
841 # Don't use initramfs when other choices unless fstype is ramfs
842 if '-initramfs-' in os.path.basename(qb) and self.fstype != 'cpio.gz':
843 continue
844 self.qemuboot = qb
845 break
846 if not self.qemuboot:
847 # Use the first one when no choice
848 self.qemuboot = qbs.split()[0]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600849 self.qbconfload = True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500850
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600851 if not self.qemuboot:
852 # If we haven't found a .qemuboot.conf at this point it probably
853 # doesn't exist, continue without
854 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500855
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600856 if not os.path.exists(self.qemuboot):
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500857 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 -0500858
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500859 logger.debug('CONFFILE: %s' % self.qemuboot)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500860
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600861 cf = configparser.ConfigParser()
862 cf.read(self.qemuboot)
863 for k, v in cf.items('config_bsp'):
864 k_upper = k.upper()
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500865 if v.startswith("../"):
866 v = os.path.abspath(os.path.dirname(self.qemuboot) + "/" + v)
867 elif v == ".":
868 v = os.path.dirname(self.qemuboot)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600869 self.set(k_upper, v)
870
871 def validate_paths(self):
872 """Ensure all relevant path variables are set"""
873 # When we're started with a *.qemuboot.conf arg assume that image
874 # artefacts are relative to that file, rather than in whatever
875 # directory DEPLOY_DIR_IMAGE in the conf file points to.
876 if self.qbconfload:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500877 imgdir = os.path.realpath(os.path.dirname(self.qemuboot))
878 if imgdir != os.path.realpath(self.get('DEPLOY_DIR_IMAGE')):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600879 logger.info('Setting DEPLOY_DIR_IMAGE to folder containing %s (%s)' % (self.qemuboot, imgdir))
880 self.set('DEPLOY_DIR_IMAGE', imgdir)
881
882 # If the STAGING_*_NATIVE directories from the config file don't exist
883 # and we're in a sourced OE build directory try to extract the paths
884 # from `bitbake -e`
885 havenative = os.path.exists(self.get('STAGING_DIR_NATIVE')) and \
886 os.path.exists(self.get('STAGING_BINDIR_NATIVE'))
887
888 if not havenative:
889 if not self.bitbake_e:
890 self.load_bitbake_env()
891
892 if self.bitbake_e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500893 native_vars = ['STAGING_DIR_NATIVE']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600894 for nv in native_vars:
895 s = re.search('^%s="(.*)"' % nv, self.bitbake_e, re.M)
896 if s and s.group(1) != self.get(nv):
897 logger.info('Overriding conf file setting of %s to %s from Bitbake environment' % (nv, s.group(1)))
898 self.set(nv, s.group(1))
899 else:
900 # when we're invoked from a running bitbake instance we won't
901 # be able to call `bitbake -e`, then try:
902 # - get OE_TMPDIR from environment and guess paths based on it
903 # - get OECORE_NATIVE_SYSROOT from environment (for sdk)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500904 tmpdir = self.get('OE_TMPDIR')
905 oecore_native_sysroot = self.get('OECORE_NATIVE_SYSROOT')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600906 if tmpdir:
907 logger.info('Setting STAGING_DIR_NATIVE and STAGING_BINDIR_NATIVE relative to OE_TMPDIR (%s)' % tmpdir)
908 hostos, _, _, _, machine = os.uname()
909 buildsys = '%s-%s' % (machine, hostos.lower())
910 staging_dir_native = '%s/sysroots/%s' % (tmpdir, buildsys)
911 self.set('STAGING_DIR_NATIVE', staging_dir_native)
912 elif oecore_native_sysroot:
913 logger.info('Setting STAGING_DIR_NATIVE to OECORE_NATIVE_SYSROOT (%s)' % oecore_native_sysroot)
914 self.set('STAGING_DIR_NATIVE', oecore_native_sysroot)
915 if self.get('STAGING_DIR_NATIVE'):
916 # we have to assume that STAGING_BINDIR_NATIVE is at usr/bin
917 staging_bindir_native = '%s/usr/bin' % self.get('STAGING_DIR_NATIVE')
918 logger.info('Setting STAGING_BINDIR_NATIVE to %s' % staging_bindir_native)
919 self.set('STAGING_BINDIR_NATIVE', '%s/usr/bin' % self.get('STAGING_DIR_NATIVE'))
920
921 def print_config(self):
922 logger.info('Continuing with the following parameters:\n')
923 if not self.fstype in self.vmtypes:
924 print('KERNEL: [%s]' % self.kernel)
Brad Bishopc68388fc2019-08-26 01:33:31 -0400925 if self.bios:
926 print('BIOS: [%s]' % self.bios)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600927 if self.dtb:
928 print('DTB: [%s]' % self.dtb)
929 print('MACHINE: [%s]' % self.get('MACHINE'))
Brad Bishop15ae2502019-06-18 21:44:24 -0400930 try:
931 fstype_flags = ' (' + ', '.join(self.fsinfo[self.fstype]) + ')'
932 except KeyError:
933 fstype_flags = ''
934 print('FSTYPE: [%s%s]' % (self.fstype, fstype_flags))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600935 if self.fstype == 'nfs':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500936 print('NFS_DIR: [%s]' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600937 else:
938 print('ROOTFS: [%s]' % self.rootfs)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500939 if self.ovmf_bios:
940 print('OVMF: %s' % self.ovmf_bios)
Brad Bishop08902b02019-08-20 09:16:51 -0400941 if (self.ovmf_secboot_pkkek1):
942 print('SECBOOT PKKEK1: [%s...]' % self.ovmf_secboot_pkkek1[0:100])
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600943 print('CONFFILE: [%s]' % self.qemuboot)
944 print('')
945
946 def setup_nfs(self):
947 if not self.nfs_server:
948 if self.slirp_enabled:
949 self.nfs_server = '10.0.2.2'
950 else:
951 self.nfs_server = '192.168.7.1'
952
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500953 # Figure out a new nfs_instance to allow multiple qemus running.
Brad Bishop977dc1a2019-02-06 16:01:43 -0500954 ps = subprocess.check_output(("ps", "auxww")).decode('utf-8')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500955 pattern = '/bin/unfsd .* -i .*\.pid -e .*/exports([0-9]+) '
956 all_instances = re.findall(pattern, ps, re.M)
957 if all_instances:
958 all_instances.sort(key=int)
959 self.nfs_instance = int(all_instances.pop()) + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600960
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500961 nfsd_port = 3049 + 2 * self.nfs_instance
962 mountd_port = 3048 + 2 * self.nfs_instance
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600963
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500964 # Export vars for runqemu-export-rootfs
965 export_dict = {
966 'NFS_INSTANCE': self.nfs_instance,
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500967 'NFSD_PORT': nfsd_port,
968 'MOUNTD_PORT': mountd_port,
969 }
970 for k, v in export_dict.items():
971 # Use '%s' since they are integers
972 os.putenv(k, '%s' % v)
973
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500974 self.unfs_opts="nfsvers=3,port=%s,udp,mountport=%s" % (nfsd_port, mountd_port)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600975
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500976 # Extract .tar.bz2 or .tar.bz if no nfs dir
977 if not (self.rootfs and os.path.isdir(self.rootfs)):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600978 src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
979 dest = "%s-nfsroot" % src_prefix
980 if os.path.exists('%s.pseudo_state' % dest):
981 logger.info('Use %s as NFS_DIR' % dest)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500982 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600983 else:
984 src = ""
985 src1 = '%s.tar.bz2' % src_prefix
986 src2 = '%s.tar.gz' % src_prefix
987 if os.path.exists(src1):
988 src = src1
989 elif os.path.exists(src2):
990 src = src2
991 if not src:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500992 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 -0600993 logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
Brad Bishop977dc1a2019-02-06 16:01:43 -0500994 cmd = ('runqemu-extract-sdk', src, dest)
995 logger.info('Running %s...' % str(cmd))
996 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500997 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600998 self.clean_nfs_dir = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500999 self.rootfs = dest
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001000
1001 # Start the userspace NFS server
Brad Bishop977dc1a2019-02-06 16:01:43 -05001002 cmd = ('runqemu-export-rootfs', 'start', self.rootfs)
1003 logger.info('Running %s...' % str(cmd))
1004 if subprocess.call(cmd) != 0:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001005 raise RunQemuError('Failed to run %s' % cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001006
1007 self.nfs_running = True
1008
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001009 def setup_slirp(self):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001010 """Setup user networking"""
1011
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001012 if self.fstype == 'nfs':
1013 self.setup_nfs()
1014 self.kernel_cmdline_script += ' ip=dhcp'
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001015 # Port mapping
1016 hostfwd = ",hostfwd=tcp::2222-:22,hostfwd=tcp::2323-:23"
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001017 qb_slirp_opt_default = "-netdev user,id=net0%s,tftp=%s" % (hostfwd, self.get('DEPLOY_DIR_IMAGE'))
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001018 qb_slirp_opt = self.get('QB_SLIRP_OPT') or qb_slirp_opt_default
1019 # Figure out the port
1020 ports = re.findall('hostfwd=[^-]*:([0-9]+)-[^,-]*', qb_slirp_opt)
1021 ports = [int(i) for i in ports]
1022 mac = 2
Brad Bishop08902b02019-08-20 09:16:51 -04001023
1024 lockdir = "/tmp/qemu-port-locks"
1025 if not os.path.exists(lockdir):
1026 # There might be a race issue when multi runqemu processess are
1027 # running at the same time.
1028 try:
1029 os.mkdir(lockdir)
1030 os.chmod(lockdir, 0o777)
1031 except FileExistsError:
1032 pass
1033
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001034 # Find a free port to avoid conflicts
1035 for p in ports[:]:
1036 p_new = p
Brad Bishop08902b02019-08-20 09:16:51 -04001037 while not self.check_free_port('localhost', p_new, lockdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001038 p_new += 1
1039 mac += 1
1040 while p_new in ports:
1041 p_new += 1
1042 mac += 1
1043 if p != p_new:
1044 ports.append(p_new)
1045 qb_slirp_opt = re.sub(':%s-' % p, ':%s-' % p_new, qb_slirp_opt)
1046 logger.info("Port forward changed: %s -> %s" % (p, p_new))
1047 mac = "%s%02x" % (self.mac_slirp, mac)
1048 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qb_slirp_opt))
1049 # Print out port foward
1050 hostfwd = re.findall('(hostfwd=[^,]*)', qb_slirp_opt)
1051 if hostfwd:
1052 logger.info('Port forward: %s' % ' '.join(hostfwd))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001053
1054 def setup_tap(self):
1055 """Setup tap"""
1056
1057 # This file is created when runqemu-gen-tapdevs creates a bank of tap
1058 # devices, indicating that the user should not bring up new ones using
1059 # sudo.
1060 nosudo_flag = '/etc/runqemu-nosudo'
1061 self.qemuifup = shutil.which('runqemu-ifup')
1062 self.qemuifdown = shutil.which('runqemu-ifdown')
1063 ip = shutil.which('ip')
1064 lockdir = "/tmp/qemu-tap-locks"
1065
1066 if not (self.qemuifup and self.qemuifdown and ip):
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001067 logger.error("runqemu-ifup: %s" % self.qemuifup)
1068 logger.error("runqemu-ifdown: %s" % self.qemuifdown)
1069 logger.error("ip: %s" % ip)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001070 raise OEPathError("runqemu-ifup, runqemu-ifdown or ip not found")
1071
1072 if not os.path.exists(lockdir):
1073 # There might be a race issue when multi runqemu processess are
1074 # running at the same time.
1075 try:
1076 os.mkdir(lockdir)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001077 os.chmod(lockdir, 0o777)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001078 except FileExistsError:
1079 pass
1080
Brad Bishop977dc1a2019-02-06 16:01:43 -05001081 cmd = (ip, 'link')
1082 logger.debug('Running %s...' % str(cmd))
1083 ip_link = subprocess.check_output(cmd).decode('utf-8')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001084 # Matches line like: 6: tap0: <foo>
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001085 possibles = re.findall('^[0-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001086 tap = ""
1087 for p in possibles:
1088 lockfile = os.path.join(lockdir, p)
1089 if os.path.exists('%s.skip' % lockfile):
1090 logger.info('Found %s.skip, skipping %s' % (lockfile, p))
1091 continue
Brad Bishop08902b02019-08-20 09:16:51 -04001092 self.taplock = lockfile + '.lock'
1093 if self.acquire_taplock(error=False):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001094 tap = p
1095 logger.info("Using preconfigured tap device %s" % tap)
1096 logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
1097 break
1098
1099 if not tap:
1100 if os.path.exists(nosudo_flag):
1101 logger.error("Error: There are no available tap devices to use for networking,")
1102 logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001103 raise RunQemuError("a new one with sudo.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001104
1105 gid = os.getgid()
1106 uid = os.getuid()
1107 logger.info("Setting up tap interface under sudo")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001108 cmd = ('sudo', self.qemuifup, str(uid), str(gid), self.bindir_native)
1109 tap = subprocess.check_output(cmd).decode('utf-8').strip()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001110 lockfile = os.path.join(lockdir, tap)
Brad Bishop08902b02019-08-20 09:16:51 -04001111 self.taplock = lockfile + '.lock'
1112 self.acquire_taplock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001113 self.cleantap = True
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001114 logger.debug('Created tap: %s' % tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001115
1116 if not tap:
1117 logger.error("Failed to setup tap device. Run runqemu-gen-tapdevs to manually create.")
1118 return 1
1119 self.tap = tap
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001120 tapnum = int(tap[3:])
1121 gateway = tapnum * 2 + 1
1122 client = gateway + 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001123 if self.fstype == 'nfs':
1124 self.setup_nfs()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001125 netconf = "192.168.7.%s::192.168.7.%s:255.255.255.0" % (client, gateway)
1126 logger.info("Network configuration: %s", netconf)
1127 self.kernel_cmdline_script += " ip=%s" % netconf
1128 mac = "%s%02x" % (self.mac_tap, client)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001129 qb_tap_opt = self.get('QB_TAP_OPT')
1130 if qb_tap_opt:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001131 qemu_tap_opt = qb_tap_opt.replace('@TAP@', tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001132 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001133 qemu_tap_opt = "-netdev tap,id=net0,ifname=%s,script=no,downscript=no" % (self.tap)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001134
1135 if self.vhost_enabled:
1136 qemu_tap_opt += ',vhost=on'
1137
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001138 self.set('NETWORK_CMD', '%s %s' % (self.network_device.replace('@MAC@', mac), qemu_tap_opt))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001139
1140 def setup_network(self):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001141 if self.get('QB_NET') == 'none':
1142 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001143 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001144 self.saved_stty = subprocess.check_output(("stty", "-g")).decode('utf-8').strip()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001145 self.network_device = self.get('QB_NETWORK_DEVICE') or self.network_device
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001146 if self.slirp_enabled:
1147 self.setup_slirp()
1148 else:
1149 self.setup_tap()
1150
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001151 def setup_rootfs(self):
1152 if self.get('QB_ROOTFS') == 'none':
1153 return
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001154 if 'wic.' in self.fstype:
1155 self.fstype = self.fstype[4:]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001156 rootfs_format = self.fstype if self.fstype in ('vmdk', 'qcow2', 'vdi') else 'raw'
1157
1158 qb_rootfs_opt = self.get('QB_ROOTFS_OPT')
1159 if qb_rootfs_opt:
1160 self.rootfs_options = qb_rootfs_opt.replace('@ROOTFS@', self.rootfs)
1161 else:
1162 self.rootfs_options = '-drive file=%s,if=virtio,format=%s' % (self.rootfs, rootfs_format)
1163
1164 if self.fstype in ('cpio.gz', 'cpio'):
1165 self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
1166 self.rootfs_options = '-initrd %s' % self.rootfs
1167 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001168 vm_drive = ''
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001169 if self.fstype in self.vmtypes:
1170 if self.fstype == 'iso':
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001171 vm_drive = '-drive file=%s,if=virtio,media=cdrom' % self.rootfs
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001172 elif self.get('QB_DRIVE_TYPE'):
1173 drive_type = self.get('QB_DRIVE_TYPE')
1174 if drive_type.startswith("/dev/sd"):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001175 logger.info('Using scsi drive')
1176 vm_drive = '-drive if=none,id=hd,file=%s,format=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' \
1177 % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001178 elif drive_type.startswith("/dev/hd"):
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001179 logger.info('Using ide drive')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001180 vm_drive = "-drive file=%s,format=%s" % (self.rootfs, rootfs_format)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001181 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001182 # virtio might have been selected explicitly (just use it), or
1183 # is used as fallback (then warn about that).
1184 if not drive_type.startswith("/dev/vd"):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001185 logger.warning("Unknown QB_DRIVE_TYPE: %s" % drive_type)
1186 logger.warning("Failed to figure out drive type, consider define or fix QB_DRIVE_TYPE")
1187 logger.warning('Trying to use virtio block drive')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001188 vm_drive = '-drive if=virtio,file=%s,format=%s' % (self.rootfs, rootfs_format)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001189
1190 # All branches above set vm_drive.
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001191 self.rootfs_options = '%s -no-reboot' % vm_drive
1192 self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('QB_KERNEL_ROOT'))
1193
1194 if self.fstype == 'nfs':
1195 self.rootfs_options = ''
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001196 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 -06001197 self.kernel_cmdline = 'root=%s rw highres=off' % k_root
1198
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001199 if self.fstype == 'none':
1200 self.rootfs_options = ''
1201
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001202 self.set('ROOTFS_OPTIONS', self.rootfs_options)
1203
1204 def guess_qb_system(self):
1205 """attempt to determine the appropriate qemu-system binary"""
1206 mach = self.get('MACHINE')
1207 if not mach:
1208 search = '.*(qemux86-64|qemux86|qemuarm64|qemuarm|qemumips64|qemumips64el|qemumipsel|qemumips|qemuppc).*'
1209 if self.rootfs:
1210 match = re.match(search, self.rootfs)
1211 if match:
1212 mach = match.group(1)
1213 elif self.kernel:
1214 match = re.match(search, self.kernel)
1215 if match:
1216 mach = match.group(1)
1217
1218 if not mach:
1219 return None
1220
1221 if mach == 'qemuarm':
1222 qbsys = 'arm'
1223 elif mach == 'qemuarm64':
1224 qbsys = 'aarch64'
1225 elif mach == 'qemux86':
1226 qbsys = 'i386'
1227 elif mach == 'qemux86-64':
1228 qbsys = 'x86_64'
1229 elif mach == 'qemuppc':
1230 qbsys = 'ppc'
1231 elif mach == 'qemumips':
1232 qbsys = 'mips'
1233 elif mach == 'qemumips64':
1234 qbsys = 'mips64'
1235 elif mach == 'qemumipsel':
1236 qbsys = 'mipsel'
1237 elif mach == 'qemumips64el':
1238 qbsys = 'mips64el'
Brad Bishop316dfdd2018-06-25 12:45:53 -04001239 elif mach == 'qemuriscv64':
1240 qbsys = 'riscv64'
1241 elif mach == 'qemuriscv32':
1242 qbsys = 'riscv32'
Brad Bishop004d4992018-10-02 23:54:45 +02001243 else:
1244 logger.error("Unable to determine QEMU PC System emulator for %s machine." % mach)
1245 logger.error("As %s is not among valid QEMU machines such as," % mach)
1246 logger.error("qemux86-64, qemux86, qemuarm64, qemuarm, qemumips64, qemumips64el, qemumipsel, qemumips, qemuppc")
1247 raise RunQemuError("Set qb_system_name with suitable QEMU PC System emulator in .*qemuboot.conf.")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001248
1249 return 'qemu-system-%s' % qbsys
1250
Brad Bishop15ae2502019-06-18 21:44:24 -04001251 def check_qemu_system(self):
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001252 qemu_system = self.get('QB_SYSTEM_NAME')
1253 if not qemu_system:
1254 qemu_system = self.guess_qb_system()
1255 if not qemu_system:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001256 raise RunQemuError("Failed to boot, QB_SYSTEM_NAME is NULL!")
Brad Bishop15ae2502019-06-18 21:44:24 -04001257 self.qemu_system = qemu_system
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001258
Brad Bishop15ae2502019-06-18 21:44:24 -04001259 def setup_final(self):
1260 qemu_bin = os.path.join(self.bindir_native, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001261
1262 # It is possible to have qemu-native in ASSUME_PROVIDED, and it won't
1263 # find QEMU in sysroot, it needs to use host's qemu.
1264 if not os.path.exists(qemu_bin):
1265 logger.info("QEMU binary not found in %s, trying host's QEMU" % qemu_bin)
1266 for path in (os.environ['PATH'] or '').split(':'):
Brad Bishop15ae2502019-06-18 21:44:24 -04001267 qemu_bin_tmp = os.path.join(path, self.qemu_system)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001268 logger.info("Trying: %s" % qemu_bin_tmp)
1269 if os.path.exists(qemu_bin_tmp):
1270 qemu_bin = qemu_bin_tmp
1271 if not os.path.isabs(qemu_bin):
1272 qemu_bin = os.path.abspath(qemu_bin)
1273 logger.info("Using host's QEMU: %s" % qemu_bin)
1274 break
1275
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001276 if not os.access(qemu_bin, os.X_OK):
1277 raise OEPathError("No QEMU binary '%s' could be found" % qemu_bin)
1278
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001279 self.qemu_opt = "%s %s %s %s" % (qemu_bin, self.get('NETWORK_CMD'), self.get('ROOTFS_OPTIONS'), self.get('QB_OPT_APPEND'))
1280
1281 for ovmf in self.ovmf_bios:
1282 format = ovmf.rsplit('.', 1)[-1]
1283 self.qemu_opt += ' -drive if=pflash,format=%s,file=%s' % (format, ovmf)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001284
1285 self.qemu_opt += ' ' + self.qemu_opt_script
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001286
Brad Bishop08902b02019-08-20 09:16:51 -04001287 if self.ovmf_secboot_pkkek1:
1288 # Provide the Platform Key and first Key Exchange Key certificate as an
1289 # OEM string in the SMBIOS Type 11 table. Prepend the certificate string
1290 # with "application prefix" of the EnrollDefaultKeys.efi application
1291 self.qemu_opt += ' -smbios type=11,value=4e32566d-8e9e-4f52-81d3-5bb9715f9727:' \
1292 + self.ovmf_secboot_pkkek1
1293
Andrew Geissler99467da2019-02-25 18:54:23 -06001294 # Append qemuparams to override previous settings
1295 if self.qemuparams:
1296 self.qemu_opt += ' ' + self.qemuparams
1297
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001298 if self.snapshot:
1299 self.qemu_opt += " -snapshot"
1300
Brad Bishop19323692019-04-05 15:28:33 -04001301 if self.serialconsole:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001302 if sys.stdin.isatty():
Brad Bishop977dc1a2019-02-06 16:01:43 -05001303 subprocess.check_call(("stty", "intr", "^]"))
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001304 logger.info("Interrupt character is '^]'")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001305
1306 first_serial = ""
1307 if not re.search("-nographic", self.qemu_opt):
1308 first_serial = "-serial mon:vc"
1309 # We always want a ttyS1. Since qemu by default adds a serial
1310 # port when nodefaults is not specified, it seems that all that
1311 # would be needed is to make sure a "-serial" is there. However,
1312 # it appears that when "-serial" is specified, it ignores the
1313 # default serial port that is normally added. So here we make
1314 # sure to add two -serial if there are none. And only one if
1315 # there is one -serial already.
1316 serial_num = len(re.findall("-serial", self.qemu_opt))
1317 if serial_num == 0:
1318 self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
1319 elif serial_num == 1:
1320 self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
1321
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001322 # We always wants ttyS0 and ttyS1 in qemu machines (see SERIAL_CONSOLES),
1323 # if not serial or serialtcp options was specified only ttyS0 is created
1324 # and sysvinit shows an error trying to enable ttyS1:
1325 # INIT: Id "S1" respawning too fast: disabled for 5 minutes
1326 serial_num = len(re.findall("-serial", self.qemu_opt))
1327 if serial_num == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001328 if re.search("-nographic", self.qemu_opt) or self.serialstdio:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001329 self.qemu_opt += " -serial mon:stdio -serial null"
1330 else:
1331 self.qemu_opt += " -serial mon:vc -serial null"
1332
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001333 def start_qemu(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001334 import shlex
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001335 if self.kernel:
Brad Bishop37a0e4d2017-12-04 01:01:44 -05001336 kernel_opts = "-kernel %s -append '%s %s %s %s'" % (self.kernel, self.kernel_cmdline,
1337 self.kernel_cmdline_script, self.get('QB_KERNEL_CMDLINE_APPEND'),
1338 self.bootparams)
Brad Bishopc68388fc2019-08-26 01:33:31 -04001339 if self.bios:
1340 kernel_opts += " -bios %s" % self.bios
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001341 if self.dtb:
1342 kernel_opts += " -dtb %s" % self.dtb
1343 else:
1344 kernel_opts = ""
1345 cmd = "%s %s" % (self.qemu_opt, kernel_opts)
Brad Bishop004d4992018-10-02 23:54:45 +02001346 cmds = shlex.split(cmd)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001347 logger.info('Running %s\n' % cmd)
Brad Bishopf86d0552018-12-04 14:18:15 -08001348 pass_fds = []
Brad Bishop08902b02019-08-20 09:16:51 -04001349 if self.taplock_descriptor:
1350 pass_fds = [self.taplock_descriptor.fileno()]
1351 if len(self.portlocks):
1352 for descriptor in self.portlocks.values():
1353 pass_fds.append(descriptor.fileno())
Brad Bishopf86d0552018-12-04 14:18:15 -08001354 process = subprocess.Popen(cmds, stderr=subprocess.PIPE, pass_fds=pass_fds)
Brad Bishop004d4992018-10-02 23:54:45 +02001355 self.qemupid = process.pid
1356 retcode = process.wait()
1357 if retcode:
1358 if retcode == -signal.SIGTERM:
1359 logger.info("Qemu terminated by SIGTERM")
1360 else:
1361 logger.error("Failed to run qemu: %s", process.stderr.read().decode())
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001362
1363 def cleanup(self):
Brad Bishop004d4992018-10-02 23:54:45 +02001364 if self.cleaned:
1365 return
1366
1367 # avoid dealing with SIGTERM when cleanup function is running
1368 signal.signal(signal.SIGTERM, signal.SIG_IGN)
1369
1370 logger.info("Cleaning up")
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001371 if self.cleantap:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001372 cmd = ('sudo', self.qemuifdown, self.tap, self.bindir_native)
1373 logger.debug('Running %s' % str(cmd))
1374 subprocess.check_call(cmd)
Brad Bishop08902b02019-08-20 09:16:51 -04001375 self.release_taplock()
1376 self.release_portlock()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001377
1378 if self.nfs_running:
1379 logger.info("Shutting down the userspace NFS server...")
Brad Bishop977dc1a2019-02-06 16:01:43 -05001380 cmd = ("runqemu-export-rootfs", "stop", self.rootfs)
1381 logger.debug('Running %s' % str(cmd))
1382 subprocess.check_call(cmd)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001383
1384 if self.saved_stty:
Brad Bishop977dc1a2019-02-06 16:01:43 -05001385 subprocess.check_call(("stty", self.saved_stty))
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001386
1387 if self.clean_nfs_dir:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001388 logger.info('Removing %s' % self.rootfs)
1389 shutil.rmtree(self.rootfs)
1390 shutil.rmtree('%s.pseudo_state' % self.rootfs)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001391
Brad Bishop004d4992018-10-02 23:54:45 +02001392 self.cleaned = True
1393
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001394 def load_bitbake_env(self, mach=None):
1395 if self.bitbake_e:
1396 return
1397
1398 bitbake = shutil.which('bitbake')
1399 if not bitbake:
1400 return
1401
1402 if not mach:
1403 mach = self.get('MACHINE')
1404
1405 if mach:
1406 cmd = 'MACHINE=%s bitbake -e' % mach
1407 else:
1408 cmd = 'bitbake -e'
1409
1410 logger.info('Running %s...' % cmd)
1411 try:
1412 self.bitbake_e = subprocess.check_output(cmd, shell=True).decode('utf-8')
1413 except subprocess.CalledProcessError as err:
1414 self.bitbake_e = ''
Brad Bishop1a4b7ee2018-12-16 17:11:34 -08001415 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 -06001416
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001417 def validate_combos(self):
1418 if (self.fstype in self.vmtypes) and self.kernel:
1419 raise RunQemuError("%s doesn't need kernel %s!" % (self.fstype, self.kernel))
1420
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001421 @property
1422 def bindir_native(self):
1423 result = self.get('STAGING_BINDIR_NATIVE')
1424 if result and os.path.exists(result):
1425 return result
1426
Brad Bishop977dc1a2019-02-06 16:01:43 -05001427 cmd = ('bitbake', 'qemu-helper-native', '-e')
1428 logger.info('Running %s...' % str(cmd))
1429 out = subprocess.check_output(cmd).decode('utf-8')
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001430
1431 match = re.search('^STAGING_BINDIR_NATIVE="(.*)"', out, re.M)
1432 if match:
1433 result = match.group(1)
1434 if os.path.exists(result):
1435 self.set('STAGING_BINDIR_NATIVE', result)
1436 return result
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001437 raise RunQemuError("Native sysroot directory %s doesn't exist" % result)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001438 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001439 raise RunQemuError("Can't find STAGING_BINDIR_NATIVE in '%s' output" % cmd)
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001440
1441
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001442def main():
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001443 if "help" in sys.argv or '-h' in sys.argv or '--help' in sys.argv:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001444 print_usage()
1445 return 0
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001446 try:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001447 config = BaseConfig()
Brad Bishop004d4992018-10-02 23:54:45 +02001448
1449 def sigterm_handler(signum, frame):
1450 logger.info("SIGTERM received")
1451 os.kill(config.qemupid, signal.SIGTERM)
1452 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001453 # Deliberately ignore the return code of 'tput smam'.
1454 subprocess.call(["tput", "smam"])
Brad Bishop004d4992018-10-02 23:54:45 +02001455 signal.signal(signal.SIGTERM, sigterm_handler)
1456
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001457 config.check_args()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001458 config.read_qemuboot()
1459 config.check_and_set()
1460 # Check whether the combos is valid or not
1461 config.validate_combos()
1462 config.print_config()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001463 config.setup_network()
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001464 config.setup_rootfs()
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001465 config.setup_final()
1466 config.start_qemu()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001467 except RunQemuError as err:
1468 logger.error(err)
1469 return 1
1470 except Exception as err:
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001471 import traceback
1472 traceback.print_exc()
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001473 return 1
1474 finally:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001475 config.cleanup()
Brad Bishopc342db32019-05-15 21:57:59 -04001476 # Deliberately ignore the return code of 'tput smam'.
1477 subprocess.call(["tput", "smam"])
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001478
1479if __name__ == "__main__":
1480 sys.exit(main())