From 6ec0a06366259907650cec999a10bf055828d40a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philippe=20Mathieu-Daud=C3=A9?= Date: Fri, 20 Dec 2019 16:42:25 +0100 Subject: [PATCH 01/14] hw/i386/x86-iommu: Add missing stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit 6c730e4af9 we introduced a stub to build the MicroVM machine without Intel IOMMU. This stub is incomplete for the other PC machines. Add the missing stubs. Fixes: 6c730e4af9 Reported-by: Travis-CI Signed-off-by: Philippe Mathieu-Daudé Tested-by: Wainer dos Santos Moschetta Signed-off-by: Alex Bennée Message-Id: <20191220154225.25879-1-philmd@redhat.com> --- hw/i386/x86-iommu-stub.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hw/i386/x86-iommu-stub.c b/hw/i386/x86-iommu-stub.c index 03576cdccb..c5ba077f9d 100644 --- a/hw/i386/x86-iommu-stub.c +++ b/hw/i386/x86-iommu-stub.c @@ -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(); +} From 22db66a436346fcccddf7617bacacdc926d2680d Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Fri, 18 Oct 2019 12:24:43 +0200 Subject: [PATCH 02/14] tests/vm: update openbsd to release 6.6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20191018102443.26469-1-kraxel@redhat.com> --- tests/vm/openbsd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/vm/openbsd b/tests/vm/openbsd index 6df5162dbf..d6173506f7 100755 --- a/tests/vm/openbsd +++ b/tests/vm/openbsd @@ -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 From bc2bf7f3480c51c3e7f38bdab1542deec765601e Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 6 Jan 2020 13:37:46 +0100 Subject: [PATCH 03/14] freebsd: use python37 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FreeBSD seems to use python37 by default now, which breaks the build script. Add python to the package list, to explicitly pick the version, and also adapt the configure command line. Signed-off-by: Gerd Hoffmann Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé Signed-off-by: Alex Bennée Message-Id: <20200106123746.18201-1-kraxel@redhat.com> --- tests/vm/freebsd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/vm/freebsd b/tests/vm/freebsd index 1825cc5821..33a736298a 100755 --- a/tests/vm/freebsd +++ b/tests/vm/freebsd @@ -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}; """ From 67892c9537d9ac50093438e77aa391f8d3e75930 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Mon, 30 Dec 2019 15:43:26 -0300 Subject: [PATCH 04/14] travis.yml: avocado: Print logs of non-pass tests only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The acceptance tests build on Travis is configured to print the entire Avocado's job log in case any test fail. Usually one is interested on failed tests only though. So this change the Travis configuration in order to show the log of tests which status is different from 'PASS' and 'SKIP' only. Note that 'CANCEL'-ed tests will have the log printed too because it can help to debug some condition on CI environment which is not being fulfilled. Signed-off-by: Wainer dos Santos Moschetta Signed-off-by: Alex Bennée Message-Id: <20191230184327.2800-2-wainersm@redhat.com> --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 638fba4799..93838bf0f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -262,8 +262,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: From 3b35388358f7d8045028565ae4c8cddee093f101 Mon Sep 17 00:00:00 2001 From: Wainer dos Santos Moschetta Date: Mon, 30 Dec 2019 15:43:27 -0300 Subject: [PATCH 05/14] travis.yml: Detach build and test steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently build and test commands are a single step in a Travis's `script` block. In order to see the output of the tests one needs to scroll down the log to find where the build messages ended and the limit is not clear. If they were in different steps then Travis would print the result build command, which can be easily grep'ed. So this change is made to detach those commands to ease the visualization of the output. Note that all steps on the `script` block is executed regardless if one previous has failed. To overcome it, let's save the return code of the build then check whether succeed or failed on the test step. Signed-off-by: Wainer dos Santos Moschetta Signed-off-by: Alex Bennée Message-Id: <20191230184327.2800-3-wainersm@redhat.com> --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 93838bf0f8..848a2714ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -94,7 +94,8 @@ before_script: - 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 From 6e3bd8a072d79b30c842ab67a0656e3a399e92f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 8 Jan 2020 10:58:58 +0000 Subject: [PATCH 06/14] travis.yml: duplicate before_script for MacOSX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than keep the hack in the global code lets "Think Different" and have a special copy for MacOSX. Signed-off-by: Alex Bennée --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 848a2714ef..6826618ea8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -89,7 +89,6 @@ 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; } @@ -240,6 +239,11 @@ matrix: os: osx osx_image: xcode10.3 compiler: clang + before_script: + - 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 From 289c8e592127eedb192d0f508f62f9f6531c0449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jan 2020 13:38:28 +0000 Subject: [PATCH 07/14] travis.yml: install homebrew python for OS X MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our python3 requirements now outstrip those of the build. While we are at it we can move more of the special casing for Mac into the one build we have. Signed-off-by: Alex Bennée --- .travis.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6826618ea8..6c1038a0f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 @@ -239,7 +232,17 @@ 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} From 3618e3a6403079383904a1a61d53d0a57508b746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jan 2020 17:55:52 +0000 Subject: [PATCH 08/14] testing: don't nest build for fp-test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Re-calling the main make is counter-productive and really messes up with parallel builds. Just ensure we have built the pre-requisites before we build the fp-test bits. If the user builds manually just complain if the parent build hasn't got the bits we need. Signed-off-by: Alex Bennée Reviewed-by: Emilio G. Cota --- tests/Makefile.include | 2 +- tests/fp/Makefile | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/Makefile.include b/tests/Makefile.include index 49e3b0d319..7a767bf114 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -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 $@)") diff --git a/tests/fp/Makefile b/tests/fp/Makefile index 5a35e7c210..56768ecfd2 100644 --- a/tests/fp/Makefile +++ b/tests/fp/Makefile @@ -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) From b906acbb3aceed5b1eca30d9d365d5bd7431400b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 17 Dec 2019 15:06:38 +0000 Subject: [PATCH 09/14] target/arm: remove unused EXCP_SEMIHOST leg MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All semihosting exceptions are dealt with earlier in the common code so we should never get here. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Keith Packard Tested-by: Keith Packard --- target/arm/helper.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index b6bec42f48..da22c19800 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -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); } From 4ff5ef9e911c670ca10cdd36dd27c5395ec2c753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 17 Dec 2019 15:08:57 +0000 Subject: [PATCH 10/14] target/arm: only update pc after semihosting completes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before we introduce blocking semihosting calls we need to ensure we can restart the system on semi hosting exception. To be able to do this the EXCP_SEMIHOST operation should be idempotent until it finally completes. Practically this means ensureing we only update the pc after the semihosting call has completed. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson Reviewed-by: Keith Packard Tested-by: Keith Packard --- linux-user/aarch64/cpu_loop.c | 1 + linux-user/arm/cpu_loop.c | 1 + target/arm/helper.c | 2 ++ target/arm/m_helper.c | 1 + target/arm/translate-a64.c | 2 +- target/arm/translate.c | 6 +++--- 6 files changed, 9 insertions(+), 4 deletions(-) diff --git a/linux-user/aarch64/cpu_loop.c b/linux-user/aarch64/cpu_loop.c index 31c845a70d..bbe9fefca8 100644 --- a/linux-user/aarch64/cpu_loop.c +++ b/linux-user/aarch64/cpu_loop.c @@ -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 */ diff --git a/linux-user/arm/cpu_loop.c b/linux-user/arm/cpu_loop.c index 7be4071751..1fae90c6df 100644 --- a/linux-user/arm/cpu_loop.c +++ b/linux-user/arm/cpu_loop.c @@ -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 */ diff --git a/target/arm/helper.c b/target/arm/helper.c index da22c19800..19a57a17da 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -8614,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 diff --git a/target/arm/m_helper.c b/target/arm/m_helper.c index 76de317e6a..33d414a684 100644 --- a/target/arm/m_helper.c +++ b/target/arm/m_helper.c @@ -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); diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index d4bebbe629..972c28c3c9 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -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); } diff --git a/target/arm/translate.c b/target/arm/translate.c index 2b6c1f91bf..5185e08641 100644 --- a/target/arm/translate.c +++ b/target/arm/translate.c @@ -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; From 8de702cb677c8381fb702cae252d6b69aa4c653b Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 4 Nov 2019 12:42:30 -0800 Subject: [PATCH 11/14] semihosting: add qemu_semihosting_console_inc for SYS_READC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides a blocking call to read a character from the console using semihosting.chardev, if specified. This takes some careful command line options to use stdio successfully as the serial ports, monitor and semihost all want to use stdio. Here's a sample set of command line options which share stdio between semihost, monitor and serial ports: qemu \ -chardev stdio,mux=on,id=stdio0 \ -serial chardev:stdio0 \ -semihosting-config enable=on,chardev=stdio0 \ -mon chardev=stdio0,mode=readline This creates a chardev hooked to stdio and then connects all of the subsystems to it. A shorter mechanism would be good to hear about. Signed-off-by: Keith Packard Message-Id: <20191104204230.12249-1-keithp@keithp.com> [AJB: fixed up deadlock, minor commit title reword] Signed-off-by: Alex Bennée Cc: Paolo Bonzini Reviewed-by: Keith Packard Tested-by: Keith Packard Reviewed-by: Richard Henderson --- hw/semihosting/console.c | 79 +++++++++++++++++++++++++++++++ include/hw/semihosting/console.h | 16 +++++++ include/hw/semihosting/semihost.h | 4 ++ linux-user/arm/semihost.c | 27 +++++++++++ stubs/semihost.c | 4 ++ target/arm/arm-semi.c | 3 +- vl.c | 3 ++ 7 files changed, 134 insertions(+), 2 deletions(-) diff --git a/hw/semihosting/console.c b/hw/semihosting/console.c index b4b17c8afb..6346bd7f50 100644 --- a/hw/semihosting/console.c +++ b/hw/semihosting/console.c @@ -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 +#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); + } +} diff --git a/include/hw/semihosting/console.h b/include/hw/semihosting/console.h index 9be9754bcd..0238f540f4 100644 --- a/include/hw/semihosting/console.h +++ b/include/hw/semihosting/console.h @@ -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 diff --git a/include/hw/semihosting/semihost.h b/include/hw/semihosting/semihost.h index 60fc42d851..b8ce5117ae 100644 --- a/include/hw/semihosting/semihost.h +++ b/include/hw/semihosting/semihost.h @@ -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 */ diff --git a/linux-user/arm/semihost.c b/linux-user/arm/semihost.c index a16b525eec..a1f0f6050e 100644 --- a/linux-user/arm/semihost.c +++ b/linux-user/arm/semihost.c @@ -14,6 +14,7 @@ #include "cpu.h" #include "hw/semihosting/console.h" #include "qemu.h" +#include 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; +} diff --git a/stubs/semihost.c b/stubs/semihost.c index f90589259c..1d8b37f7b2 100644 --- a/stubs/semihost.c +++ b/stubs/semihost.c @@ -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) +{ +} diff --git a/target/arm/arm-semi.c b/target/arm/arm-semi.c index 6f7b6d801b..47d61f6fe1 100644 --- a/target/arm/arm-semi.c +++ b/target/arm/arm-semi.c @@ -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); diff --git a/vl.c b/vl.c index 86474a55c9..b211921258 100644 --- a/vl.c +++ b/vl.c @@ -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) From 9c354591cae35d91e97244469904ab4483482d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 18 Dec 2019 14:28:36 +0000 Subject: [PATCH 12/14] tests/tcg: add a dumb-as-bricks semihosting console test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We don't run this during check-tcg as we would need to check stuff is echoed back. However we can still build the binary so people can test it manually. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson --- tests/tcg/aarch64/Makefile.softmmu-target | 11 ++++++- tests/tcg/aarch64/system/semiconsole.c | 38 +++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/aarch64/system/semiconsole.c diff --git a/tests/tcg/aarch64/Makefile.softmmu-target b/tests/tcg/aarch64/Makefile.softmmu-target index 950dbb4bac..7b4eede3f0 100644 --- a/tests/tcg/aarch64/Makefile.softmmu-target +++ b/tests/tcg/aarch64/Makefile.softmmu-target @@ -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 diff --git a/tests/tcg/aarch64/system/semiconsole.c b/tests/tcg/aarch64/system/semiconsole.c new file mode 100644 index 0000000000..bfe7c9e26b --- /dev/null +++ b/tests/tcg/aarch64/system/semiconsole.c @@ -0,0 +1,38 @@ +/* + * Semihosting Console Test + * + * Copyright (c) 2019 Linaro Ltd + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include +#include + +#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; +} From f05938090b966e58739d98fe6c755b72234d34ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Wed, 8 Jan 2020 12:24:38 +0000 Subject: [PATCH 13/14] tests/tcg: extract __semi_call into a header and expand MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are two types of ARM semicall - lets test them both. Putting the logic in a header will make re-using the functions easier later. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson --- tests/tcg/arm/Makefile.target | 9 +++++++++ tests/tcg/arm/semicall.h | 35 +++++++++++++++++++++++++++++++++++ tests/tcg/arm/semihosting.c | 21 +-------------------- 3 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 tests/tcg/arm/semicall.h diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 0765f37ff0..41aa26f4e1 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -31,9 +31,18 @@ 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,$@) \ diff --git a/tests/tcg/arm/semicall.h b/tests/tcg/arm/semicall.h new file mode 100644 index 0000000000..d4f6818192 --- /dev/null +++ b/tests/tcg/arm/semicall.h @@ -0,0 +1,35 @@ +/* + * Semihosting Tests + * + * Copyright (c) 2019 + * Written by Alex Bennée + * + * 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; +} diff --git a/tests/tcg/arm/semihosting.c b/tests/tcg/arm/semihosting.c index 09c89cb481..33faac9916 100644 --- a/tests/tcg/arm/semihosting.c +++ b/tests/tcg/arm/semihosting.c @@ -8,26 +8,7 @@ */ #include - -#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]) { From 486e58b188c1b093a8f64d4b5cd11ff5c3514cb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Thu, 19 Dec 2019 12:13:44 +0000 Subject: [PATCH 14/14] tests/tcg: add user version of dumb-as-bricks semiconsole test MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are linux-user users of semihosting so we'd better check things work for them as well. Signed-off-by: Alex Bennée Reviewed-by: Richard Henderson --- tests/tcg/aarch64/Makefile.target | 7 +++++++ tests/tcg/arm/Makefile.target | 19 +++++++++++++++++++ tests/tcg/arm/semiconsole.c | 27 +++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 tests/tcg/arm/semiconsole.c diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index 96d2321045..df3fe8032c 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -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) diff --git a/tests/tcg/arm/Makefile.target b/tests/tcg/arm/Makefile.target index 41aa26f4e1..11c39c601e 100644 --- a/tests/tcg/arm/Makefile.target +++ b/tests/tcg/arm/Makefile.target @@ -49,6 +49,25 @@ run-plugin-semihosting-with-%: $(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 diff --git a/tests/tcg/arm/semiconsole.c b/tests/tcg/arm/semiconsole.c new file mode 100644 index 0000000000..6ef0bd2450 --- /dev/null +++ b/tests/tcg/arm/semiconsole.c @@ -0,0 +1,27 @@ +/* + * linux-user semihosting console + * + * Copyright (c) 2019 + * Written by Alex Bennée + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include +#include +#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; +}