Skip to contentSkip to conversation

runqemu: refactor it and remove machine knowledge

PATCH Superseded Robert Yang 3 participants 15 messages Aug 19, 2016 – Aug 22, 2016

v3 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v3 cover runqemu: refactor it and remove machine knowledge

* V3
- Move the qemu boot settings out of tune files (e.g., arch-x86.inc) to avoid mixing BSP settings with the tunings as Mark suggested. and put them to <machine>.conf or <qemuboot>.inc file.

* V2
- Fixes for RP's comments
a) Remove a kvm commit message since qemu-kvm can only run target when its arch is the same as the host arch:
The kvm support is not limited on x86 or x86_64

b) Fix a typo in commit message: qemu-boot.bbclass -> qemuboot.bbclass, You may wonder why I use qemuboot.bbclass but not qemu-boot.bbclass, this is because the bbclass will save vars into qemuboot.py, the qemuboot.py can't be qemu-boot.py here, otherwise, "import qemu-boot.py" doesn't work since "-" is not a validate identifier, so use "qemuboot" to make them unify.

c) Reorder the patches to make sure they don't break the bisect build.

- Update commit message:

    "Fix SLIRP mode" -> "Fix SLIRP mode, add help message, avoid mixing

with tap"

* V1
Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

- Re-write it in python3, which can reduce lines from 1239 to about 750 lines
- All the machine knowledges are gone
- Most of the TUN_ARCH knowledge are gone except aarch64 and powerpc, it's not easy to remove the two, so leave them there atm
- All the previous options are preserved, and there is a new way to run
runqemu: (it doesn't need run "bitake -e" in such a case) $ runqemu tmp/deploy/images/qemux86
or:
$ runqemu tmp/deploy/images/qemuarm/<image>.ext4
or:
$ runqemu tmp/deploy/images/qemuarm/qemuboot.py
- Fixed audio support, not limited on x86 or x86_64
- The kvm support is not limited on x86 or x86_64 (REMOVED by V2)
- Fix SLIRP mode (FIXED by V2)
- Fix NFS boot, it will extract <image>.tar.bz2 or tar.gz to DEPLOY_DIR_IMAGE/<image>-nfsroot when no NFS_DIR, and remove it after stop.
- More bsps can be boot, such as genericx86 and genericx86-64.
- The patch for qemuzynq, qemuzynqmp, qemumicroblaze has been sent to meta-xilinx' mailing list.
- I can't find any qemush4 bsp or how to build it, so it is not considered atm.

- Tested the following machines, all of them work well. genericx86 genericx86-64
qemuarm qemuarm64
qemumips qemumips64 qemuppc
qemux86 qemux86-64
qemuzynq qemuzynqmp

Tested ext4, nfs, slirp, vmdk, iso and cpio.gz when they are available.

And also test "bitbake core-image-sato -ctestimage" which uses runqemu, it works, well.

// Robert

The following changes since commit 5dca6cc2fcdb2799c19b1697f0647a16ce296290:

systemd-compat-units: Only enable for systemd in DISTRO_FEATURES (2016-08-18 16:52:02 +0100)

are available in the git repository at:

git://git.openembedded.org/openembedded-core-contrib rbt/runqemu
http://cgit.openembedded.org/cgit.cgi/openembedded-core-contrib/log/?h=rbt/runqemu

Robert Yang (8):
qemuboot.bbclass: add it for runqemu qemuarm.conf: set vars for runqemu qemuarm64.conf: set vars for runqemu qemux86.conf/qemux86-64.conf: set vars for runqemu qemumips/qemumips64.conf: set vars for runqemu qemuppc.conf: set vars for runqemu qemu.inc: inherit qemuboot.bbclass
runqemu: refactor it and remove machine knowledge

 meta/classes/qemuboot.bbclass               |   59 ++
 meta/conf/machine/include/qemu.inc          |    2 +
 meta/conf/machine/include/qemuboot-mips.inc |    7 +
 meta/conf/machine/include/qemuboot-x86.inc  |   14 +
 meta/conf/machine/qemuarm.conf              |    5 +
 meta/conf/machine/qemuarm64.conf            |    9 +
 meta/conf/machine/qemumips.conf             |    1 +
 meta/conf/machine/qemumips64.conf           |    1 +
 meta/conf/machine/qemuppc.conf              |    6 +
 meta/conf/machine/qemux86-64.conf           |    1 +
 meta/conf/machine/qemux86.conf              |    1 +
 scripts/runqemu                             | 1260 ++++++++++++++++-----------
 scripts/runqemu-internal                    |  739 ----------------
 13 files changed, 841 insertions(+), 1264 deletions(-)
 create mode 100644 meta/classes/qemuboot.bbclass
 create mode 100644 meta/conf/machine/include/qemuboot-mips.inc
 create mode 100644 meta/conf/machine/include/qemuboot-x86.inc
 delete mode 100755 scripts/runqemu-internal
Signature · 1 line
2.9.0
#1 lore raw

PATCH v3 1/8 qemuboot.bbclass: add it for runqemu

It saves vars in ${DEPLOY_DIR_IMAGE}/qemuboot.py, and runqemu will import it.

The bsp which can be boot by runqemu will inherit it.

---
 meta/classes/qemuboot.bbclass | 59 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
 create mode 100644 meta/classes/qemuboot.bbclass
meta/classes/qemuboot.bbclass new file +59 -0
new file mode 100644
index 0000000..6480021
@@ -0,0 +1,59 @@
+# Help runqemu boot target board, "QB" means Qemu Boot, the following
+# vars can be set in conf files, such as <bsp.conf> to make it can be
+# boot by runqemu:
+#
+# QB_SYSTEM_NAME: qemu name, e.g., "qemu-system-i386"
+# QB_OPT_APPEND: options to append to qemu, e.g., "-show-cursor"
+# QB_SERIAL_OPT: serial port, e.g., "-serial mon:stdio"
+# QB_DEFAULT_KERNEL: default kernel to boot, e.g., "bzImage"
+# QB_DEFAULT_FSTYPE: default FSTYPE to boot, e.g., "ext4"
+# QB_MEM: memory, e.g., "-m 512"
+# QB_MACHINE: qemu machine, e.g., "-machine virt"
+# QB_CPU: qemu cpu, e.g., "-cpu qemu32"
+# QB_CPU_KVM: the similar to QB_CPU, but used when kvm, e.g., '-cpu kvm64',
+#             set it when support kvm.
+# QB_KERNEL_CMDLINE_APPEND: options to append to kernel's -append
+#                           option, e.g., "console=ttyS0 console=tty"
+# QB_DTB: qemu dtb name
+# QB_AUDIO_DRV: qemu audio driver, e.g., "alsa", set it when support audio
+# QB_AUDIO_OPT: qemu audio option, e.g., "-soundhw ac97,es1370", used
+#               when QB_AUDIO_DRV is set.
+#
+# Not often used vars:
+# QB_ROOTFS_OPTIONS: used to replace runqemu's ROOTFS_OPTIONS
+# QB_NETWORK_CMD: used to replace runqemu's QB_NETWORK_CMD
+#
+# Usage:
+# IMAGE_CLASSES += "qemuboot"
+# See "runqemu help" for more info
+
+do_qemuboot_vars[nostamp] = "1"
+
+QB_MEM ?= "-m 256"
+QB_SERIAL_OPT ?= "-serial mon:stdio -serial null"
+QB_DEFAULT_KERNEL ?= "${KERNEL_IMAGETYPE}"
+QB_DEFAULT_FSTYPE ?= "ext4"
+QB_OPT_APPEND ?= "-show-cursor"
+
+do_qemuboot_vars[dirs] = "${DEPLOY_DIR_IMAGE}"
+python do_qemuboot_vars() {
+    build_vars = ['MACHINE', 'TUNE_ARCH', 'DEPLOY_DIR_IMAGE', \
+                'IMAGE_LINK_NAME', 'STAGING_DIR_NATIVE', \
+                'STAGING_BINDIR_NATIVE', 'STAGING_DIR_HOST']
+
+    # Vars from bsp
+    qb_vars = []
+
+    for k in d.keys():
+        if k.startswith('QB_'):
+            qb_vars.append(k)
+
+    out_file = "%s/%s" % (d.getVar('DEPLOY_DIR_IMAGE', True), 'qemuboot.py')
+    with open(out_file, 'w') as f:
+        f.write('config_bsp = {\n')
+        for k in build_vars + qb_vars:
+            f.write("    '%s': '%s',\n" % (k, d.getVar(k, True)))
+        f.write('}\n')
+}
+
+addtask do_qemuboot_vars before do_build
Signature · 1 line
2.9.0
#2 lore raw

PATCH v3 2/8 qemuarm.conf: set vars for runqemu

In reply to Robert Yang

These info are from old runqemu.

---
 meta/conf/machine/qemuarm.conf | 5 +++++
 1 file changed, 5 insertions(+)
meta/conf/machine/qemuarm.conf +5 -0
index cdad03f..34686cf 100644
@@ -10,3 +10,8 @@ KERNEL_IMAGETYPE = "zImage"
 
 SERIAL_CONSOLES = "115200;ttyAMA0 115200;ttyAMA1"
 
+# For runqemu
+QB_SYSTEM_NAME = "qemu-system-arm"
+QB_MACHINE = "-machine versatilepb"
+QB_KERNEL_CMDLINE_APPEND = "console=ttyAMA0,115200 console=tty"
+QB_OPT_APPEND = "-show-cursor -usb -usbdevice tablet"
Signature · 1 line
2.9.0
#3 lore raw

PATCH v3 3/8 qemuarm64.conf: set vars for runqemu

In reply to Robert Yang
---
 meta/conf/machine/qemuarm64.conf | 9 +++++++++
 1 file changed, 9 insertions(+)
meta/conf/machine/qemuarm64.conf +9 -0
index f59fb15..fd73583 100644
@@ -8,3 +8,12 @@ require conf/machine/include/qemu.inc
 KERNEL_IMAGETYPE = "Image"
 
 SERIAL_CONSOLES = "38400;ttyAMA0 38400;hvc0"
+
+# For runqemu
+QB_SYSTEM_NAME = "qemu-system-aarch64"
+QB_MEM = "-m 512"
+QB_MACHINE = "-machine virt"
+QB_CPU = "-cpu cortex-a57"
+QB_SERIAL_OPT = "-device virtio-serial-device -chardev null,id=virtcon -device virtconsole,chardev=virtcon"
+QB_KERNEL_CMDLINE_APPEND = "console=ttyAMA0,38400"
+QB_OPT_APPEND = "-show-cursor"
Signature · 1 line
2.9.0
#4 lore raw

PATCH v3 4/8 qemux86.conf/qemux86-64.conf: set vars for runqemu

In reply to Robert Yang

Add qemuboot-x86.inc to reduce duplicated code, the x86/x86_64 bsps which can be boot by runqemu can require qemuboot-x86.inc.

---
 meta/conf/machine/include/qemuboot-x86.inc | 14 ++++++++++++++
 meta/conf/machine/qemux86-64.conf          |  1 +
 meta/conf/machine/qemux86.conf             |  1 +
 3 files changed, 16 insertions(+)
 create mode 100644 meta/conf/machine/include/qemuboot-x86.inc
meta/conf/machine/include/qemuboot-x86.inc new file +14 -0
new file mode 100644
index 0000000..2ff3ca9
@@ -0,0 +1,14 @@
+# For runqemu
+IMAGE_CLASSES += "qemuboot"
+QB_SYSTEM_NAME_x86 = "qemu-system-i386"
+QB_CPU_x86 = "-cpu qemu32"
+QB_CPU_KVM_x86 = "-cpu kvm32"
+
+QB_SYSTEM_NAME_x86-64 = "qemu-system-x86_64"
+QB_CPU_x86-64 = "-cpu core2duo"
+QB_CPU_KVM_x86-64 = "-cpu kvm64"
+
+QB_AUDIO_DRV = "alsa"
+QB_AUDIO_OPT = "-soundhw ac97,es1370"
+QB_KERNEL_CMDLINE_APPEND = "vga=0 uvesafb.mode_option=640x480-32 oprofile.timer=1"
+QB_OPT_APPEND = "-vga vmware -show-cursor -usb -usbdevice tablet"
meta/conf/machine/qemux86-64.conf +1 -0
index 489194a..881a454 100644
@@ -10,6 +10,7 @@ PREFERRED_PROVIDER_virtual/libgles2 ?= "mesa"
 require conf/machine/include/qemu.inc
 DEFAULTTUNE ?= "core2-64"
 require conf/machine/include/tune-core2.inc
+require conf/machine/include/qemuboot-x86.inc
 
 KERNEL_IMAGETYPE = "bzImage"
 
meta/conf/machine/qemux86.conf +1 -0
index 3cc8091..ca707fb 100644
@@ -9,6 +9,7 @@ PREFERRED_PROVIDER_virtual/libgles2 ?= "mesa"
 
 require conf/machine/include/qemu.inc
 require conf/machine/include/tune-i586.inc
+require conf/machine/include/qemuboot-x86.inc
 
 KERNEL_IMAGETYPE = "bzImage"
 
Signature · 1 line
2.9.0
#5 lore raw

PATCH v3 5/8 qemumips/qemumips64.conf: set vars for runqemu

In reply to Robert Yang

Add qemuboot-mips.inc to reduce duplicated code, the various mips bsps which can be boot by runqemu can require qemuboot-mips.inc

---
 meta/conf/machine/include/qemuboot-mips.inc | 7 +++++++
 meta/conf/machine/qemumips.conf             | 1 +
 meta/conf/machine/qemumips64.conf           | 1 +
 3 files changed, 9 insertions(+)
 create mode 100644 meta/conf/machine/include/qemuboot-mips.inc
meta/conf/machine/include/qemuboot-mips.inc new file +7 -0
new file mode 100644
index 0000000..0f04b81
@@ -0,0 +1,7 @@
+# For runqemu
+IMAGE_CLASSES += "qemuboot"
+QB_MEM = "-m 256"
+QB_MACHINE = "-machine malta"
+QB_KERNEL_CMDLINE_APPEND = "console=ttyS0 console=tty"
+QB_OPT_APPEND = "-vga cirrus -show-cursor -usb -usbdevice tablet"
+QB_SYSTEM_NAME = "qemu-system-${TUNE_ARCH}"
meta/conf/machine/qemumips.conf +1 -0
index fbf8137..3182ea1 100644
@@ -4,6 +4,7 @@
 
 require conf/machine/include/qemu.inc
 require conf/machine/include/tune-mips32r2.inc
+require conf/machine/include/qemuboot-mips.inc
 
 KERNEL_IMAGETYPE = "vmlinux"
 KERNEL_ALT_IMAGETYPE = "vmlinux.bin"
meta/conf/machine/qemumips64.conf +1 -0
index 8c3f1fe..9529f4c 100644
@@ -4,6 +4,7 @@
 
 require conf/machine/include/qemu.inc
 require conf/machine/include/tune-mips64.inc
+require conf/machine/include/qemuboot-mips.inc
 
 KERNEL_IMAGETYPE = "vmlinux"
 KERNEL_ALT_IMAGETYPE = "vmlinux.bin"
Signature · 1 line
2.9.0
#6 lore raw

PATCH v3 6/8 qemuppc.conf: set vars for runqemu

In reply to Robert Yang
---
 meta/conf/machine/qemuppc.conf | 6 ++++++
 1 file changed, 6 insertions(+)
meta/conf/machine/qemuppc.conf +6 -0
index bf0038d..dbadf5a 100644
@@ -11,3 +11,9 @@ KERNEL_IMAGETYPE = "vmlinux"
 
 SERIAL_CONSOLES = "115200;ttyS0 115200;ttyS1"
 
+# For runqemu
+QB_SYSTEM_NAME = "qemu-system-ppc"
+QB_MACHINE = "-machine mac99"
+QB_CPU = "-cpu G4"
+QB_KERNEL_CMDLINE_APPEND = "console=ttyS0 console=tty"
+QB_OPT_APPEND = "-show-cursor -usb -usbdevice tablet"
Signature · 1 line
2.9.0
#7 lore raw

PATCH v3 7/8 qemu.inc: inherit qemuboot.bbclass

In reply to Robert Yang

All qemu boards should be able to boot by runqemu.

---
 meta/conf/machine/include/qemu.inc | 2 ++
 1 file changed, 2 insertions(+)
meta/conf/machine/include/qemu.inc +2 -0
index f44dbe6..2bc4dc2 100644
@@ -29,3 +29,5 @@ EXTRA_IMAGEDEPENDS += "qemu-native qemu-helper-native"
 KERNEL_FEATURES_append_pn-linux-yocto = " features/nfsd/nfsd-enable.scc"
 
 MACHINE_EXTRA_RRECOMMENDS += "rng-tools"
+
+IMAGE_CLASSES += "qemuboot"
Signature · 1 line
2.9.0
#8 lore raw

PATCH v3 8/8 runqemu: refactor it and remove machine knowledge

In reply to Robert Yang

Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

* Re-write it in python3, which can reduce lines from 1239 to about 750 lines
* All the machine knowledges are gone
* Most of the TUN_ARCH knowledge are gone except aarch64 and powerpc, it's not easy to remove the two, so leave them there atm
* All the previous options are preserved, and there is a new way to run
runqemu: (it doesn't need run "bitake -e" in such a case)

  $ runqemu tmp/deploy/images/qemux86
  or:
  $ runqemu tmp/deploy/images/qemuarm/<image>.ext4
  or:
  $ runqemu tmp/deploy/images/qemuarm/qemuboot.py
* Fixed audio support, not limited on x86 or x86_64
* Fix SLIRP mode, add help message, avoid mixing with tap
* Fix NFS boot, it will extract <image>.tar.bz2 or tar.gz to
  DEPLOY_DIR_IMAGE/<image>-nfsroot when no NFS_DIR, and remove it after
  stop.
* More bsps can be boot, such as genericx86 and genericx86-64.
* The patch for qemuzynq, qemuzynqmp, qemumicroblaze has been sent to
  meta-xilinx' mailing list.
* I can't find any qemush4 bsp or how to build it, so it is not
  considered atm.

[YOCTO #1018]
[YOCTO #4827]
[YOCTO #7459]
[YOCTO #7887]

---
 scripts/runqemu          | 1260 +++++++++++++++++++++++++++-------------------
 scripts/runqemu-internal |  739 ---------------------------
 2 files changed, 735 insertions(+), 1264 deletions(-)
 delete mode 100755 scripts/runqemu-internal
scripts/runqemu +735 -525
index d52ea15..3fd7034 100755
@@ -1,8 +1,9 @@
-#!/bin/bash
-#
+#!/usr/bin/env python3
+
 # Handle running OE images standalone with QEMU
 #
 # Copyright (C) 2006-2011 Linux Foundation
+# Copyright (c) 2016 Wind River Systems, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License version 2 as
@@ -17,536 +18,745 @@
 # with this program; if not, write to the Free Software Foundation, Inc.,
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
-usage() {
-    MYNAME=`basename $0`
-cat <<_EOF
+import os
+import sys
+import logging
+import subprocess
+import re
+import fcntl
+import shutil
+
+def create_logger():
+    logger = logging.getLogger('runqemu')
+    logger.setLevel(logging.INFO)
+
+    # create console handler and set level to debug
+    ch = logging.StreamHandler()
+    ch.setLevel(logging.INFO)
+
+    # create formatter
+    formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
+
+    # add formatter to ch
+    ch.setFormatter(formatter)
+
+    # add ch to logger
+    logger.addHandler(ch)
+
+    return logger
+
+logger = create_logger()
 
+def print_usage():
+    print("""
 Usage: you can run this script with any valid combination
 of the following environment variables (in any order):
   KERNEL - the kernel image file to use
   ROOTFS - the rootfs image file or nfsroot directory to use
   MACHINE - the machine name (optional, autodetected from KERNEL filename if unspecified)
   Simplified QEMU command-line options can be passed with:
-    nographic - disables video console
-    serial - enables a serial console on /dev/ttyS0
-    kvm - enables KVM when running qemux86/qemux86-64 (VT-capable CPU required)
-    kvm-vhost - enables KVM with vhost support when running qemux86/qemux86-64 (VT-capable CPU required)
+    nographic - disable video console
+    serial - enable a serial console on /dev/ttyS0
+    slirp - enable user networking, no root privileges is required
+    kvm - enable KVM when running x86/x86_64 (VT-capable CPU required)
+    kvm-vhost - enable KVM with vhost when running x86/x86_64 (VT-capable CPU required)
     publicvnc - enable a VNC server open to all hosts
-  qemuparams="xyz" - specify custom parameters to QEMU
-  bootparams="xyz" - specify custom kernel parameters during boot
+    audio - enable audio
+  tcpserial=<port> - specify tcp serial port number
+  biosdir=<dir> - specify custom bios dir
+  biosfilename=<filename> - specify bios filename
+  qemuparams=<xyz> - specify custom parameters to QEMU
+  bootparams=<xyz> - specify custom kernel parameters during boot
+  help: print this text
 
 Examples:
-  $MYNAME qemuarm
-  $MYNAME qemux86-64 core-image-sato ext4
-  $MYNAME qemux86-64 wic-image-minimal wic
-  $MYNAME path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
-  $MYNAME qemux86 iso/hddimg/vmdk/qcow2/vdi/ramfs/cpio.gz...
-  $MYNAME qemux86 qemuparams="-m 256"
-  $MYNAME qemux86 bootparams="psplash=false"
-  $MYNAME path/to/<image>-<machine>.vmdk
-  $MYNAME path/to/<image>-<machine>.wic
-_EOF
-    exit 1
-}
-
-if [ "x$1" = "x" ]; then
-    usage
-fi
-
-error() {
-    echo "Error: "$*
-    usage
-}
-
-MACHINE=${MACHINE:=""}
-KERNEL=${KERNEL:=""}
-ROOTFS=${ROOTFS:=""}
-FSTYPE=${FSTYPE:=""}
-LAZY_ROOTFS=""
-SCRIPT_QEMU_OPT=""
-SCRIPT_QEMU_EXTRA_OPT=""
-SCRIPT_KERNEL_OPT=""
-SERIALSTDIO=""
-TCPSERIAL_PORTNUM=""
-KVM_ENABLED="no"
-KVM_ACTIVE="no"
-VHOST_ENABLED="no"
-VHOST_ACTIVE="no"
-IS_VM="false"
-
-# Determine whether the file is a kernel or QEMU image, and set the
-# appropriate variables
-process_filename() {
-    filename=$1
-
-    # Extract the filename extension
-    EXT=`echo $filename | awk -F . '{ print \$NF }'`
-    case /$EXT/ in
-	/bin/)
-		# A file ending in .bin is a kernel
-		[ -z "$KERNEL" ] && KERNEL=$filename || \
-		    error "conflicting KERNEL args [$KERNEL] and [$filename]"
-		;;
-	/ext[234]/|/jffs2/|/btrfs/)
-		# A file ending in a supportted fs type is a rootfs image
-		if [ -z "$FSTYPE" -o "$FSTYPE" = "$EXT" ]; then
-		    FSTYPE=$EXT
-		    ROOTFS=$filename
-		else
-		    error "conflicting FSTYPE types [$FSTYPE] and [$EXT]"
-		fi
-		;;
-	/hddimg/|/hdddirect/|/vmdk/|/wic/|/qcow2/|/vdi/)
-		FSTYPE=$EXT
-		VM=$filename
-		ROOTFS=$filename
-		IS_VM="true"
-		;;
-	*)
-		error "unknown file arg [$filename]"
-		;;
-    esac
-}
-
-check_fstype_conflicts() {
-    if [ -z "$FSTYPE" -o "$FSTYPE" = "$1" ]; then
-        FSTYPE=$1
-    else
-        error "conflicting FSTYPE types [$FSTYPE] and [$1]"
-    fi
-}
-# Parse command line args without requiring specific ordering. It's a
-# bit more complex, but offers a great user experience.
-while true; do
-    arg=${1}
-    case "$arg" in
-        "qemux86" | "qemux86-64" | "qemuarm" | "qemuarm64" | "qemumips" | "qemumipsel" | \
-        "qemumips64" | "qemush4"  | "qemuppc" | "qemumicroblaze" | "qemuzynq" | "qemuzynqmp")
-            [ -z "$MACHINE" -o "$MACHINE" = "$arg" ] && MACHINE=$arg || \
-                error "conflicting MACHINE types [$MACHINE] and [$arg]"
-            ;;
-        "ext"[234] | "jffs2" | "nfs" | "btrfs")
-            check_fstype_conflicts $arg
-            ;;
-        "hddimg" | "hdddirect" | "wic" | "vmdk" | "qcow2" | "vdi" | "iso")
-            check_fstype_conflicts $arg
-            IS_VM="true"
-            ;;
-        "ramfs" | "cpio.gz")
-            FSTYPE=cpio.gz
-            ;;
-        "nographic")
-            SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -nographic"
-            SCRIPT_KERNEL_OPT="$SCRIPT_KERNEL_OPT console=ttyS0"
-            ;;
-        "serial")
-            SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -serial stdio"
-            SCRIPT_KERNEL_OPT="$SCRIPT_KERNEL_OPT console=ttyS0"
-            SERIALSTDIO="1"
-            ;;
-        "tcpserial="*)
-            TCPSERIAL_PORTNUM=${arg##tcpserial=}
-            ;;
-        "biosdir="*)
-            CUSTOMBIOSDIR="${arg##biosdir=}"
-	    ;;
-        "biosfilename="*)
-            SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -bios ${arg##biosfilename=}"
-            ;;
-        "qemuparams="*)
-            SCRIPT_QEMU_EXTRA_OPT="${arg##qemuparams=}"
-
-            # Warn user if they try to specify serial or kvm options
-            # to use simplified options instead
-            serial_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-serial\)'`
-            kvm_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-enable-kvm\)'`
-            vga_option=`expr "$SCRIPT_QEMU_EXTRA_OPT" : '.*\(-vga\)'`
-            [ ! -z "$serial_option" -o ! -z "$kvm_option" ] && \
-                echo "Please use simplified serial or kvm options instead"
-            ;;
-        "bootparams="*)
-            SCRIPT_KERNEL_OPT="$SCRIPT_KERNEL_OPT ${arg##bootparams=}"
-            ;;
-        "audio")
-            if [ "x$MACHINE" = "xqemux86" -o "x$MACHINE" = "xqemux86-64" ]; then
-                echo "Enabling audio in qemu."
-                echo "Please install snd_intel8x0 or snd_ens1370 driver in linux guest."
-                QEMU_AUDIO_DRV="alsa"
-                SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -soundhw ac97,es1370"
-            fi
-            ;;
-        "kvm")
-            KVM_ENABLED="yes"
-            KVM_CAPABLE=`grep -q 'vmx\|svm' /proc/cpuinfo && echo 1`
-            ;;
-        "kvm-vhost")
-            KVM_ENABLED="yes"
-            KVM_CAPABLE=`grep -q 'vmx\|svm' /proc/cpuinfo && echo 1`
-            VHOST_ENABLED="yes"
-            ;;
-        "slirp")
-            SLIRP_ENABLED="yes"
-            ;;
-        "publicvnc")
-            SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -vnc :0"
-            ;;
-        *-image*)
-            [ -z "$ROOTFS" ] || \
-        		error "conflicting ROOTFS args [$ROOTFS] and [$arg]"
-            if [ -f "$arg" ]; then
-                process_filename $arg
-            elif [ -d "$arg" ]; then
-                # Handle the case where the nfsroot dir has -image-
-                # in the pathname
-                echo "Assuming $arg is an nfs rootfs"
-                FSTYPE=nfs
-                ROOTFS=$arg
-            else
-                ROOTFS=$arg
-                LAZY_ROOTFS="true"
-            fi
-            ;;
-        "") break ;;
-        *)
-            # A directory name is an nfs rootfs
-            if [ -d "$arg" ]; then
-                echo "Assuming $arg is an nfs rootfs"
-                if [ -z "$FSTYPE" -o "$FSTYPE" = "nfs" ]; then
-                    FSTYPE=nfs
-                else
-                    error "conflicting FSTYPE types [$arg] and nfs"
-                fi
-
-                if [ -z "$ROOTFS" ]; then
-                    ROOTFS=$arg
-                else
-                    error "conflicting ROOTFS args [$ROOTFS] and [$arg]"
-                fi
-            elif [ -f "$arg" ]; then
-                process_filename $arg
-            else
-                error "unable to classify arg [$arg]"
-            fi
-            ;;
-    esac
-    shift
-done
-
-if [ ! -c /dev/net/tun ] ; then
-	echo "TUN control device /dev/net/tun is unavailable; you may need to enable TUN (e.g. sudo modprobe tun)"
-	exit 1
-elif [ ! -w /dev/net/tun ] ; then
-	echo "TUN control device /dev/net/tun is not writable, please fix (e.g. sudo chmod 666 /dev/net/tun)"
-	exit 1
-fi
-
-# Report errors for missing combinations of options
-if [ -z "$MACHINE" -a -z "$KERNEL" -a -z "$VM" -a "$FSTYPE" != "wic" ]; then
-    error "you must specify at least a MACHINE or KERNEL argument"
-fi
-if [ "$FSTYPE" = "nfs" -a -z "$ROOTFS" ]; then
-    error "NFS booting without an explicit ROOTFS path is not yet supported"
-fi
-
-if [ -z "$MACHINE" ]; then
-    if [ "$IS_VM" = "true" ]; then
-        [ "x$FSTYPE" = "xwic" ] && filename=$ROOTFS || filename=$VM
-        MACHINE=`basename $filename | sed -n 's/.*\(qemux86-64\|qemux86\|qemuarm64\|qemuarm\|qemumips64\|qemumips\|qemuppc\|qemush4\).*/\1/p'`
-        if [ -z "$MACHINE" ]; then
-            error "Unable to set MACHINE from image filename [$VM]"
-        fi
-        echo "Set MACHINE to [$MACHINE] based on image [$VM]"
-    else
-        MACHINE=`basename $KERNEL | sed -n 's/.*\(qemux86-64\|qemux86\|qemuarm64\|qemuarm\|qemumips64\|qemumips\|qemuppc\|qemush4\).*/\1/p'`
-        if [ -z "$MACHINE" ]; then
-            error "Unable to set MACHINE from kernel filename [$KERNEL]"
-        fi
-        echo "Set MACHINE to [$MACHINE] based on kernel [$KERNEL]"
-    fi
-fi
-
-YOCTO_KVM_WIKI="https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
-YOCTO_PARAVIRT_KVM_WIKI="https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
-# Detect KVM configuration
-if [ "x$KVM_ENABLED" = "xyes" ]; then
-    if [ -z "$KVM_CAPABLE" ]; then
-        echo "You are trying to enable KVM on a cpu without VT support."
-        echo "Remove kvm from the command-line, or refer"
-        echo "$YOCTO_KVM_WIKI";
-        exit 1;
-    fi
-    if [ "x$MACHINE" != "xqemux86" -a "x$MACHINE" != "xqemux86-64" ]; then
-        echo "KVM only support x86 & x86-64. Remove kvm from the command-line";
-        exit 1;
-    fi
-    if [ ! -e /dev/kvm ]; then
-        echo "Missing KVM device. Have you inserted kvm modules?"
-        echo "For further help see:"
-        echo "$YOCTO_KVM_WIKI";
-        exit 1;
-    fi
-    if [ -w /dev/kvm -a -r /dev/kvm ]; then
-        SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -enable-kvm"
-        KVM_ACTIVE="yes"
-    else
-        echo "You have no rights on /dev/kvm."
-        echo "Please change the ownership of this file as described at:"
-        echo "$YOCTO_KVM_WIKI";
-        exit 1;
-    fi
-    if [ "x$VHOST_ENABLED" = "xyes" ]; then
-        if [ ! -e /dev/vhost-net ]; then
-            echo "Missing virtio net device. Have you inserted vhost-net module?"
-            echo "For further help see:"
-            echo "$YOCTO_PARAVIRT_KVM_WIKI";
-            exit 1;
-        fi
-
-        if [ -w /dev/vhost-net -a -r /dev/vhost-net ]; then
-            VHOST_ACTIVE="yes"
-        else
-            echo "You have no rights on /dev/vhost-net."
-            echo "Please change the ownership of this file as described at:"
-            echo "$YOCTO_KVM_WIKI";
-            exit 1;
-        fi
-    fi
-fi
-
-machine2=`echo $MACHINE | tr 'a-z' 'A-Z' | sed 's/-/_/'`
-# MACHINE is now set for all cases
-
-# Defaults used when these vars need to be inferred
-QEMUX86_DEFAULT_KERNEL=bzImage-qemux86.bin
-QEMUX86_DEFAULT_FSTYPE=ext4
-
-QEMUX86_64_DEFAULT_KERNEL=bzImage-qemux86-64.bin
-QEMUX86_64_DEFAULT_FSTYPE=ext4
-
-QEMUARM_DEFAULT_KERNEL=zImage-qemuarm.bin
-QEMUARM_DEFAULT_FSTYPE=ext4
-
-QEMUARM64_DEFAULT_KERNEL=Image-qemuarm64.bin
-QEMUARM64_DEFAULT_FSTYPE=ext4
-
-QEMUMIPS_DEFAULT_KERNEL=vmlinux-qemumips.bin
-QEMUMIPS_DEFAULT_FSTYPE=ext4
-
-QEMUMIPSEL_DEFAULT_KERNEL=vmlinux-qemumipsel.bin
-QEMUMIPSEL_DEFAULT_FSTYPE=ext4
-
-QEMUMIPS64_DEFAULT_KERNEL=vmlinux-qemumips64.bin
-QEMUMIPS64_DEFAULT_FSTYPE=ext4
-
-QEMUSH4_DEFAULT_KERNEL=vmlinux-qemumips.bin
-QEMUSH4_DEFAULT_FSTYPE=ext4
-
-QEMUPPC_DEFAULT_KERNEL=vmlinux-qemuppc.bin
-QEMUPPC_DEFAULT_FSTYPE=ext4
-
-QEMUMICROBLAZE_DEFAULT_KERNEL=linux.bin.ub
-QEMUMICROBLAZE_DEFAULT_FSTYPE=cpio
-
-QEMUZYNQ_DEFAULT_KERNEL=uImage
-QEMUZYNQ_DEFAULT_FSTYPE=cpio
-
-QEMUZYNQMP_DEFAULT_KERNEL=Image
-QEMUZYNQMP_DEFAULT_FSTYPE=cpio
-
-setup_path_vars() {
-    if [ -z "$OE_TMPDIR" ] ; then
-        PATHS_REQUIRED=true
-    elif [ "$1" = "1" -a -z "$DEPLOY_DIR_IMAGE" ] ; then
-        PATHS_REQUIRED=true
-    else
-        PATHS_REQUIRED=false
-    fi
-
-    if [ "$PATHS_REQUIRED" = "true" ]; then
-        # Try to get the variable values from bitbake
-        type -P bitbake &>/dev/null || {
-            echo "In order for this script to dynamically infer paths";
-            echo "to kernels or filesystem images, you either need";
-            echo "bitbake in your PATH or to source oe-init-build-env";
-            echo "before running this script" >&2;
-            exit 1; }
-
-        # We have bitbake in PATH, get the variable values from bitbake
-        BITBAKE_ENV_TMPFILE=`mktemp --tmpdir runqemu.XXXXXXXXXX`
-        if [ "$?" != "0" ] ; then
-            echo "Error: mktemp failed for bitbake environment output"
-            exit 1
-        fi
-
-        MACHINE=$MACHINE bitbake -e > $BITBAKE_ENV_TMPFILE
-        if [ -z "$OE_TMPDIR" ] ; then
-            OE_TMPDIR=`sed -n 's/^TMPDIR=\"\(.*\)\"/\1/p' $BITBAKE_ENV_TMPFILE`
-        fi
-        if [ -z "$DEPLOY_DIR_IMAGE" ] ; then
-            DEPLOY_DIR_IMAGE=`sed -n 's/^DEPLOY_DIR_IMAGE=\"\(.*\)\"/\1/p' $BITBAKE_ENV_TMPFILE`
-        fi
-        if [ -z "$QEMU_DTB" ] ; then
-            QEMU_DTB=`sed -n 's/^QEMU_DTB=\"\(.*\)\"/\1/p' $BITBAKE_ENV_TMPFILE`
-        fi
-        if [ -z "$OE_TMPDIR" ]; then
-            # Check for errors from bitbake that the user needs to know about
-            BITBAKE_OUTPUT=`cat $BITBAKE_ENV_TMPFILE | wc -l`
-            if [ "$BITBAKE_OUTPUT" -eq "0" ]; then
-                echo "Error: this script needs to be run from your build directory, or you need"
-                echo "to explicitly set OE_TMPDIR and DEPLOY_DIR_IMAGE in your environment"
-            else
-                echo "There was an error running bitbake to determine TMPDIR"
-                echo "Here is the output from 'bitbake -e':"
-                cat $BITBAKE_ENV_TMPFILE
-            fi
-            rm $BITBAKE_ENV_TMPFILE
-            exit 1
-        fi
-        rm $BITBAKE_ENV_TMPFILE
-    fi
-}
-
-setup_sysroot() {
-    # Toolchain installs set up $OECORE_NATIVE_SYSROOT in their
-    # environment script. If that variable isn't set, we're
-    # either in an in-tree build scenario or the environment
-    # script wasn't source'd.
-    if [ -z "$OECORE_NATIVE_SYSROOT" ]; then
-        setup_path_vars
-        BUILD_ARCH=`uname -m`
-        BUILD_OS=`uname | tr '[A-Z]' '[a-z]'`
-        BUILD_SYS="$BUILD_ARCH-$BUILD_OS"
-
-        OECORE_NATIVE_SYSROOT=$OE_TMPDIR/sysroots/$BUILD_SYS
-    fi 
-
-    # Some recipes store the BIOS under $OE_TMPDIR/sysroots/$MACHINE,
-    # now defined as OECORE_MACHINE_SYSROOT. The latter is used when searching
-    # BIOS, VGA BIOS and keymaps.
-    if [ -z "$OECORE_MACHINE_SYSROOT" ]; then
-        OECORE_MACHINE_SYSROOT=$OE_TMPDIR/sysroots/$MACHINE
-    fi
-}
-
-# Locate a rootfs image to boot which matches our expected
-# machine and fstype. 
-findimage() {
-    where=$1
-    machine=$2
-    extension=$3
-
-    # Sort rootfs candidates by modification time - the most
-    # recently created one is the one we most likely want to boot.
-    filename=`ls -t1 $where/*-image*$machine.$extension 2>/dev/null | head -n1`
-    if [ "x$filename" != "x" ]; then
-        ROOTFS=$filename
-        return
-    fi
-
-    echo "Couldn't find a $machine rootfs image in $where."
-    exit 1
-}
-
-if [ -e "$ROOTFS" -a -z "$FSTYPE" ]; then
-    # Extract the filename extension
-    EXT=`echo $ROOTFS | awk -F . '{ print \$NF }'`
-    if [ "x$EXT" = "xext2" -o "x$EXT" = "xext3" -o \
-          "x$EXT" = "xjffs2" -o "x$EXT" = "xbtrfs" -o \
-          "x$EXT" = "xext4" ]; then
-        FSTYPE=$EXT
-    else
-        echo "Note: Unable to determine filesystem extension for $ROOTFS"
-        echo "We will use the default FSTYPE for $MACHINE"
-        # ...which is done further below...
-    fi
-fi
-
-if [ -z "$KERNEL" -a "$IS_VM" = "false" ]; then \
-    setup_path_vars 1
-    eval kernel_file=\$${machine2}_DEFAULT_KERNEL
-    KERNEL=$DEPLOY_DIR_IMAGE/$kernel_file
-
-    if [ -z "$KERNEL" ]; then
-        error "Unable to determine default kernel for MACHINE [$MACHINE]"
-    fi
-fi
-# KERNEL is now set for all cases
-
-if [ -z "$FSTYPE" ]; then
-    eval FSTYPE=\$${machine2}_DEFAULT_FSTYPE
-
-    if [ -z "$FSTYPE" ]; then
-        error "Unable to determine default fstype for MACHINE [$MACHINE]"
-    fi
-fi
-
-# FSTYPE is now set for all cases
-
-# Handle cases where a ROOTFS type is given instead of a filename, e.g.
-# core-image-sato
-if [ "$LAZY_ROOTFS" = "true" ]; then
-    setup_path_vars 1
-    echo "Assuming $ROOTFS really means $DEPLOY_DIR_IMAGE/$ROOTFS-$MACHINE.$FSTYPE"
-    if [ "$IS_VM" = "true" ]; then
-        VM=$DEPLOY_DIR_IMAGE/$ROOTFS-$MACHINE.$FSTYPE
-    else
-        ROOTFS=$DEPLOY_DIR_IMAGE/$ROOTFS-$MACHINE.$FSTYPE
-    fi
-fi
-
-if [ -z "$ROOTFS" ]; then
-    setup_path_vars 1
-    T=$DEPLOY_DIR_IMAGE
-    eval rootfs_list=\$${machine2}_DEFAULT_ROOTFS
-    findimage $T $MACHINE $FSTYPE
-
-    if [ -z "$ROOTFS" ]; then
-        error "Unable to determine default rootfs for MACHINE [$MACHINE]"
-    elif [ "$IS_VM" = "true" ]; then
-		VM=$ROOTFS
-    fi
-fi
-# ROOTFS is now set for all cases, now expand it to be an absolute path, it should exist at this point
-
-ROOTFS=`readlink -f $ROOTFS`
-
-echo ""
-echo "Continuing with the following parameters:"
-if [ "$IS_VM" = "false" ]; then
-    echo "KERNEL: [$KERNEL]"
-    echo "ROOTFS: [$ROOTFS]"
-else
-    echo "VM:   [$VM]"
-fi
-echo "FSTYPE: [$FSTYPE]"
-
-setup_sysroot
-# OECORE_NATIVE_SYSROOT and OECORE_MACHINE_SYSROOT are now set for all cases
-
-INTERNAL_SCRIPT="$0-internal"
-if [ ! -f "$INTERNAL_SCRIPT" -o ! -r "$INTERNAL_SCRIPT" ]; then
-INTERNAL_SCRIPT=`which runqemu-internal`
-fi
-
-# Specify directory for BIOS, VGA BIOS and keymaps
-if [ ! -z "$CUSTOMBIOSDIR" ]; then
-    if [ -d "$OECORE_NATIVE_SYSROOT/$CUSTOMBIOSDIR" ]; then
-        echo "Assuming biosdir is $OECORE_NATIVE_SYSROOT/$CUSTOMBIOSDIR"
-        SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -L $OECORE_NATIVE_SYSROOT/$CUSTOMBIOSDIR"
-    elif [ -d "$OECORE_MACHINE_SYSROOT/$CUSTOMBIOSDIR" ]; then
-        echo "Assuming biosdir is $OECORE_MACHINE_SYSROOT/$CUSTOMBIOSDIR"
-        SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -L $OECORE_MACHINE_SYSROOT/$CUSTOMBIOSDIR"
-    else
-        if [ ! -d "$CUSTOMBIOSDIR" ]; then
-            echo "Custom BIOS directory not found. Tried: $CUSTOMBIOSDIR"
-            echo "and $OECORE_NATIVE_SYSROOT/$CUSTOMBIOSDIR"
-            echo "and $OECORE_MACHINE_SYSROOT/$CUSTOMBIOSDIR"
-            exit 1;
-        fi
-        echo "Assuming biosdir is $CUSTOMBIOSDIR"
-        SCRIPT_QEMU_OPT="$SCRIPT_QEMU_OPT -L $CUSTOMBIOSDIR"
-    fi
-fi
-
-. $INTERNAL_SCRIPT
-exit $?
+  runqemu qemuarm
+  runqemu tmp/deploy/images/qemuarm
+  runqemu tmp/deploy/images/qemux86/qemuboot.py
+  runqemu qemux86-64 core-image-sato ext4
+  runqemu qemux86-64 wic-image-minimal wic
+  runqemu path/to/bzImage-qemux86.bin path/to/nfsrootdir/ serial
+  runqemu qemux86 iso/hddimg/vmdk/qcow2/vdi/ramfs/cpio.gz...
+  runqemu qemux86 qemuparams="-m 256"
+  runqemu qemux86 bootparams="psplash=false"
+  runqemu path/to/<image>-<machine>.vmdk
+  runqemu path/to/<image>-<machine>.wic
+""")
+
+def check_tun():
+    """Check /dev/net/run"""
+    dev_tun = '/dev/net/tun'
+    if not os.path.exists(dev_tun):
+        raise Exception("TUN control device %s is unavailable; you may need to enable TUN (e.g. sudo modprobe tun)" % dev_tun)
+
+    if not os.access(dev_tun, os.W_OK):
+        raise Exception("TUN control device %s is not writable, please fix (e.g. sudo chmod 666 %s)" % (dev_tun, dev_tun))
+
+
+def acquire_lock(lockfile):
+    lock = lockfile + '.lock'
+    logger.info("Acquiring lockfile %s..." % lock)
+    with open(lock, 'w') as f:
+        try:
+            fcntl.flock(f, fcntl.LOCK_EX|fcntl.LOCK_NB)
+        except Exception as e:
+            logger.info("Acquiring lockfile %s failed: %s" % (lock, e))
+            return False
+    return True
+
+def release_lock(lockfile):
+    lock = lockfile + '.lock'
+    with open(lock) as f:
+        fcntl.flock(f, fcntl.LOCK_UN)
+    os.remove(lock)
+
+
+class BaseConfig(object):
+    def __init__(self):
+        # Vars can be merged with qemuboot.py, use a dict to manage them.
+        self.d = {
+            'MACHINE': '',
+            'QEMU_OPT_SCRIPT': '',
+            'KERNEL_CMDLINE_SCRIPT': '',
+            'DEPLOY_DIR_IMAGE': '',
+            'KERNEL_ROOT': '/dev/vda',
+        }
+
+        self.qemu_opt = ''
+        self.nfs_dir = ''
+        self.clean_nfs_dir = False
+        self.nfs_server = ''
+        self.rootfs = ''
+        self.kernel = ''
+        self.kernel_cmdline = ''
+        self.fstype = ''
+        self.kvm_enabled = False
+        self.vhost_enabled = False
+        self.slirp_enabled = False
+        self.nfs_instance = 0
+        self.nfs_running = False
+        self.serialstdio = False
+        self.cleantap = False
+        self.saved_stty = ''
+        self.lockfile = ''
+        self.audio_enabled = False
+        self.tcpserial_portnum = ''
+        self.custombiosdir = ''
+        self.fstypes = ('ext2', 'ext3', 'ext4', 'jffs2', 'nfs', 'btrfs', 'cpio.gz', 'cpio', 'ramfs')
+        self.vmtypes = ('hddimg', 'hdddirect', 'wic', 'vmdk', 'qcow2', 'vdi', 'iso')
+
+    def get(self, key):
+        if key in self.d:
+            return self.d.get(key)
+        else:
+            return ''
+
+    def set(self, key, value):
+        self.d[key] = value
+
+    def append(self, key, appendvar):
+        """Append a value to d[key]"""
+        if not appendvar.startswith(' '):
+            logger.warn('Maybe invalid append value "%s"' % appendvar)
+        if key in self.d:
+            self.d[key] = self.d[key] + appendvar
+        else:
+            self.d[key] = appendvar
+
+    def check_arg_fstype(self, fst):
+        """Check and set FSTYPE"""
+        if fst not in self.fstypes + self.vmtypes:
+            logger.warn("Maybe unsupported FSTYPE: %s" % fst)
+        if not self.fstype or self.fstype == fst:
+            if fst == 'ramfs':
+                fst = 'cpio.gz'
+            self.fstype = fst
+        else:
+            raise Exception("Conflicting: FSTYPE %s and %s" % (self.fstype, fst))
+
+    def set_machine_deploy_dir(self, machine, deploy_dir_image):
+        """Set MACHINE and DEPLOY_DIR_IMAGE"""
+        logger.info('MACHINE: %s' % machine)
+        logger.info('DEPLOY_DIR_IMAGE: %s' % deploy_dir_image)
+        self.set("MACHINE", machine)
+        self.set("DEPLOY_DIR_IMAGE", deploy_dir_image)
+
+    def check_arg_nfs(self, p):
+        if os.path.isdir(p):
+            self.nfs_dir = p
+        else:
+            m = re.match('(.*):(.*)', p)
+            self.nfs_server = m.group(1)
+            self.nfs_dir = m.group(2)
+        self.rootfs = ""
+        self.check_arg_fstype('nfs')
+
+    def check_arg_path(self, p):
+        """
+        - Check whether it is qemuboot.py or contains qemuboot.py
+        - Check whether is a kernel file
+        - Check whether is a image file
+        - Check whether it is a nfs dir
+        """
+        if os.path.basename(p) == 'qemuboot.py':
+            machine = os.path.basename(os.path.dirname(p))
+            self.set_machine_deploy_dir(machine, os.path.dirname(p))
+        elif os.path.exists(os.path.join(p, 'qemuboot.py')):
+            machine = os.path.basename(p)
+            self.set_machine_deploy_dir(machine, p)
+        elif re.search('\.bin$', p) or re.search('bzImage', p) or \
+             re.search('zImage', p) or re.search('vmlinux', p) or \
+             re.search('fitImage', p) or re.search('uImage', p):
+            self.kernel =  p
+        elif (not os.path.isdir(p)) and re.search('-image-', p):
+            dirpath = os.path.dirname(p)
+            if os.path.exists('%s/qemuboot.py' % dirpath):
+                machine = os.path.basename(os.path.dirname(p))
+                self.set_machine_deploy_dir(machine, os.path.dirname(p))
+            self.rootfs =  p
+            m = re.search('.*\.(.*)$', p)
+            if m:
+                fst = m.group(1)
+                self.check_arg_fstype(fst)
+            else:
+                raise Exception("Can't find FSTYPE from: %s" % p)
+        elif os.path.isdir(p) or (re.search(':', arg) and re.search('/', arg)):
+            logger.info("Assuming %s is an nfs rootfs" % p)
+            self.check_arg_nfs(p)
+        else:
+            raise Exception("Unknown path arg %s" % p)
+
+    def check_arg_machine(self, arg):
+        """Check whether it is a machine"""
+        if self.get('MACHINE') and self.get('MACHINE') != arg or re.search('/', arg):
+            raise Exception("Unknown arg: %s" % arg)
+        elif self.get('MACHINE') == arg:
+            return
+        logger.info('Assuming MACHINE = %s' % arg)
+        cmd = 'MACHINE=%s bitbake -e' % arg
+        logger.info('Running %s...' % cmd)
+        bitbake_e = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        # bitbake -e doesn't report invalid MACHINE as an error, so
+        # let's check DEPLOY_DIR_IMAGE to make sure that it is a valid
+        # MACHINE.
+        s = re.search('^DEPLOY_DIR_IMAGE="(.*)"', bitbake_e, re.M)
+        if s:
+            deploy_dir_image = s.group(1)
+        else:
+            raise Exception("bitbake -e %s" % bitbake_e)
+        if os.path.isdir(deploy_dir_image):
+            qb = deploy_dir_image + '/qemuboot.py'
+            if os.path.exists(qb):
+                self.set_machine_deploy_dir(arg, deploy_dir_image)
+            else:
+                raise Exception("%s doesn't exist" % qb)
+        else:
+            raise Exception("Falied to set MACHINE to %s. Unknown arg: %s" % (arg, arg))
+
+    def check_args(self):
+        unknown_arg = ""
+        for arg in sys.argv[1:]:
+            if arg in self.fstypes + self.vmtypes:
+                self.check_arg_fstype(arg)
+            elif arg == 'nographic':
+                self.append('QEMU_OPT_SCRIPT', ' -nographic')
+                self.append('KERNEL_CMDLINE_SCRIPT', ' console=ttyS0')
+            elif arg == 'serial':
+                self.append('QEMU_OPT_SCRIPT', ' -serial stdio')
+                self.append('KERNEL_CMDLINE_SCRIPT', ' console=ttyS0')
+                self.serialstdio = True
+            elif arg == 'audio':
+                logger.info("Enabling audio in qemu")
+                logger.info("Please install sound drivers in linux host")
+                self.audio_enabled = True
+            elif arg == 'kvm':
+                self.kvm_enabled = True
+            elif arg == 'kvm-vhost':
+                self.vhost_enabled = True
+            elif arg == 'slirp':
+                self.slirp_enabled = True
+            elif arg == 'publicvnc':
+                self.append('QEMU_OPT_SCRIPT', ' -vnc :0')
+            elif arg.startswith('tcpserial='):
+                self.tcpserial_portnum = arg[len('tcpserial='):]
+            elif arg.startswith('biosdir='):
+                self.custombiosdir = arg[len('biosdir='):]
+            elif arg.startswith('biosfilename='):
+                self.append('QEMU_OPT_SCRIPT', ' -bios %s' % arg[len('biosfilename='):])
+            elif arg.startswith('qemuparams='):
+                self.append('QEMU_OPT_SCRIPT', ' %s' % arg[len('qemuparams='):])
+            elif arg.startswith('bootparams='):
+                self.append('KERNEL_CMDLINE_SCRIPT', ' %s' % arg[len('bootparams='):])
+            elif os.path.exists(arg) or (re.search(':', arg) and re.search('/', arg)):
+                self.check_arg_path(os.path.abspath(arg))
+            elif re.search('-image-', arg):
+                # Lazy rootfs
+                self.rootfs = arg
+            else:
+                # At last, assume is it the MACHINE
+                if (not unknown_arg) or unknown_arg == arg:
+                    unknown_arg = arg
+                else:
+                    raise Exception("Can't handle two unknown args: %s %s" % (unknown_arg, arg))
+        # Check to make sure it is a valid machine
+        if unknown_arg:
+            if self.get('MACHINE') == unknown_arg:
+                return
+            if not self.get('DEPLOY_DIR_IMAGE'):
+                # Trying to get DEPLOY_DIR_IMAGE from env.
+                p = os.getenv('DEPLOY_DIR_IMAGE')
+                if p and os.path.exists(os.path.join(p, 'qemuboot.py')):
+                    machine = os.path.basename(p)
+                    self.set_machine_deploy_dir(machine, p)
+                    if unknown_arg == machine:
+                        return
+            self.check_arg_machine(unknown_arg)
+
+    def check_kvm(self):
+        """Check kvm and kvm-host"""
+        if not (self.kvm_enabled or self.vhost_enabled):
+            self.append("QEMU_OPT_SCRIPT", ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU')))
+            return
+
+        if not self.get('QB_CPU_KVM'):
+            raise Exception("QB_CPU_KVM is NULL, this board doesn't support kvm")
+
+        self.append("QEMU_OPT_SCRIPT", ' %s %s' % (self.get('QB_MACHINE'), self.get('QB_CPU_KVM')))
+        yocto_kvm_wiki = "https://wiki.yoctoproject.org/wiki/How_to_enable_KVM_for_Poky_qemu"
+        yocto_paravirt_kvm_wiki = "https://wiki.yoctoproject.org/wiki/Running_an_x86_Yocto_Linux_image_under_QEMU_KVM"
+        dev_kvm = '/dev/kvm'
+        dev_vhost = '/dev/vhost-net'
+        with open('/proc/cpuinfo', 'r') as f:
+            kvm_cap = re.search('vmx|svm', "".join(f.readlines()))
+        if not kvm_cap:
+            logger.error("You are trying to enable KVM on a cpu without VT support.")
+            logger.error("Remove kvm from the command-line, or refer:")
+            raise Exception(yocto_kvm_wiki)
+
+        if not os.path.exists(dev_kvm):
+            logger.error("Missing KVM device. Have you inserted kvm modules?")
+            logger.error("For further help see:")
+            raise Exception(yocto_kvm_wiki)
+
+        if os.access(dev_kvm, os.W_OK|os.R_OK):
+            self.append('QEMU_OPT_SCRIPT', ' -enable-kvm')
+        else:
+            logger.error("You have no read or write permission on /dev/kvm.")
+            logger.error("Please change the ownership of this file as described at:")
+            raise Exception(yocto_kvm_wiki)
+
+        if self.vhost_enabled:
+            if not os.path.exists(dev_vhost):
+                logger.error("Missing virtio net device. Have you inserted vhost-net module?")
+                logger.error("For further help see:")
+                raise Exception(yocto_paravirt_kvm_wiki)
+
+        if not os.access(dev_kvm, os.W_OK|os.R_OK):
+                logger.error("You have no read or write permission on /dev/vhost-net.")
+                logger.error("Please change the ownership of this file as described at:")
+                raise Exception(yocto_kvm_wiki)
+
+    def check_fstype(self):
+        """Check and setup FSTYPE"""
+        if not self.fstype:
+            fstype = self.get('QB_DEFAULT_FSTYPE')
+            if fstype:
+                self.fstype = fstype
+            else:
+                raise Exception("FSTYPE is NULL!")
+
+    def check_rootfs(self):
+        """Check and set rootfs"""
+        rootfs = self.rootfs
+        if rootfs:
+            if not os.path.exists(rootfs):
+                # Lazy rootfs
+                rootfs = "%s/%s-%s.%s" % (self.get('DEPLOY_DIR_IMAGE'),
+                        self.rootfs, self.get('MACHINE'),
+                        self.fstype)
+        elif self.fstype == 'nfs':
+            return
+        else:
+            rootfs = '%s/%s.%s' % (self.get('DEPLOY_DIR_IMAGE'),
+                    self.get('IMAGE_LINK_NAME'), self.fstype)
+        if os.path.exists(rootfs):
+            self.rootfs = rootfs
+        else:
+            raise Exception("Can't find rootfs: %s" % rootfs)
+
+    def check_kernel(self):
+        """Check and set kernel, dtb"""
+        # The vm image doesn't need a kernel
+        if self.fstype in self.vmtypes:
+            return
+        kernel = self.kernel
+        if not kernel:
+            kernel = "%s/%s" % (self.get('DEPLOY_DIR_IMAGE'), self.get('QB_DEFAULT_KERNEL'))
+
+        if os.path.exists(kernel):
+            self.kernel = kernel
+        else:
+            raise Exception("KERNEL %s not found" % kernel)
+
+        dtb = self.get('QB_DTB')
+        if dtb:
+            dtb = "%s/%s" % (self.get('DEPLOY_DIR_IMAGE'), dtb)
+            if os.path.exists(dtb):
+                self.set('QB_DTB', '-dtb %s' % dtb)
+            else:
+                raise Exception("DTB %s not found" % dtb)
+
+
+    def check_biosdir(self):
+        """Check custombiosdir"""
+        if not self.custombiosdir:
+            return
+
+        biosdir = ""
+        biosdir_native = "%s/%s" % (self.get('STAGING_DIR_NATIVE'), self.custombiosdir)
+        biosdir_host = "%s/%s" % (self.get('STAGING_DIR_HOST'), self.custombiosdir)
+        for i in (self.custombiosdir, biosdir_native, biosdir_host):
+            if os.path.isdir(i):
+                biosdir = i
+                break
+
+        if biosdir:
+            logger.info("Assuming biosdir is: %s" % biosdir)
+            self.append('QEMU_OPT_SCRIPT', ' -L %s' % biosdir)
+        else:
+            logger.error("Custom BIOS directory not found. Tried: %s, %s, and %s" % (self.custombiosdir, biosdir_native, biosdir_host))
+            raise Exception("Invalid custombiosdir: %s" % self.custombiosdir)
+
+    def check_mem(self):
+        s = re.search('-m +([0-9]+)', self.get('QEMU_OPT_SCRIPT'))
+        if s:
+            self.set('QB_MEM', '-m %s' % s.group(1))
+        elif not self.get('QB_MEM'):
+            logger.info('QB_MEM is not set, use 512M by default')
+            self.set('QB_MEM', '-m 512')
+
+        self.append('KERNEL_CMDLINE_SCRIPT', ' mem=%s' % self.get('QB_MEM').replace('-m','').strip() + 'M')
+        self.append('QEMU_OPT_SCRIPT', ' %s' % self.get('QB_MEM'))
+
+    def check_tcpserial(self):
+        if self.tcpserial_portnum:
+            if self.get('TUNE_ARCH') == 'aarch64':
+                self.append('QEMU_OPT_SCRIPT', ' -device virtio-serial-device -chardev socket,id=virtcon,port=%s,host=127.0.0.1 -device virtconsole,chardev=virtcon' % self.tcpserial_portnum)
+            else:
+                self.append('QEMU_OPT_SCRIPT', ' -serial tcp:127.0.0.1:%s' % self.tcpserial_portnum)
+
+
+    def check_and_set(self):
+        """Check configs sanity and set when needed"""
+        check_tun()
+        # Check audio
+        if self.audio_enabled:
+            if not self.get('QB_AUDIO_DRV'):
+                raise Exception("QB_AUDIO_DRV is NULL, this board doesn't support audio")
+            if not self.get('QB_AUDIO_OPT'):
+                logger.warn('QB_AUDIO_OPT is NULL, you may need define it to make audio work')
+            else:
+                self.append('QEMU_OPT_SCRIPT', ' %s' % self.get('QB_AUDIO_OPT'))
+            os.putenv('QEMU_AUDIO_DRV', self.get('QB_AUDIO_DRV'))
+        else:
+            os.putenv('QEMU_AUDIO_DRV', 'none')
+
+        self.check_kvm()
+        self.check_fstype()
+        self.check_rootfs()
+        self.check_kernel()
+        self.check_biosdir()
+        self.check_mem()
+        self.check_tcpserial()
+
+    def import_qemuboot(self):
+        deploy_dir_image = self.get('DEPLOY_DIR_IMAGE')
+        if not deploy_dir_image:
+            raise Exception("DEPLOY_DIR_IMAGE is NULL!")
+        sys.path.insert(0, deploy_dir_image)
+        import qemuboot
+        for k in qemuboot.config_bsp:
+            if qemuboot.config_bsp[k]:
+                self.set(k, qemuboot.config_bsp[k])
+
+    def print_config(self):
+        logger.info('Continuing with the following parameters:\n')
+        if not self.fstype in self.vmtypes:
+            print('KERNEL: [%s]' % self.kernel)
+        print('MACHINE: [%s]' % self.get('MACHINE'))
+        print('FSTYPE: [%s]' % self.fstype)
+        if self.fstype  == 'nfs':
+            print('NFS_DIR: [%s]' % self.nfs_dir)
+        else:
+            print('ROOTFS: [%s]' % self.rootfs)
+        print('')
+
+    def weak_assign(self, var, value):
+        if not self.get(var):
+            self.set(var, value)
+
+    def setup_nfs(self):
+        if not self.nfs_server:
+            if self.slirp_enabled:
+                self.nfs_server = '10.0.2.2'
+            else:
+                self.nfs_server = '192.168.7.1'
+
+        nfs_instance = int(self.nfs_instance)
+
+        mountd_rpcport = 21111 + nfs_instance
+        nfsd_rpcport = 11111 + nfs_instance
+        nfsd_port = 3049 + 2 * nfs_instance
+        mountd_port = 3048 + 2 * nfs_instance
+        unfs_opts="nfsvers=3,port=%s,mountprog=%s,nfsprog=%s,udp,mountport=%s" % (nfsd_port, mountd_rpcport, nfsd_rpcport, mountd_port)
+        self.unfs_opts = unfs_opts
+
+        p = '%s/.runqemu-sdk/pseudo' % os.getenv('HOME')
+        os.putenv('PSEUDO_LOCALSTATEDIR', p)
+
+        # Extract .tar.bz2 or .tar.bz if no self.nfs_dir
+        if not self.nfs_dir:
+            src_prefix = '%s/%s' % (self.get('DEPLOY_DIR_IMAGE'), self.get('IMAGE_LINK_NAME'))
+            dest = "%s-nfsroot" % src_prefix
+            if os.path.exists('%s.pseudo_state' % dest):
+                logger.info('Use %s as NFS_DIR' % dest)
+                self.nfs_dir = dest
+            else:
+                src = ""
+                src1 = '%s.tar.bz2' % src_prefix
+                src2 = '%s.tar.gz' % src_prefix
+                if os.path.exists(src1):
+                    src = src1
+                elif os.path.exists(src2):
+                    src = src2
+                if not src:
+                    raise Exception("No NFS_DIR is set and can't find %s or %s to extract" % (src1, src2))
+                logger.info('NFS_DIR not found, extracting %s to %s' % (src, dest))
+                cmd = 'runqemu-extract-sdk %s %s' % (src, dest)
+                logger.info('Running %s...' % cmd)
+                if subprocess.call(cmd, shell=True) != 0:
+                    raise Exception('Failed to run %s' % cmd)
+                self.clean_nfs_dir = True
+                self.nfs_dir = dest
+
+        # Start the userspace NFS server
+        cmd = 'runqemu-export-rootfs restart %s' % self.nfs_dir
+        logger.info('Running %s...' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+        self.nfs_running = True
+
+
+    def setup_slirp(self):
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        if self.get('TUNE_ARCH') == 'aarch64':
+            raise Exception("aarch64 doesn't support slirp mode")
+        self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        self.set('QB_NETWORK_CMD', '')
+
+    def setup_tap(self):
+        """Setup tap"""
+
+        # This file is created when runqemu-gen-tapdevs creates a bank of tap
+        # devices, indicating that the user should not bring up new ones using
+        # sudo.
+        nosudo_flag = '/etc/runqemu-nosudo'
+        self.qemuifup = shutil.which('runqemu-ifup')
+        self.qemuifdown = shutil.which('runqemu-ifdown')
+        ip = shutil.which('ip')
+        lockdir = "/tmp/qemu-tap-locks"
+
+        if not (self.qemuifup and self.qemuifdown and ip):
+            raise Exception("runqemu-ifup, runqemu-ifdown or ip not found")
+
+        if not os.path.exists(lockdir):
+            os.mkdir(lockdir)
+
+        cmd = '%s link' % ip
+        logger.info('Running %s...' % cmd)
+        ip_link = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        # Matches line like: 6: tap0: <foo>
+        possibles = re.findall('^[1-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
+        tap = ""
+        use_preconf_tap = False
+        for p in possibles:
+            lockfile = os.path.join(lockdir, p)
+            if os.path.exists('%s.skip' % lockfile):
+                logger.info('Found %s.skip, skipping %s' % (lockfile, p))
+                continue
+            if acquire_lock(lockfile):
+                self.lockfile = lockfile
+                tap = p
+                logger.info("Using preconfigured tap device %s" % tap)
+                logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
+                use_preconf_tap = True
+                break
+
+        if not tap:
+            if os.path.exists(nosudo_flag):
+                logger.error("Error: There are no available tap devices to use for networking,")
+                logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
+                raise Exception("a new one with sudo.")
+
+            gid = os.getgid()
+            uid = os.getuid()
+            logger.info("Setting up tap interface under sudo")
+            cmd = 'sudo %s %s %s %s' % (self.qemuifup, uid, gid, self.get('STAGING_DIR_NATIVE'))
+            tap = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+            self.cleantap = True
+            logger.info('Created tap: %s' % tap)
+
+        self.tap = tap
+        n0 = tap[3:]
+        n1 = int(n0) * 2 + 1
+        n2 = n1 + 1
+        self.nfs_instance = n0
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        self.append("KERNEL_CMDLINE_SCRIPT", " ip=192.168.7.%s::192.168.7.%s:255.255.255.0" % (n2, n1))
+        qemu_tap_cmd = "-net tap,vlan=0,ifname=%s,script=no,downscript=no" % self.tap
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        if self.get('TUNE_ARCH') == 'aarch64':
+            qemu_network_cmd = '-netdev tap,id=net0,ifname=%s,script=no,downscript=no -device virtio-net-device,netdev=net0' % self.tap
+            self.rootfs_options = '-drive id=disk0,file=%s,if=none,format=raw -device virtio-blk-device,drive=disk0' % self.rootfs
+        elif self.get('TUNE_ARCH') == 'powerpc':
+            qemu_network_cmd = '%s ' % qemu_tap_cmd
+        else:
+            qemu_network_cmd = "-net nic,model=virtio %s " % qemu_tap_cmd
+        if self.vhost_enabled:
+            qemu_network_cmd += ',vhost=on'
+        self.weak_assign('QB_NETWORK_CMD', qemu_network_cmd)
+
+    def setup_network(self):
+        cmd = "stty -g"
+        self.saved_stty = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        if self.slirp_enabled:
+            self.setup_slirp()
+        else:
+            self.setup_tap()
+
+        if self.fstype in ('cpio.gz', 'cpio'):
+            self.set('QB_NETWORK_CMD', '')
+            self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
+            self.rootfs_options = '-initrd %s' % self.rootfs
+        else:
+            if self.fstype in self.vmtypes:
+                if self.fstype == 'iso':
+                    vm_drive = '-cdrom %s' % self.rootfs
+                else:
+                    cmd1 = "grep -q 'root=/dev/sd' %s" % self.rootfs
+                    cmd2 = "grep -q 'root=/dev/hd' %s" % self.rootfs
+                    if subprocess.call(cmd1, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = '-drive if=none,id=hd,file=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' % self.rootfs
+                    elif subprocess.call(cmd2, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = self.rootfs
+                    else:
+                        logger.warn("Can't detect drive type %s" % self.rootfs)
+                        logger.warn('Tring to use virtio block drive')
+                        vm_drive = '-drive if=virtio,file=%s' % self.rootfs
+                self.rootfs_options = '%s -no-reboot' % vm_drive
+            self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('KERNEL_ROOT'))
+
+        if self.fstype == 'nfs':
+            self.rootfs_options = ''
+            k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server, self.nfs_dir, self.unfs_opts)
+            self.kernel_cmdline = 'root=%s rw highres=off' % k_root
+
+        self.weak_assign('QB_ROOTFS_OPTIONS', self.rootfs_options)
+
+    def setup_final(self):
+        qemu_system = self.get('QB_SYSTEM_NAME')
+        if not qemu_system:
+            raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!")
+
+        qemu_bin = '%s/%s' % (self.get('STAGING_BINDIR_NATIVE'), qemu_system)
+        if not os.access(qemu_bin, os.X_OK):
+            raise Exception("No QEMU binary '%s' could be found" % qemu_bin)
+
+        self.qemu_opt = "%s %s %s %s %s %s" % (qemu_bin, self.get('QB_NETWORK_CMD'), self.get('QEMU_OPT_SCRIPT'), self.get('QB_ROOTFS_OPTIONS'), self.get('QB_DTB'), self.get('QB_OPT_APPEND'))
+
+        if self.serialstdio:
+            logger.info("Interrupt character is '^]'")
+            cmd = "stty intr ^]"
+            subprocess.call(cmd, shell=True)
+
+        first_serial = ""
+        if not re.search("-nographic", self.qemu_opt):
+            first_serial = "-serial mon:vc"
+        # We always want a ttyS1. Since qemu by default adds a serial
+        # port when nodefaults is not specified, it seems that all that
+        # would be needed is to make sure a "-serial" is there. However,
+        # it appears that when "-serial" is specified, it ignores the
+        # default serial port that is normally added.  So here we make
+        # sure to add two -serial if there are none. And only one if
+        # there is one -serial already.
+        serial_num = len(re.findall("-serial", self.qemu_opt))
+        if serial_num == 0:
+            self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
+        elif serial_num == 1:
+            self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
+
+    def start_qemu(self):
+        if self.kernel:
+            kernel_opts = "-kernel %s -append '%s %s %s'" % (self.kernel, self.kernel_cmdline, self.get('KERNEL_CMDLINE_SCRIPT'), self.get('QB_KERNEL_CMDLINE_APPEND'))
+        else:
+            kernel_opts = ""
+        cmd = "%s %s" % (self.qemu_opt, kernel_opts)
+        logger.info('Running %s' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+    def cleanup(self):
+        if self.cleantap:
+            cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap, self.get('STAGING_DIR_NATIVE'))
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+        if self.lockfile:
+            logger.info("Releasing lockfile of preconfigured tap device '%s'" % self.tap)
+            release_lock(self.lockfile)
+
+        if self.nfs_running:
+            logger.info("Shutting down the userspace NFS server...")
+            cmd = "runqemu-export-rootfs stop %s" % self.nfs_dir
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+
+        if self.saved_stty:
+            cmd = "stty %s" % self.saved_stty
+            subprocess.call(cmd, shell=True)
+
+        if self.clean_nfs_dir:
+            logger.info('Removing %s' % self.nfs_dir)
+            shutil.rmtree(self.nfs_dir)
+            shutil.rmtree('%s.pseudo_state' % self.nfs_dir)
+
+def main():
+    if len(sys.argv) == 1 or "help" in sys.argv:
+        print_usage()
+        return 0
+    config = BaseConfig()
+    config.check_args()
+    config.import_qemuboot()
+    config.check_and_set()
+    config.print_config()
+    try:
+        config.setup_network()
+        config.setup_final()
+        config.start_qemu()
+    finally:
+        config.cleanup()
+    return 0
+
+if __name__ == "__main__":
+    try:
+        ret = main()
+    except Exception as esc:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)
scripts/runqemu-internal deleted +0 -739

739 lines not on this page · raw message

Signature · 1 line
2.9.0
#9 lore raw
Quoted 8 lines · Robert Yang

Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

-- snip --

scripts/runqemu line 555

Quoted 7 lines
scripts/runqemu +7 -0
+
+
+    def setup_slirp(self):
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        if self.get('TUNE_ARCH') == 'aarch64':
+            raise Exception("aarch64 doesn't support slirp mode")

This doesn't seem quite right? because slirp works fine with the qemuzynqmp machine which is aarch64 (based on the patch you provided for meta-xilinx). This looks to be specific to the qemuarm64 machine?

Regards,
Nathan

Quoted 178 lines
scripts/runqemu +178 -0
+        self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        self.set('QB_NETWORK_CMD', '')
+
+    def setup_tap(self):
+        """Setup tap"""
+
+        # This file is created when runqemu-gen-tapdevs creates a bank of tap
+        # devices, indicating that the user should not bring up new ones using
+        # sudo.
+        nosudo_flag = '/etc/runqemu-nosudo'
+        self.qemuifup = shutil.which('runqemu-ifup')
+        self.qemuifdown = shutil.which('runqemu-ifdown')
+        ip = shutil.which('ip')
+        lockdir = "/tmp/qemu-tap-locks"
+
+        if not (self.qemuifup and self.qemuifdown and ip):
+            raise Exception("runqemu-ifup, runqemu-ifdown or ip not found")
+
+        if not os.path.exists(lockdir):
+            os.mkdir(lockdir)
+
+        cmd = '%s link' % ip
+        logger.info('Running %s...' % cmd)
+        ip_link = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        # Matches line like: 6: tap0: <foo>
+        possibles = re.findall('^[1-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
+        tap = ""
+        use_preconf_tap = False
+        for p in possibles:
+            lockfile = os.path.join(lockdir, p)
+            if os.path.exists('%s.skip' % lockfile):
+                logger.info('Found %s.skip, skipping %s' % (lockfile, p))
+                continue
+            if acquire_lock(lockfile):
+                self.lockfile = lockfile
+                tap = p
+                logger.info("Using preconfigured tap device %s" % tap)
+                logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
+                use_preconf_tap = True
+                break
+
+        if not tap:
+            if os.path.exists(nosudo_flag):
+                logger.error("Error: There are no available tap devices to use for networking,")
+                logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
+                raise Exception("a new one with sudo.")
+
+            gid = os.getgid()
+            uid = os.getuid()
+            logger.info("Setting up tap interface under sudo")
+            cmd = 'sudo %s %s %s %s' % (self.qemuifup, uid, gid, self.get('STAGING_DIR_NATIVE'))
+            tap = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+            self.cleantap = True
+            logger.info('Created tap: %s' % tap)
+
+        self.tap = tap
+        n0 = tap[3:]
+        n1 = int(n0) * 2 + 1
+        n2 = n1 + 1
+        self.nfs_instance = n0
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        self.append("KERNEL_CMDLINE_SCRIPT", " ip=192.168.7.%s::192.168.7.%s:255.255.255.0" % (n2, n1))
+        qemu_tap_cmd = "-net tap,vlan=0,ifname=%s,script=no,downscript=no" % self.tap
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        if self.get('TUNE_ARCH') == 'aarch64':
+            qemu_network_cmd = '-netdev tap,id=net0,ifname=%s,script=no,downscript=no -device virtio-net-device,netdev=net0' % self.tap
+            self.rootfs_options = '-drive id=disk0,file=%s,if=none,format=raw -device virtio-blk-device,drive=disk0' % self.rootfs
+        elif self.get('TUNE_ARCH') == 'powerpc':
+            qemu_network_cmd = '%s ' % qemu_tap_cmd
+        else:
+            qemu_network_cmd = "-net nic,model=virtio %s " % qemu_tap_cmd
+        if self.vhost_enabled:
+            qemu_network_cmd += ',vhost=on'
+        self.weak_assign('QB_NETWORK_CMD', qemu_network_cmd)
+
+    def setup_network(self):
+        cmd = "stty -g"
+        self.saved_stty = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        if self.slirp_enabled:
+            self.setup_slirp()
+        else:
+            self.setup_tap()
+
+        if self.fstype in ('cpio.gz', 'cpio'):
+            self.set('QB_NETWORK_CMD', '')
+            self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
+            self.rootfs_options = '-initrd %s' % self.rootfs
+        else:
+            if self.fstype in self.vmtypes:
+                if self.fstype == 'iso':
+                    vm_drive = '-cdrom %s' % self.rootfs
+                else:
+                    cmd1 = "grep -q 'root=/dev/sd' %s" % self.rootfs
+                    cmd2 = "grep -q 'root=/dev/hd' %s" % self.rootfs
+                    if subprocess.call(cmd1, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = '-drive if=none,id=hd,file=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' % self.rootfs
+                    elif subprocess.call(cmd2, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = self.rootfs
+                    else:
+                        logger.warn("Can't detect drive type %s" % self.rootfs)
+                        logger.warn('Tring to use virtio block drive')
+                        vm_drive = '-drive if=virtio,file=%s' % self.rootfs
+                self.rootfs_options = '%s -no-reboot' % vm_drive
+            self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('KERNEL_ROOT'))
+
+        if self.fstype == 'nfs':
+            self.rootfs_options = ''
+            k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server, self.nfs_dir, self.unfs_opts)
+            self.kernel_cmdline = 'root=%s rw highres=off' % k_root
+
+        self.weak_assign('QB_ROOTFS_OPTIONS', self.rootfs_options)
+
+    def setup_final(self):
+        qemu_system = self.get('QB_SYSTEM_NAME')
+        if not qemu_system:
+            raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!")
+
+        qemu_bin = '%s/%s' % (self.get('STAGING_BINDIR_NATIVE'), qemu_system)
+        if not os.access(qemu_bin, os.X_OK):
+            raise Exception("No QEMU binary '%s' could be found" % qemu_bin)
+
+        self.qemu_opt = "%s %s %s %s %s %s" % (qemu_bin, self.get('QB_NETWORK_CMD'), self.get('QEMU_OPT_SCRIPT'), self.get('QB_ROOTFS_OPTIONS'), self.get('QB_DTB'), self.get('QB_OPT_APPEND'))
+
+        if self.serialstdio:
+            logger.info("Interrupt character is '^]'")
+            cmd = "stty intr ^]"
+            subprocess.call(cmd, shell=True)
+
+        first_serial = ""
+        if not re.search("-nographic", self.qemu_opt):
+            first_serial = "-serial mon:vc"
+        # We always want a ttyS1. Since qemu by default adds a serial
+        # port when nodefaults is not specified, it seems that all that
+        # would be needed is to make sure a "-serial" is there. However,
+        # it appears that when "-serial" is specified, it ignores the
+        # default serial port that is normally added.  So here we make
+        # sure to add two -serial if there are none. And only one if
+        # there is one -serial already.
+        serial_num = len(re.findall("-serial", self.qemu_opt))
+        if serial_num == 0:
+            self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
+        elif serial_num == 1:
+            self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
+
+    def start_qemu(self):
+        if self.kernel:
+            kernel_opts = "-kernel %s -append '%s %s %s'" % (self.kernel, self.kernel_cmdline, self.get('KERNEL_CMDLINE_SCRIPT'), self.get('QB_KERNEL_CMDLINE_APPEND'))
+        else:
+            kernel_opts = ""
+        cmd = "%s %s" % (self.qemu_opt, kernel_opts)
+        logger.info('Running %s' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+    def cleanup(self):
+        if self.cleantap:
+            cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap, self.get('STAGING_DIR_NATIVE'))
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+        if self.lockfile:
+            logger.info("Releasing lockfile of preconfigured tap device '%s'" % self.tap)
+            release_lock(self.lockfile)
+
+        if self.nfs_running:
+            logger.info("Shutting down the userspace NFS server...")
+            cmd = "runqemu-export-rootfs stop %s" % self.nfs_dir
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+
+        if self.saved_stty:
+            cmd = "stty %s" % self.saved_stty
+            subprocess.call(cmd, shell=True)
+
+        if self.clean_nfs_dir:

scripts/runqemu line 743

Quoted 10 lines
scripts/runqemu +10 -0
+            logger.info('Removing %s' % self.nfs_dir)
+            shutil.rmtree(self.nfs_dir)
+            shutil.rmtree('%s.pseudo_state' % self.nfs_dir)
+
+def main():
+    if len(sys.argv) == 1 or "help" in sys.argv:
+        print_usage()
+        return 0
+    config = BaseConfig()
+    config.check_args()

When it fails to parse the args instead of showing the python exception info (with call stack, etc), it should show the exception message and the runqemu usage.

Regards,
Nathan

#10 lore raw
Quoted 12 lines · Nathan Rossi
Quoted 8 lines · Robert Yang

Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

-- snip --

Quoted 11 lines

scripts/runqemu line 555

Quoted 7 lines
scripts/runqemu +7 -0
+
+
+    def setup_slirp(self):
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        if self.get('TUNE_ARCH') == 'aarch64':
+            raise Exception("aarch64 doesn't support slirp mode")

This doesn't seem quite right? because slirp works fine with the qemuzynqmp machine which is aarch64 (based on the patch you provided for meta-xilinx). This looks to be specific to the qemuarm64 machine?

Yes, thanks for the testing.

When I first tested run qemuzynqmp, the following patch didn't get merged, so it didn't work with slirp:

commit e5c6a78db46192800669f1b392351f6b52f3e20c

Author:     Alistair Francis <[email protected]>
AuthorDate: Wed Jun 15 13:43:23 2016 -0700
Commit:     Richard Purdie <[email protected]>
CommitDate: Wed Aug 10 10:45:32 2016 +0100

runqemu: qemuzynqmp: Add Linux boot support

Add support to direct boot Linux instead of just booting u-boot.

And for qemuarm64, the old code:
QEMU_NETWORK_CMD="-netdev tap,id=net0,ifname=$TAP,script=no,downscript=no -device virtio-net-device,netdev=net0 "

It hardcoded TAP, and didn't work with slirp when I tested it, so I added the checking to avoid unexpected errors. Does anyone know how to boot qemuarm64 by slirp, please ?

I tested "runqemu qemuzynqmp slirp" just now, it works, so I will remove this checking in the repo.

For further work, if there are more bsps which can not be boot by slirp, maybe we can add a var like QB_SLIRP_SUPPORTED = "0" or "1", and default to 1, if the bsp sets '0' then error out.

Removed the checking, and updated in the repo:

if self.get('TUNE_ARCH') == 'aarch64':
raise Exception("aarch64 doesn't support slirp mode")

// Robert

Quoted 200 lines

Regards,
Nathan

Quoted 178 lines
scripts/runqemu +178 -0
+        self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        self.set('QB_NETWORK_CMD', '')
+
+    def setup_tap(self):
+        """Setup tap"""
+
+        # This file is created when runqemu-gen-tapdevs creates a bank of tap
+        # devices, indicating that the user should not bring up new ones using
+        # sudo.
+        nosudo_flag = '/etc/runqemu-nosudo'
+        self.qemuifup = shutil.which('runqemu-ifup')
+        self.qemuifdown = shutil.which('runqemu-ifdown')
+        ip = shutil.which('ip')
+        lockdir = "/tmp/qemu-tap-locks"
+
+        if not (self.qemuifup and self.qemuifdown and ip):
+            raise Exception("runqemu-ifup, runqemu-ifdown or ip not found")
+
+        if not os.path.exists(lockdir):
+            os.mkdir(lockdir)
+
+        cmd = '%s link' % ip
+        logger.info('Running %s...' % cmd)
+        ip_link = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        # Matches line like: 6: tap0: <foo>
+        possibles = re.findall('^[1-9]+: +(tap[0-9]+): <.*', ip_link, re.M)
+        tap = ""
+        use_preconf_tap = False
+        for p in possibles:
+            lockfile = os.path.join(lockdir, p)
+            if os.path.exists('%s.skip' % lockfile):
+                logger.info('Found %s.skip, skipping %s' % (lockfile, p))
+                continue
+            if acquire_lock(lockfile):
+                self.lockfile = lockfile
+                tap = p
+                logger.info("Using preconfigured tap device %s" % tap)
+                logger.info("If this is not intended, touch %s.skip to make runqemu skip %s." %(lockfile, tap))
+                use_preconf_tap = True
+                break
+
+        if not tap:
+            if os.path.exists(nosudo_flag):
+                logger.error("Error: There are no available tap devices to use for networking,")
+                logger.error("and I see %s exists, so I am not going to try creating" % nosudo_flag)
+                raise Exception("a new one with sudo.")
+
+            gid = os.getgid()
+            uid = os.getuid()
+            logger.info("Setting up tap interface under sudo")
+            cmd = 'sudo %s %s %s %s' % (self.qemuifup, uid, gid, self.get('STAGING_DIR_NATIVE'))
+            tap = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+            self.cleantap = True
+            logger.info('Created tap: %s' % tap)
+
+        self.tap = tap
+        n0 = tap[3:]
+        n1 = int(n0) * 2 + 1
+        n2 = n1 + 1
+        self.nfs_instance = n0
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        self.append("KERNEL_CMDLINE_SCRIPT", " ip=192.168.7.%s::192.168.7.%s:255.255.255.0" % (n2, n1))
+        qemu_tap_cmd = "-net tap,vlan=0,ifname=%s,script=no,downscript=no" % self.tap
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' % self.rootfs
+        if self.get('TUNE_ARCH') == 'aarch64':
+            qemu_network_cmd = '-netdev tap,id=net0,ifname=%s,script=no,downscript=no -device virtio-net-device,netdev=net0' % self.tap
+            self.rootfs_options = '-drive id=disk0,file=%s,if=none,format=raw -device virtio-blk-device,drive=disk0' % self.rootfs
+        elif self.get('TUNE_ARCH') == 'powerpc':
+            qemu_network_cmd = '%s ' % qemu_tap_cmd
+        else:
+            qemu_network_cmd = "-net nic,model=virtio %s " % qemu_tap_cmd
+        if self.vhost_enabled:
+            qemu_network_cmd += ',vhost=on'
+        self.weak_assign('QB_NETWORK_CMD', qemu_network_cmd)
+
+    def setup_network(self):
+        cmd = "stty -g"
+        self.saved_stty = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE).stdout.read().decode('utf-8')
+        if self.slirp_enabled:
+            self.setup_slirp()
+        else:
+            self.setup_tap()
+
+        if self.fstype in ('cpio.gz', 'cpio'):
+            self.set('QB_NETWORK_CMD', '')
+            self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
+            self.rootfs_options = '-initrd %s' % self.rootfs
+        else:
+            if self.fstype in self.vmtypes:
+                if self.fstype == 'iso':
+                    vm_drive = '-cdrom %s' % self.rootfs
+                else:
+                    cmd1 = "grep -q 'root=/dev/sd' %s" % self.rootfs
+                    cmd2 = "grep -q 'root=/dev/hd' %s" % self.rootfs
+                    if subprocess.call(cmd1, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = '-drive if=none,id=hd,file=%s -device virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' % self.rootfs
+                    elif subprocess.call(cmd2, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = self.rootfs
+                    else:
+                        logger.warn("Can't detect drive type %s" % self.rootfs)
+                        logger.warn('Tring to use virtio block drive')
+                        vm_drive = '-drive if=virtio,file=%s' % self.rootfs
+                self.rootfs_options = '%s -no-reboot' % vm_drive
+            self.kernel_cmdline = 'root=%s rw highres=off' % (self.get('KERNEL_ROOT'))
+
+        if self.fstype == 'nfs':
+            self.rootfs_options = ''
+            k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server, self.nfs_dir, self.unfs_opts)
+            self.kernel_cmdline = 'root=%s rw highres=off' % k_root
+
+        self.weak_assign('QB_ROOTFS_OPTIONS', self.rootfs_options)
+
+    def setup_final(self):
+        qemu_system = self.get('QB_SYSTEM_NAME')
+        if not qemu_system:
+            raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!")
+
+        qemu_bin = '%s/%s' % (self.get('STAGING_BINDIR_NATIVE'), qemu_system)
+        if not os.access(qemu_bin, os.X_OK):
+            raise Exception("No QEMU binary '%s' could be found" % qemu_bin)
+
+        self.qemu_opt = "%s %s %s %s %s %s" % (qemu_bin, self.get('QB_NETWORK_CMD'), self.get('QEMU_OPT_SCRIPT'), self.get('QB_ROOTFS_OPTIONS'), self.get('QB_DTB'), self.get('QB_OPT_APPEND'))
+
+        if self.serialstdio:
+            logger.info("Interrupt character is '^]'")
+            cmd = "stty intr ^]"
+            subprocess.call(cmd, shell=True)
+
+        first_serial = ""
+        if not re.search("-nographic", self.qemu_opt):
+            first_serial = "-serial mon:vc"
+        # We always want a ttyS1. Since qemu by default adds a serial
+        # port when nodefaults is not specified, it seems that all that
+        # would be needed is to make sure a "-serial" is there. However,
+        # it appears that when "-serial" is specified, it ignores the
+        # default serial port that is normally added.  So here we make
+        # sure to add two -serial if there are none. And only one if
+        # there is one -serial already.
+        serial_num = len(re.findall("-serial", self.qemu_opt))
+        if serial_num == 0:
+            self.qemu_opt += " %s %s" % (first_serial, self.get("QB_SERIAL_OPT"))
+        elif serial_num == 1:
+            self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
+
+    def start_qemu(self):
+        if self.kernel:
+            kernel_opts = "-kernel %s -append '%s %s %s'" % (self.kernel, self.kernel_cmdline, self.get('KERNEL_CMDLINE_SCRIPT'), self.get('QB_KERNEL_CMDLINE_APPEND'))
+        else:
+            kernel_opts = ""
+        cmd = "%s %s" % (self.qemu_opt, kernel_opts)
+        logger.info('Running %s' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+    def cleanup(self):
+        if self.cleantap:
+            cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap, self.get('STAGING_DIR_NATIVE'))
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+        if self.lockfile:
+            logger.info("Releasing lockfile of preconfigured tap device '%s'" % self.tap)
+            release_lock(self.lockfile)
+
+        if self.nfs_running:
+            logger.info("Shutting down the userspace NFS server...")
+            cmd = "runqemu-export-rootfs stop %s" % self.nfs_dir
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+
+        if self.saved_stty:
+            cmd = "stty %s" % self.saved_stty
+            subprocess.call(cmd, shell=True)
+
+        if self.clean_nfs_dir:

scripts/runqemu line 743

Quoted 10 lines
scripts/runqemu +10 -0
+            logger.info('Removing %s' % self.nfs_dir)
+            shutil.rmtree(self.nfs_dir)
+            shutil.rmtree('%s.pseudo_state' % self.nfs_dir)
+
+def main():
+    if len(sys.argv) == 1 or "help" in sys.argv:
+        print_usage()
+        return 0
+    config = BaseConfig()
+    config.check_args()

When it fails to parse the args instead of showing the python exception info (with call stack, etc), it should show the exception message and the runqemu usage.

Regards,
Nathan

#11 lore raw
Quoted 48 lines · Robert Yang
Quoted 15 lines · Nathan Rossi
Quoted 9 lines · Robert Yang

Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

-- snip --

Quoted 12 lines

Review

Quoted 7 lines
(quoted diff) +7 -0
+
+
+    def setup_slirp(self):
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        if self.get('TUNE_ARCH') == 'aarch64':
+            raise Exception("aarch64 doesn't support slirp mode")

This doesn't seem quite right? because slirp works fine with the qemuzynqmp machine which is aarch64 (based on the patch you provided for meta-xilinx). This looks to be specific to the qemuarm64 machine?

Yes, thanks for the testing.

When I first tested run qemuzynqmp, the following patch didn't get merged, so it didn't work with slirp:

commit e5c6a78db46192800669f1b392351f6b52f3e20c

Author:     Alistair Francis <[email protected]>
AuthorDate: Wed Jun 15 13:43:23 2016 -0700
Commit:     Richard Purdie <[email protected]>
CommitDate: Wed Aug 10 10:45:32 2016 +0100

runqemu: qemuzynqmp: Add Linux boot support

Add support to direct boot Linux instead of just booting u-boot.

Quoted 7 lines

And for qemuarm64, the old code:
QEMU_NETWORK_CMD="-netdev tap,id=net0,ifname=$TAP,script=no,downscript=no -device virtio-net-device,netdev=net0 "

It hardcoded TAP, and didn't work with slirp when I tested it, so I added the checking to avoid unexpected errors. Does anyone know how to boot qemuarm64 by slirp, please ?

I was able to boot qemuarm64 with slirp, here is a patch (its a quick hack specific for qemuarm64).

scripts/runqemu +0 -1
index 7633bcb..ccf46a9 100755
@@ -552,8 +552,9 @@ class BaseConfig(object):
         if self.fstype == 'nfs':
             self.setup_nfs()
         self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
-        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %

self.rootfs
- self.set('QB_NETWORK_CMD', '')
+ qemu_network_cmd = '-netdev user,id=net0 -device
virtio-net-device,netdev=net0'
+ self.rootfs_options = '-drive
id=disk0,file=%s,if=none,format=raw -device
virtio-blk-device,drive=disk0' % self.rootfs
+ self.set('QB_NETWORK_CMD', qemu_network_cmd)

     def setup_tap(self):
         """Setup tap"""

Note the rootfs_options set, it appears this is in the setup_tap as well, and is required to get the disk to appear. Might need to refactor the drive setup into the "setup_final"? or a setup_disk/rootfs function?

Quoted 7 lines

I tested "runqemu qemuzynqmp slirp" just now, it works, so I will remove this checking in the repo.

For further work, if there are more bsps which can not be boot by slirp, maybe we can add a var like QB_SLIRP_SUPPORTED = "0" or "1", and default to 1, if the bsp sets '0' then error out.

It might be worth having a QB_SLIRP_CMD = "", this would allow machines to setup the args for slirp/user mode networking and tap networking separately.

Quoted 246 lines

Removed the checking, and updated in the repo:

if self.get('TUNE_ARCH') == 'aarch64':
raise Exception("aarch64 doesn't support slirp mode")

// Robert

Quoted 237 lines

Regards,
Nathan

Quoted 214 lines
(quoted diff) +2 -0
+        self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %

self.rootfs

(quoted diff) +6 -0
+        self.set('QB_NETWORK_CMD', '')
+
+    def setup_tap(self):
+        """Setup tap"""
+
+        # This file is created when runqemu-gen-tapdevs creates a bank

of tap
+ # devices, indicating that the user should not bring up new ones
using

(quoted diff) +9 -0
+        # sudo.
+        nosudo_flag = '/etc/runqemu-nosudo'
+        self.qemuifup = shutil.which('runqemu-ifup')
+        self.qemuifdown = shutil.which('runqemu-ifdown')
+        ip = shutil.which('ip')
+        lockdir = "/tmp/qemu-tap-locks"
+
+        if not (self.qemuifup and self.qemuifdown and ip):
+            raise Exception("runqemu-ifup, runqemu-ifdown or ip not

found")

(quoted diff) +7 -0
+
+        if not os.path.exists(lockdir):
+            os.mkdir(lockdir)
+
+        cmd = '%s link' % ip
+        logger.info('Running %s...' % cmd)
+        ip_link = subprocess.Popen(cmd, shell=True,

stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +2 -0
+        # Matches line like: 6: tap0: <foo>
+        possibles = re.findall('^[1-9]+: +(tap[0-9]+): <.*', ip_link,

re.M)

(quoted diff) +6 -0
+        tap = ""
+        use_preconf_tap = False
+        for p in possibles:
+            lockfile = os.path.join(lockdir, p)
+            if os.path.exists('%s.skip' % lockfile):
+                logger.info('Found %s.skip, skipping %s' % (lockfile,

p))

(quoted diff) +6 -0
+                continue
+            if acquire_lock(lockfile):
+                self.lockfile = lockfile
+                tap = p
+                logger.info("Using preconfigured tap device %s" % tap)
+                logger.info("If this is not intended, touch %s.skip to

make runqemu skip %s." %(lockfile, tap))

(quoted diff) +6 -0
+                use_preconf_tap = True
+                break
+
+        if not tap:
+            if os.path.exists(nosudo_flag):
+                logger.error("Error: There are no available tap devices

to use for networking,")
+ logger.error("and I see %s exists, so I am not going to
try creating" % nosudo_flag)

(quoted diff) +6 -0
+                raise Exception("a new one with sudo.")
+
+            gid = os.getgid()
+            uid = os.getuid()
+            logger.info("Setting up tap interface under sudo")
+            cmd = 'sudo %s %s %s %s' % (self.qemuifup, uid, gid,

self.get('STAGING_DIR_NATIVE'))
+ tap = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +11 -0
+            self.cleantap = True
+            logger.info('Created tap: %s' % tap)
+
+        self.tap = tap
+        n0 = tap[3:]
+        n1 = int(n0) * 2 + 1
+        n2 = n1 + 1
+        self.nfs_instance = n0
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        self.append("KERNEL_CMDLINE_SCRIPT", "

ip=192.168.7.%s::192.168.7.%s:255.255.255.0" % (n2, n1))
+ qemu_tap_cmd = "-net
tap,vlan=0,ifname=%s,script=no,downscript=no" % self.tap
+ self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %
self.rootfs

(quoted diff) +2 -0
+        if self.get('TUNE_ARCH') == 'aarch64':
+            qemu_network_cmd = '-netdev

tap,id=net0,ifname=%s,script=no,downscript=no -device virtio-net-device,netdev=net0' % self.tap
+ self.rootfs_options = '-drive
id=disk0,file=%s,if=none,format=raw -device virtio-blk-device,drive=disk0' % self.rootfs

(quoted diff) +4 -0
+        elif self.get('TUNE_ARCH') == 'powerpc':
+            qemu_network_cmd = '%s ' % qemu_tap_cmd
+        else:
+            qemu_network_cmd = "-net nic,model=virtio %s " %

qemu_tap_cmd

(quoted diff) +7 -0
+        if self.vhost_enabled:
+            qemu_network_cmd += ',vhost=on'
+        self.weak_assign('QB_NETWORK_CMD', qemu_network_cmd)
+
+    def setup_network(self):
+        cmd = "stty -g"
+        self.saved_stty = subprocess.Popen(cmd, shell=True,

stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +19 -0
+        if self.slirp_enabled:
+            self.setup_slirp()
+        else:
+            self.setup_tap()
+
+        if self.fstype in ('cpio.gz', 'cpio'):
+            self.set('QB_NETWORK_CMD', '')
+            self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
+            self.rootfs_options = '-initrd %s' % self.rootfs
+        else:
+            if self.fstype in self.vmtypes:
+                if self.fstype == 'iso':
+                    vm_drive = '-cdrom %s' % self.rootfs
+                else:
+                    cmd1 = "grep -q 'root=/dev/sd' %s" % self.rootfs
+                    cmd2 = "grep -q 'root=/dev/hd' %s" % self.rootfs
+                    if subprocess.call(cmd1, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = '-drive if=none,id=hd,file=%s -device

virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' % self.rootfs

(quoted diff) +5 -0
+                    elif subprocess.call(cmd2, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = self.rootfs
+                    else:
+                        logger.warn("Can't detect drive type %s" %

self.rootfs)

(quoted diff) +2 -0
+                        logger.warn('Tring to use virtio block drive')
+                        vm_drive = '-drive if=virtio,file=%s' %

self.rootfs

(quoted diff) +2 -0
+                self.rootfs_options = '%s -no-reboot' % vm_drive
+            self.kernel_cmdline = 'root=%s rw highres=off' %

(self.get('KERNEL_ROOT'))

(quoted diff) +4 -0
+
+        if self.fstype == 'nfs':
+            self.rootfs_options = ''
+            k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server,

self.nfs_dir, self.unfs_opts)

(quoted diff) +10 -0
+            self.kernel_cmdline = 'root=%s rw highres=off' % k_root
+
+        self.weak_assign('QB_ROOTFS_OPTIONS', self.rootfs_options)
+
+    def setup_final(self):
+        qemu_system = self.get('QB_SYSTEM_NAME')
+        if not qemu_system:
+            raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!")
+
+        qemu_bin = '%s/%s' % (self.get('STAGING_BINDIR_NATIVE'),

qemu_system)

(quoted diff) +2 -0
+        if not os.access(qemu_bin, os.X_OK):
+            raise Exception("No QEMU binary '%s' could be found" %

qemu_bin)

(quoted diff) +2 -0
+
+        self.qemu_opt = "%s %s %s %s %s %s" % (qemu_bin,

self.get('QB_NETWORK_CMD'), self.get('QEMU_OPT_SCRIPT'), self.get('QB_ROOTFS_OPTIONS'), self.get('QB_DTB'), self.get('QB_OPT_APPEND'))

(quoted diff) +19 -0
+
+        if self.serialstdio:
+            logger.info("Interrupt character is '^]'")
+            cmd = "stty intr ^]"
+            subprocess.call(cmd, shell=True)
+
+        first_serial = ""
+        if not re.search("-nographic", self.qemu_opt):
+            first_serial = "-serial mon:vc"
+        # We always want a ttyS1. Since qemu by default adds a serial
+        # port when nodefaults is not specified, it seems that all that
+        # would be needed is to make sure a "-serial" is there. However,
+        # it appears that when "-serial" is specified, it ignores the
+        # default serial port that is normally added.  So here we make
+        # sure to add two -serial if there are none. And only one if
+        # there is one -serial already.
+        serial_num = len(re.findall("-serial", self.qemu_opt))
+        if serial_num == 0:
+            self.qemu_opt += " %s %s" % (first_serial,

self.get("QB_SERIAL_OPT"))

(quoted diff) +6 -0
+        elif serial_num == 1:
+            self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
+
+    def start_qemu(self):
+        if self.kernel:
+            kernel_opts = "-kernel %s -append '%s %s %s'" %

(self.kernel, self.kernel_cmdline, self.get('KERNEL_CMDLINE_SCRIPT'), self.get('QB_KERNEL_CMDLINE_APPEND'))

(quoted diff) +10 -0
+        else:
+            kernel_opts = ""
+        cmd = "%s %s" % (self.qemu_opt, kernel_opts)
+        logger.info('Running %s' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+    def cleanup(self):
+        if self.cleantap:
+            cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap,

self.get('STAGING_DIR_NATIVE'))

(quoted diff) +4 -0
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+        if self.lockfile:
+            logger.info("Releasing lockfile of preconfigured tap device

'%s'" % self.tap)

(quoted diff) +13 -0
+            release_lock(self.lockfile)
+
+        if self.nfs_running:
+            logger.info("Shutting down the userspace NFS server...")
+            cmd = "runqemu-export-rootfs stop %s" % self.nfs_dir
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+
+        if self.saved_stty:
+            cmd = "stty %s" % self.saved_stty
+            subprocess.call(cmd, shell=True)
+
+        if self.clean_nfs_dir:

Review

Quoted 10 lines
(quoted diff) +10 -0
+            logger.info('Removing %s' % self.nfs_dir)
+            shutil.rmtree(self.nfs_dir)
+            shutil.rmtree('%s.pseudo_state' % self.nfs_dir)
+
+def main():
+    if len(sys.argv) == 1 or "help" in sys.argv:
+        print_usage()
+        return 0
+    config = BaseConfig()
+    config.check_args()

When it fails to parse the args instead of showing the python exception info (with call stack, etc), it should show the exception message and the runqemu usage.

Regards,
Nathan

You may not have seen this comment, since I accidentally put two "Regards," in my previous email.

Regards,
Nathan

#12 lore raw
Quoted 72 lines · Nathan Rossi
Quoted 48 lines · Robert Yang
Quoted 15 lines · Nathan Rossi
Quoted 9 lines · Robert Yang

Previously, runqemu had hard coded machine knowledge, which limited its usage, for example, qemu can boot genericx86, but runqemu can't, we need edit runqemu/runqemu-internal a lot if we want to boot genericx86.

Now bsp conf files can set vars to make it can be boot by runqemu, and qemuboot.bbclass will save these info to DEPLOY_DIR_IMAGE/qemuboot.py. Please see qemuboot.bbclass' comments on how to set the vars.

-- snip --

Quoted 12 lines

Review

Quoted 7 lines
(quoted diff) +7 -0
+
+
+    def setup_slirp(self):
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        if self.get('TUNE_ARCH') == 'aarch64':
+            raise Exception("aarch64 doesn't support slirp mode")

This doesn't seem quite right? because slirp works fine with the qemuzynqmp machine which is aarch64 (based on the patch you provided for meta-xilinx). This looks to be specific to the qemuarm64 machine?

Yes, thanks for the testing.

When I first tested run qemuzynqmp, the following patch didn't get merged, so it didn't work with slirp:

commit e5c6a78db46192800669f1b392351f6b52f3e20c

Author:     Alistair Francis <[email protected]>
AuthorDate: Wed Jun 15 13:43:23 2016 -0700
Commit:     Richard Purdie <[email protected]>
CommitDate: Wed Aug 10 10:45:32 2016 +0100

runqemu: qemuzynqmp: Add Linux boot support

Add support to direct boot Linux instead of just booting u-boot.

Quoted 7 lines

And for qemuarm64, the old code:
QEMU_NETWORK_CMD="-netdev tap,id=net0,ifname=$TAP,script=no,downscript=no -device virtio-net-device,netdev=net0 "

It hardcoded TAP, and didn't work with slirp when I tested it, so I added the checking to avoid unexpected errors. Does anyone know how to boot qemuarm64 by slirp, please ?

I was able to boot qemuarm64 with slirp, here is a patch (its a quick hack specific for qemuarm64).

scripts/runqemu +0 -1
index 7633bcb..ccf46a9 100755
@@ -552,8 +552,9 @@ class BaseConfig(object):
         if self.fstype == 'nfs':
             self.setup_nfs()
         self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
-        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %

self.rootfs

scripts/runqemu +1 -1
-        self.set('QB_NETWORK_CMD', '')
+        qemu_network_cmd = '-netdev user,id=net0 -device
Quoted 5 lines

virtio-net-device,netdev=net0'
+ self.rootfs_options = '-drive
id=disk0,file=%s,if=none,format=raw -device
virtio-blk-device,drive=disk0' % self.rootfs
+ self.set('QB_NETWORK_CMD', qemu_network_cmd)

Cool, this can boot aarch64 bsp, though it fails on other archs' bsps such as qemuarm, qemux86, we can use QB_SLIRP_CMD as you suggested to fix the problem.

$ runqemu nographic tmp/deploy/images/qemuarm slirp
[snip]
qemu-system-arm: -device virtio-net-device,netdev=net0: No 'virtio-bus' bus found for device 'virtio-net-device'
[snip]
Quoted 8 lines
     def setup_tap(self):
         """Setup tap"""

Note the rootfs_options set, it appears this is in the setup_tap as well, and is required to get the disk to appear. Might need to refactor the drive setup into the "setup_final"? or a setup_disk/rootfs function?

Set rootfs_options in setup_final() was what I had did before, but it would make code more complicated, the problem is slirp, tap, cpio, nfs, ext2/3/4, iso and vmdk have different rootfs_options, and plus aarch64 is special, so if we don't set it when we check each of them, and move the set to setup_final(), then we have to do the check again.

Quoted 5 lines
Quoted 5 lines

I tested "runqemu qemuzynqmp slirp" just now, it works, so I will remove this checking in the repo.

Quoted 7 lines
Quoted 3 lines

For further work, if there are more bsps which can not be boot by slirp, maybe we can add a var like QB_SLIRP_SUPPORTED = "0" or "1", and default to 1, if the bsp sets '0' then error out.

It might be worth having a QB_SLIRP_CMD = "", this would allow machines to setup the args for slirp/user mode networking and tap networking separately.

See above, sounds good, will do.

Quoted 244 lines
Quoted 244 lines

Removed the checking, and updated in the repo:

if self.get('TUNE_ARCH') == 'aarch64':
raise Exception("aarch64 doesn't support slirp mode")

// Robert

Quoted 234 lines

Regards,
Nathan

Quoted 214 lines
(quoted diff) +2 -0
+        self.append('KERNEL_CMDLINE_SCRIPT', ' ip=dhcp')
+        self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %

self.rootfs

(quoted diff) +6 -0
+        self.set('QB_NETWORK_CMD', '')
+
+    def setup_tap(self):
+        """Setup tap"""
+
+        # This file is created when runqemu-gen-tapdevs creates a bank

of tap
+ # devices, indicating that the user should not bring up new ones
using

(quoted diff) +9 -0
+        # sudo.
+        nosudo_flag = '/etc/runqemu-nosudo'
+        self.qemuifup = shutil.which('runqemu-ifup')
+        self.qemuifdown = shutil.which('runqemu-ifdown')
+        ip = shutil.which('ip')
+        lockdir = "/tmp/qemu-tap-locks"
+
+        if not (self.qemuifup and self.qemuifdown and ip):
+            raise Exception("runqemu-ifup, runqemu-ifdown or ip not

found")

(quoted diff) +7 -0
+
+        if not os.path.exists(lockdir):
+            os.mkdir(lockdir)
+
+        cmd = '%s link' % ip
+        logger.info('Running %s...' % cmd)
+        ip_link = subprocess.Popen(cmd, shell=True,

stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +2 -0
+        # Matches line like: 6: tap0: <foo>
+        possibles = re.findall('^[1-9]+: +(tap[0-9]+): <.*', ip_link,

re.M)

(quoted diff) +6 -0
+        tap = ""
+        use_preconf_tap = False
+        for p in possibles:
+            lockfile = os.path.join(lockdir, p)
+            if os.path.exists('%s.skip' % lockfile):
+                logger.info('Found %s.skip, skipping %s' % (lockfile,

p))

(quoted diff) +6 -0
+                continue
+            if acquire_lock(lockfile):
+                self.lockfile = lockfile
+                tap = p
+                logger.info("Using preconfigured tap device %s" % tap)
+                logger.info("If this is not intended, touch %s.skip to

make runqemu skip %s." %(lockfile, tap))

(quoted diff) +6 -0
+                use_preconf_tap = True
+                break
+
+        if not tap:
+            if os.path.exists(nosudo_flag):
+                logger.error("Error: There are no available tap devices

to use for networking,")
+ logger.error("and I see %s exists, so I am not going to
try creating" % nosudo_flag)

(quoted diff) +6 -0
+                raise Exception("a new one with sudo.")
+
+            gid = os.getgid()
+            uid = os.getuid()
+            logger.info("Setting up tap interface under sudo")
+            cmd = 'sudo %s %s %s %s' % (self.qemuifup, uid, gid,

self.get('STAGING_DIR_NATIVE'))
+ tap = subprocess.Popen(cmd, shell=True,
stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +11 -0
+            self.cleantap = True
+            logger.info('Created tap: %s' % tap)
+
+        self.tap = tap
+        n0 = tap[3:]
+        n1 = int(n0) * 2 + 1
+        n2 = n1 + 1
+        self.nfs_instance = n0
+        if self.fstype == 'nfs':
+            self.setup_nfs()
+        self.append("KERNEL_CMDLINE_SCRIPT", "

ip=192.168.7.%s::192.168.7.%s:255.255.255.0" % (n2, n1))
+ qemu_tap_cmd = "-net
tap,vlan=0,ifname=%s,script=no,downscript=no" % self.tap
+ self.rootfs_options = '-drive file=%s,if=virtio,format=raw' %
self.rootfs

(quoted diff) +2 -0
+        if self.get('TUNE_ARCH') == 'aarch64':
+            qemu_network_cmd = '-netdev

tap,id=net0,ifname=%s,script=no,downscript=no -device virtio-net-device,netdev=net0' % self.tap
+ self.rootfs_options = '-drive
id=disk0,file=%s,if=none,format=raw -device virtio-blk-device,drive=disk0' % self.rootfs

(quoted diff) +4 -0
+        elif self.get('TUNE_ARCH') == 'powerpc':
+            qemu_network_cmd = '%s ' % qemu_tap_cmd
+        else:
+            qemu_network_cmd = "-net nic,model=virtio %s " %

qemu_tap_cmd

(quoted diff) +7 -0
+        if self.vhost_enabled:
+            qemu_network_cmd += ',vhost=on'
+        self.weak_assign('QB_NETWORK_CMD', qemu_network_cmd)
+
+    def setup_network(self):
+        cmd = "stty -g"
+        self.saved_stty = subprocess.Popen(cmd, shell=True,

stdout=subprocess.PIPE).stdout.read().decode('utf-8')

(quoted diff) +19 -0
+        if self.slirp_enabled:
+            self.setup_slirp()
+        else:
+            self.setup_tap()
+
+        if self.fstype in ('cpio.gz', 'cpio'):
+            self.set('QB_NETWORK_CMD', '')
+            self.kernel_cmdline = 'root=/dev/ram0 rw debugshell'
+            self.rootfs_options = '-initrd %s' % self.rootfs
+        else:
+            if self.fstype in self.vmtypes:
+                if self.fstype == 'iso':
+                    vm_drive = '-cdrom %s' % self.rootfs
+                else:
+                    cmd1 = "grep -q 'root=/dev/sd' %s" % self.rootfs
+                    cmd2 = "grep -q 'root=/dev/hd' %s" % self.rootfs
+                    if subprocess.call(cmd1, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = '-drive if=none,id=hd,file=%s -device

virtio-scsi-pci,id=scsi -device scsi-hd,drive=hd' % self.rootfs

(quoted diff) +5 -0
+                    elif subprocess.call(cmd2, shell=True) == 0:
+                        logger.info('Using scsi drive')
+                        vm_drive = self.rootfs
+                    else:
+                        logger.warn("Can't detect drive type %s" %

self.rootfs)

(quoted diff) +2 -0
+                        logger.warn('Tring to use virtio block drive')
+                        vm_drive = '-drive if=virtio,file=%s' %

self.rootfs

(quoted diff) +2 -0
+                self.rootfs_options = '%s -no-reboot' % vm_drive
+            self.kernel_cmdline = 'root=%s rw highres=off' %

(self.get('KERNEL_ROOT'))

(quoted diff) +4 -0
+
+        if self.fstype == 'nfs':
+            self.rootfs_options = ''
+            k_root = '/dev/nfs nfsroot=%s:%s,%s' % (self.nfs_server,

self.nfs_dir, self.unfs_opts)

(quoted diff) +10 -0
+            self.kernel_cmdline = 'root=%s rw highres=off' % k_root
+
+        self.weak_assign('QB_ROOTFS_OPTIONS', self.rootfs_options)
+
+    def setup_final(self):
+        qemu_system = self.get('QB_SYSTEM_NAME')
+        if not qemu_system:
+            raise Exception("Failed to boot, QB_SYSTEM_NAME is NULL!")
+
+        qemu_bin = '%s/%s' % (self.get('STAGING_BINDIR_NATIVE'),

qemu_system)

(quoted diff) +2 -0
+        if not os.access(qemu_bin, os.X_OK):
+            raise Exception("No QEMU binary '%s' could be found" %

qemu_bin)

(quoted diff) +2 -0
+
+        self.qemu_opt = "%s %s %s %s %s %s" % (qemu_bin,

self.get('QB_NETWORK_CMD'), self.get('QEMU_OPT_SCRIPT'), self.get('QB_ROOTFS_OPTIONS'), self.get('QB_DTB'), self.get('QB_OPT_APPEND'))

(quoted diff) +19 -0
+
+        if self.serialstdio:
+            logger.info("Interrupt character is '^]'")
+            cmd = "stty intr ^]"
+            subprocess.call(cmd, shell=True)
+
+        first_serial = ""
+        if not re.search("-nographic", self.qemu_opt):
+            first_serial = "-serial mon:vc"
+        # We always want a ttyS1. Since qemu by default adds a serial
+        # port when nodefaults is not specified, it seems that all that
+        # would be needed is to make sure a "-serial" is there. However,
+        # it appears that when "-serial" is specified, it ignores the
+        # default serial port that is normally added.  So here we make
+        # sure to add two -serial if there are none. And only one if
+        # there is one -serial already.
+        serial_num = len(re.findall("-serial", self.qemu_opt))
+        if serial_num == 0:
+            self.qemu_opt += " %s %s" % (first_serial,

self.get("QB_SERIAL_OPT"))

(quoted diff) +6 -0
+        elif serial_num == 1:
+            self.qemu_opt += " %s" % self.get("QB_SERIAL_OPT")
+
+    def start_qemu(self):
+        if self.kernel:
+            kernel_opts = "-kernel %s -append '%s %s %s'" %

(self.kernel, self.kernel_cmdline, self.get('KERNEL_CMDLINE_SCRIPT'), self.get('QB_KERNEL_CMDLINE_APPEND'))

(quoted diff) +10 -0
+        else:
+            kernel_opts = ""
+        cmd = "%s %s" % (self.qemu_opt, kernel_opts)
+        logger.info('Running %s' % cmd)
+        if subprocess.call(cmd, shell=True) != 0:
+            raise Exception('Failed to run %s' % cmd)
+
+    def cleanup(self):
+        if self.cleantap:
+            cmd = 'sudo %s %s %s' % (self.qemuifdown, self.tap,

self.get('STAGING_DIR_NATIVE'))

(quoted diff) +4 -0
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+        if self.lockfile:
+            logger.info("Releasing lockfile of preconfigured tap device

'%s'" % self.tap)

(quoted diff) +13 -0
+            release_lock(self.lockfile)
+
+        if self.nfs_running:
+            logger.info("Shutting down the userspace NFS server...")
+            cmd = "runqemu-export-rootfs stop %s" % self.nfs_dir
+            logger.info('Running %s' % cmd)
+            subprocess.call(cmd, shell=True)
+
+        if self.saved_stty:
+            cmd = "stty %s" % self.saved_stty
+            subprocess.call(cmd, shell=True)
+
+        if self.clean_nfs_dir:

Review

Quoted 10 lines
(quoted diff) +10 -0
+            logger.info('Removing %s' % self.nfs_dir)
+            shutil.rmtree(self.nfs_dir)
+            shutil.rmtree('%s.pseudo_state' % self.nfs_dir)
+
+def main():
+    if len(sys.argv) == 1 or "help" in sys.argv:
+        print_usage()
+        return 0
+    config = BaseConfig()
+    config.check_args()

When it fails to parse the args instead of showing the python exception info (with call stack, etc), it should show the exception message and the runqemu usage.

Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

Regards,
Nathan

You may not have seen this comment, since I accidentally put two "Regards," in my previous email.

Yes, I had missed this, print the full help text seems too more, I will print "See 'runqemu help' on how to use it"

// Robert

Quoted 4 lines

Regards,
Nathan

#13 lore raw
In reply to Robert Yang
Quoted 6 lines · Robert Yang

* V3
- Move the qemu boot settings out of tune files (e.g., arch
-x86.inc)
to avoid mixing BSP settings with the tunings as Mark suggested.
and
put them to <machine>.conf or <qemuboot>.inc file.

I tried pulling this into master-next and testing on the autobuilder. It seems there is a problem with the networking and device locking/allocation:

https://autobuilder.yoctoproject.org/main/builders/nightly-deb/builds/8
55/steps/Running%20Sanity%20Tests/logs/stdio

https://autobuilder.yoctoproject.org/main/builders/nightly-arm64/builds
/531

[and many others]

Also a problem with runqemu-internal being removed:

https://autobuilder.yoctoproject.org/main/builders/nightly-intel-gpl/bu
ilds/886/steps/BuildImages/logs/stdio

Cheers,

Richard

#14 lore raw
Quoted 11 lines · Richard Purdie
Quoted 6 lines · Robert Yang

* V3
- Move the qemu boot settings out of tune files (e.g., arch
-x86.inc)
to avoid mixing BSP settings with the tunings as Mark suggested.
and
put them to <machine>.conf or <qemuboot>.inc file.

I tried pulling this into master-next and testing on the autobuilder. It seems there is a problem with the networking and device locking/allocation:

Sorry, I can't use "with open(lock, 'w') as f:" since the file would be closed automatically when "with" section is done, and the file will be unlocked when closed.

Quoted 7 lines

https://autobuilder.yoctoproject.org/main/builders/nightly-deb/builds/8
55/steps/Running%20Sanity%20Tests/logs/stdio

https://autobuilder.yoctoproject.org/main/builders/nightly-arm64/builds
/531

Quoted 6 lines

[and many others]

Also a problem with runqemu-internal being removed:

https://autobuilder.yoctoproject.org/main/builders/nightly-intel-gpl/bu
ilds/886/steps/BuildImages/logs/stdio

Sorry, I will fix this in V4.

// Robert

Quoted 5 lines

Cheers,

Richard