Testing fixes and semiconsole support:

- build fix (missing x86-iommu stubs)
   - python fixes for freebsd and OSX
   - nicer reporting of acceptance failures
   - fix build nesting of fp-test (breaks bsds)
   - semihosting clean-ups
   - support for blocking semihosting console
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAl4XEbsACgkQ+9DbCVqe
 KkRtOwgAkdw3Pwi6sSlKdouR0lcWsRRqY2T3nA+xM/JrS+W9+hJ3VsM7EcBCJZcJ
 juJkQs3kU7Gs3LAeKbjmNq9xj9eTElD20l23RufiNB2CgULwHJ2+skGCTCq+1T1P
 VBWWNky4RyGjgcKoQQ8cNUmFhntnemGjnxvz1G0dObPu6yl5jNXIk7qJFZkSsERy
 YptCN8AF2bLXekYiB9Zn0xRd+O5Q4u/RtOg62REZoZOTA11M2Zuy+fkRK4XSzM/I
 wVdRd0t0hKViktl3Z4iu3MsQqCxaHIirsfEMVkmbGWMmepq3db9Xs1k4Ss2I7Uo3
 YRTxj1BCwynsGbDpWSI/XHOYgKp8rA==
 =lSAv
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-and-semihosting-090120-2' into staging

Testing fixes and semiconsole support:

  - build fix (missing x86-iommu stubs)
  - python fixes for freebsd and OSX
  - nicer reporting of acceptance failures
  - fix build nesting of fp-test (breaks bsds)
  - semihosting clean-ups
  - support for blocking semihosting console

# gpg: Signature made Thu 09 Jan 2020 11:42:51 GMT
# gpg:                using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44
# gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full]
# Primary key fingerprint: 6685 AE99 E751 67BC AFC8  DF35 FBD0 DB09 5A9E 2A44

* remotes/stsquad/tags/pull-testing-and-semihosting-090120-2:
  tests/tcg: add user version of dumb-as-bricks semiconsole test
  tests/tcg: extract __semi_call into a header and expand
  tests/tcg: add a dumb-as-bricks semihosting console test
  semihosting: add qemu_semihosting_console_inc for SYS_READC
  target/arm: only update pc after semihosting completes
  target/arm: remove unused EXCP_SEMIHOST leg
  testing: don't nest build for fp-test
  travis.yml: install homebrew python for OS X
  travis.yml: duplicate before_script for MacOSX
  travis.yml: Detach build and test steps
  travis.yml: avocado: Print logs of non-pass tests only
  freebsd: use python37
  tests/vm: update openbsd to release 6.6
  hw/i386/x86-iommu: Add missing stubs

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-01-10 13:19:34 +00:00
commit f38a71b01f
26 changed files with 328 additions and 56 deletions

View File

@ -51,13 +51,6 @@ addons:
- sparse
- uuid-dev
- gcovr
homebrew:
packages:
- ccache
- glib
- pixman
- gnu-sed
update: true
# The channel name "irc.oftc.net#qemu" is encrypted against qemu/qemu
@ -89,12 +82,12 @@ git:
before_script:
- if [ "$TRAVIS_OS_NAME" == "osx" ] ; then export PATH="/usr/local/opt/ccache/libexec:$PATH" ; fi
- if command -v ccache ; then ccache --zero-stats ; fi
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
script:
- make -j3 && travis_retry ${TEST_CMD}
- BUILD_RC=0 && make -j3 || BUILD_RC=$?
- if [ "$BUILD_RC" -eq 0 ] ; then travis_retry ${TEST_CMD} ; else $(exit $BUILD_RC); fi
after_script:
- if command -v ccache ; then ccache --show-stats ; fi
@ -239,6 +232,21 @@ matrix:
os: osx
osx_image: xcode10.3
compiler: clang
addons:
homebrew:
packages:
- ccache
- glib
- pixman
- gnu-sed
- python
update: true
before_script:
- brew link --overwrite python
- export PATH="/usr/local/opt/ccache/libexec:$PATH"
- if command -v ccache ; then ccache --zero-stats ; fi
- mkdir -p ${BUILD_DIR} && cd ${BUILD_DIR}
- ${SRC_DIR}/configure ${BASE_CONFIG} ${CONFIG} || { cat config.log && exit 1; }
# Python builds
@ -262,8 +270,8 @@ matrix:
- env:
- CONFIG="--python=/usr/bin/python3 --target-list=x86_64-softmmu,mips-softmmu,mips64el-softmmu,aarch64-softmmu,arm-softmmu,s390x-softmmu,alpha-softmmu,ppc-softmmu,ppc64-softmmu,m68k-softmmu,sparc-softmmu"
- TEST_CMD="make check-acceptance"
after_failure:
- cat tests/results/latest/job.log
after_script:
- python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat
addons:
apt:
packages:

View File

@ -32,3 +32,12 @@ X86IOMMUState *x86_iommu_get_default(void)
return NULL;
}
bool x86_iommu_ir_supported(X86IOMMUState *s)
{
return false;
}
IommuType x86_iommu_get_type(void)
{
abort();
}

View File

@ -20,8 +20,15 @@
#include "hw/semihosting/semihost.h"
#include "hw/semihosting/console.h"
#include "exec/gdbstub.h"
#include "exec/exec-all.h"
#include "qemu/log.h"
#include "chardev/char.h"
#include <pthread.h>
#include "chardev/char-fe.h"
#include "sysemu/sysemu.h"
#include "qemu/main-loop.h"
#include "qapi/error.h"
#include "qemu/fifo8.h"
int qemu_semihosting_log_out(const char *s, int len)
{
@ -98,3 +105,75 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
__func__, addr);
}
}
#define FIFO_SIZE 1024
/* Access to this structure is protected by the BQL */
typedef struct SemihostingConsole {
CharBackend backend;
GSList *sleeping_cpus;
bool got;
Fifo8 fifo;
} SemihostingConsole;
static SemihostingConsole console;
static int console_can_read(void *opaque)
{
SemihostingConsole *c = opaque;
int ret;
g_assert(qemu_mutex_iothread_locked());
ret = (int) fifo8_num_free(&c->fifo);
return ret;
}
static void console_wake_up(gpointer data, gpointer user_data)
{
CPUState *cs = (CPUState *) data;
/* cpu_handle_halt won't know we have work so just unbung here */
cs->halted = 0;
qemu_cpu_kick(cs);
}
static void console_read(void *opaque, const uint8_t *buf, int size)
{
SemihostingConsole *c = opaque;
g_assert(qemu_mutex_iothread_locked());
while (size-- && !fifo8_is_full(&c->fifo)) {
fifo8_push(&c->fifo, *buf++);
}
g_slist_foreach(c->sleeping_cpus, console_wake_up, NULL);
c->sleeping_cpus = NULL;
}
target_ulong qemu_semihosting_console_inc(CPUArchState *env)
{
uint8_t ch;
SemihostingConsole *c = &console;
g_assert(qemu_mutex_iothread_locked());
g_assert(current_cpu);
if (fifo8_is_empty(&c->fifo)) {
c->sleeping_cpus = g_slist_prepend(c->sleeping_cpus, current_cpu);
current_cpu->halted = 1;
current_cpu->exception_index = EXCP_HALTED;
cpu_loop_exit(current_cpu);
/* never returns */
}
ch = fifo8_pop(&c->fifo);
return (target_ulong) ch;
}
void qemu_semihosting_console_init(void)
{
Chardev *chr = semihosting_get_chardev();
if (chr) {
fifo8_create(&console.fifo, FIFO_SIZE);
qemu_chr_fe_init(&console.backend, chr, &error_abort);
qemu_chr_fe_set_handlers(&console.backend,
console_can_read,
console_read,
NULL, NULL, &console,
NULL, true);
}
}

View File

@ -37,6 +37,22 @@ int qemu_semihosting_console_outs(CPUArchState *env, target_ulong s);
*/
void qemu_semihosting_console_outc(CPUArchState *env, target_ulong c);
/**
* qemu_semihosting_console_inc:
* @env: CPUArchState
*
* Receive single character from debug console. This may be the remote
* gdb session if a softmmu guest is currently being debugged. As this
* call may block if no data is available we suspend the CPU and will
* re-execute the instruction when data is there. Therefore two
* conditions must be met:
* - CPUState is synchronized before calling this function
* - pc is only updated once the character is successfully returned
*
* Returns: character read OR cpu_loop_exit!
*/
target_ulong qemu_semihosting_console_inc(CPUArchState *env);
/**
* qemu_semihosting_log_out:
* @s: pointer to string

View File

@ -56,6 +56,9 @@ static inline Chardev *semihosting_get_chardev(void)
{
return NULL;
}
static inline void qemu_semihosting_console_init(void)
{
}
#else /* !CONFIG_USER_ONLY */
bool semihosting_enabled(void);
SemihostingTarget semihosting_get_target(void);
@ -68,6 +71,7 @@ Chardev *semihosting_get_chardev(void);
void qemu_semihosting_enable(void);
int qemu_semihosting_config_options(const char *opt);
void qemu_semihosting_connect_chardevs(void);
void qemu_semihosting_console_init(void);
#endif /* CONFIG_USER_ONLY */
#endif /* SEMIHOST_H */

View File

@ -130,6 +130,7 @@ void cpu_loop(CPUARMState *env)
break;
case EXCP_SEMIHOST:
env->xregs[0] = do_arm_semihosting(env);
env->pc += 4;
break;
case EXCP_YIELD:
/* nothing to do here for user-mode, just resume guest code */

View File

@ -377,6 +377,7 @@ void cpu_loop(CPUARMState *env)
break;
case EXCP_SEMIHOST:
env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */

View File

@ -14,6 +14,7 @@
#include "cpu.h"
#include "hw/semihosting/console.h"
#include "qemu.h"
#include <termios.h>
int qemu_semihosting_console_outs(CPUArchState *env, target_ulong addr)
{
@ -47,3 +48,29 @@ void qemu_semihosting_console_outc(CPUArchState *env, target_ulong addr)
}
}
}
/*
* For linux-user we can safely block. However as we want to return as
* soon as a character is read we need to tweak the termio to disable
* line buffering. We restore the old mode afterwards in case the
* program is expecting more normal behaviour. This is slow but
* nothing using semihosting console reading is expecting to be fast.
*/
target_ulong qemu_semihosting_console_inc(CPUArchState *env)
{
uint8_t c;
struct termios old_tio, new_tio;
/* Disable line-buffering and echo */
tcgetattr(STDIN_FILENO, &old_tio);
new_tio = old_tio;
new_tio.c_lflag &= (~ICANON & ~ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &new_tio);
c = getchar();
/* restore config */
tcsetattr(STDIN_FILENO, TCSANOW, &old_tio);
return (target_ulong) c;
}

View File

@ -69,3 +69,7 @@ void semihosting_arg_fallback(const char *file, const char *cmd)
void qemu_semihosting_connect_chardevs(void)
{
}
void qemu_semihosting_console_init(void)
{
}

View File

@ -802,8 +802,7 @@ target_ulong do_arm_semihosting(CPUARMState *env)
return guestfd_fns[gf->type].readfn(cpu, gf, arg1, len);
case TARGET_SYS_READC:
qemu_log_mask(LOG_UNIMP, "%s: SYS_READC not implemented", __func__);
return 0;
return qemu_semihosting_console_inc(env);
case TARGET_SYS_ISTTY:
GET_ARG(0);

View File

@ -8566,12 +8566,6 @@ static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
case EXCP_VFIQ:
addr += 0x100;
break;
case EXCP_SEMIHOST:
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
return;
default:
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
}
@ -8620,11 +8614,13 @@ static void handle_semihosting(CPUState *cs)
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
env->pc += 4;
} else {
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
}
}
#endif

View File

@ -2185,6 +2185,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
env->regs[15] += env->thumb ? 2 : 4;
return;
case EXCP_BKPT:
armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_DEBUG, false);

View File

@ -1937,7 +1937,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
break;
}
#endif
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else {
unsupported_encoding(s, insn);
}

View File

@ -1124,7 +1124,7 @@ static inline void gen_hlt(DisasContext *s, int imm)
s->current_el != 0 &&
#endif
(imm == (s->thumb ? 0x3c : 0xf000))) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
return;
}
@ -8457,7 +8457,7 @@ static bool trans_BKPT(DisasContext *s, arg_BKPT *a)
!IS_USER(s) &&
#endif
(a->imm == 0xab)) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else {
gen_exception_bkpt_insn(s, syn_aa32_bkpt(a->imm, false));
}
@ -10266,7 +10266,7 @@ static bool trans_SVC(DisasContext *s, arg_SVC *a)
!IS_USER(s) &&
#endif
(a->imm == semihost_imm)) {
gen_exception_internal_insn(s, s->base.pc_next, EXCP_SEMIHOST);
gen_exception_internal_insn(s, s->pc_curr, EXCP_SEMIHOST);
} else {
gen_set_pc_im(s, s->base.pc_next);
s->svc_imm = a->imm;

View File

@ -969,7 +969,7 @@ FP_TEST_BIN=$(BUILD_DIR)/tests/fp/fp-test
# the build dir is created by configure
.PHONY: $(FP_TEST_BIN)
$(FP_TEST_BIN):
$(FP_TEST_BIN): config-host.h $(test-util-obj-y)
$(call quiet-command, \
$(MAKE) $(SUBDIR_MAKEFLAGS) -C $(dir $@) V="$(V)" $(notdir $@), \
"BUILD", "$(notdir $@)")

View File

@ -554,15 +554,13 @@ TF_OBJS_LIB += $(TF_OBJS_TEST)
BINARIES := fp-test$(EXESUF) fp-bench$(EXESUF)
# everything depends on config-host.h because platform.h includes it
all: $(BUILD_DIR)/config-host.h
$(MAKE) $(BINARIES)
# We require artefacts from the main build including config-host.h
# because platform.h includes it. Rather than re-invoking the main
# build we just error out if things aren't there.
$(LIBQEMUUTIL) $(BUILD_DIR)/config-host.h:
$(error $@ missing, re-run parent build)
$(LIBQEMUUTIL):
$(MAKE) -C $(BUILD_DIR) libqemuutil.a
$(BUILD_DIR)/config-host.h:
$(MAKE) -C $(BUILD_DIR) config-host.h
all: $(BUILD_DIR)/config-host.h $(BINARIES)
# libtestfloat.a depends on libsoftfloat.a, so specify it first
FP_TEST_LIBS := libtestfloat.a libsoftfloat.a $(LIBQEMUUTIL)

View File

@ -31,7 +31,16 @@ LDFLAGS+=-static -nostdlib $(CRT_OBJS) $(MINILIB_OBJS) -lgcc
memory: CFLAGS+=-DCHECK_UNALIGNED=1
# Running
QEMU_OPTS+=-M virt -cpu max -display none -semihosting-config enable=on,target=native,chardev=output -kernel
QEMU_BASE_MACHINE=-M virt -cpu max -display none
QEMU_OPTS+=$(QEMU_BASE_MACHINE) -semihosting-config enable=on,target=native,chardev=output -kernel
# console test is manual only
QEMU_SEMIHOST=-chardev stdio,mux=on,id=stdio0 -semihosting-config enable=on,chardev=stdio0 -mon chardev=stdio0,mode=readline
run-semiconsole: QEMU_OPTS=$(QEMU_BASE_MACHINE) $(QEMU_SEMIHOST) -kernel
run-semiconsole: semiconsole
$(call skip-test, $<, "MANUAL ONLY")
run-plugin-semiconsole-with-%: semiconsole
$(call skip-test, $<, "MANUAL ONLY")
# Simple Record/Replay Test
.PHONY: memory-record

View File

@ -32,4 +32,11 @@ run-plugin-semihosting-with-%:
$(call strip-plugin,$<) 2> $<.err, \
"$< on $(TARGET_NAME) with $*")
AARCH64_TESTS += semiconsole
run-semiconsole: semiconsole
$(call skip-test, $<, "MANUAL ONLY")
run-plugin-semiconsole-with-%:
$(call skip-test, $<, "MANUAL ONLY")
TESTS += $(AARCH64_TESTS)

View File

@ -0,0 +1,38 @@
/*
* Semihosting Console Test
*
* Copyright (c) 2019 Linaro Ltd
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <inttypes.h>
#include <minilib.h>
#define SYS_READC 0x7
uintptr_t __semi_call(uintptr_t type, uintptr_t arg0)
{
register uintptr_t t asm("x0") = type;
register uintptr_t a0 asm("x1") = arg0;
asm("hlt 0xf000"
: "=r" (t)
: "r" (t), "r" (a0));
return t;
}
int main(void)
{
char c;
ml_printf("Semihosting Console Test\n");
ml_printf("hit X to exit:");
do {
c = __semi_call(SYS_READC, 0);
__sys_outc(c);
} while (c != 'X');
return 0;
}

View File

@ -31,15 +31,43 @@ run-fcvt: fcvt
# Semihosting smoke test for linux-user
ARM_TESTS += semihosting
semihosting: CFLAGS += -mthumb
run-semihosting: semihosting
$(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)")
ARM_TESTS += semihosting-arm
semihosting-arm: CFLAGS += -marm
semihosting-arm: semihosting.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
run-semihosting-arm: semihosting-arm
$(call run-test,$<,$(QEMU) $< 2> $<.err, "$< on $(TARGET_NAME)")
run-plugin-semihosting-with-%:
$(call run-test, $@, $(QEMU) $(QEMU_OPTS) \
-plugin $(PLUGIN_DIR)/$(call extract-plugin,$@) \
$(call strip-plugin,$<) 2> $<.err, \
"$< on $(TARGET_NAME) with $*")
ARM_TESTS += semiconsole semiconsole-arm
semiconsole: CFLAGS += -mthumb
run-semiconsole: semiconsole
$(call skip-test, $<, "MANUAL ONLY")
run-plugin-semiconsole-with-%:
$(call skip-test, $<, "MANUAL ONLY")
semiconsole-arm: CFLAGS += -marm
semiconsole-arm: semiconsole.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $< -o $@ $(LDFLAGS)
run-semiconsole-arm: semiconsole-arm
$(call skip-test, $<, "MANUAL ONLY")
run-plugin-semiconsole-arm-with-%:
$(call skip-test, $<, "MANUAL ONLY")
TESTS += $(ARM_TESTS)
# On ARM Linux only supports 4k pages

35
tests/tcg/arm/semicall.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Semihosting Tests
*
* Copyright (c) 2019
* Written by Alex Bennée <alex.bennee@linaro.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#define SYS_WRITE0 0x04
#define SYS_READC 0x07
#define SYS_REPORTEXC 0x18
uintptr_t __semi_call(uintptr_t type, uintptr_t arg0)
{
#if defined(__arm__)
register uintptr_t t asm("r0") = type;
register uintptr_t a0 asm("r1") = arg0;
#ifdef __thumb__
# define SVC "svc 0xab"
#else
# define SVC "svc 0x123456"
#endif
asm(SVC : "=r" (t)
: "r" (t), "r" (a0));
#else
register uintptr_t t asm("x0") = type;
register uintptr_t a0 asm("x1") = arg0;
asm("hlt 0xf000"
: "=r" (t)
: "r" (t), "r" (a0));
#endif
return t;
}

View File

@ -0,0 +1,27 @@
/*
* linux-user semihosting console
*
* Copyright (c) 2019
* Written by Alex Bennée <alex.bennee@linaro.org>
*
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <stdio.h>
#include <stdint.h>
#include "semicall.h"
int main(void)
{
char c;
printf("Semihosting Console Test\n");
printf("hit X to exit:");
do {
c = __semi_call(SYS_READC, 0);
printf("got '%c'\n", c);
} while (c != 'X');
return 0;
}

View File

@ -8,26 +8,7 @@
*/
#include <stdint.h>
#define SYS_WRITE0 0x04
#define SYS_REPORTEXC 0x18
void __semi_call(uintptr_t type, uintptr_t arg0)
{
#if defined(__arm__)
register uintptr_t t asm("r0") = type;
register uintptr_t a0 asm("r1") = arg0;
asm("svc 0xab"
: /* no return */
: "r" (t), "r" (a0));
#else
register uintptr_t t asm("x0") = type;
register uintptr_t a0 asm("x1") = arg0;
asm("hlt 0xf000"
: /* no return */
: "r" (t), "r" (a0));
#endif
}
#include "semicall.h"
int main(int argc, char *argv[argc])
{

View File

@ -32,6 +32,7 @@ class FreeBSDVM(basevm.BaseVM):
"git",
"pkgconf",
"bzip2",
"python37",
# gnu tools
"bash",
@ -63,7 +64,7 @@ class FreeBSDVM(basevm.BaseVM):
mkdir src build; cd src;
tar -xf /dev/vtbd1;
cd ../build
../src/configure --python=python3.6 {configure_opts};
../src/configure --python=python3.7 {configure_opts};
gmake --output-sync -j{jobs} {target} {verbose};
"""

View File

@ -22,8 +22,8 @@ class OpenBSDVM(basevm.BaseVM):
name = "openbsd"
arch = "x86_64"
link = "https://cdn.openbsd.org/pub/OpenBSD/6.5/amd64/install65.iso"
csum = "38d1f8cadd502f1c27bf05c5abde6cc505dd28f3f34f8a941048ff9a54f9f608"
link = "https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.iso"
csum = "b22e63df56e6266de6bbeed8e9be0fbe9ee2291551c5bc03f3cc2e4ab9436ee3"
size = "20G"
pkgs = [
# tools

3
vl.c
View File

@ -4238,6 +4238,9 @@ int main(int argc, char **argv, char **envp)
qemu_opts_foreach(qemu_find_opts("mon"),
mon_init_func, NULL, &error_fatal);
/* connect semihosting console input if requested */
qemu_semihosting_console_init();
if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
exit(1);
if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)