From: "Alex Bennée" <alex.bennee@linaro.org> To: qemu-devel@nongnu.org Cc: "Keith Packard" <keithp@keithp.com>, "open list:RISC-V TCG CPUs" <qemu-riscv@nongnu.org>, "Sagar Karandikar" <sagark@eecs.berkeley.edu>, "Bastian Koppelmann" <kbastian@mail.uni-paderborn.de>, "Laurent Vivier" <laurent@vivier.eu>, "Palmer Dabbelt" <palmer@dabbelt.com>, "Alistair Francis" <Alistair.Francis@wdc.com>, "Alex Bennée" <alex.bennee@linaro.org> Subject: [PATCH v1 16/20] riscv: Add semihosting support Date: Fri, 8 Jan 2021 22:42:52 +0000 [thread overview] Message-ID: <20210108224256.2321-17-alex.bennee@linaro.org> (raw) In-Reply-To: <20210108224256.2321-1-alex.bennee@linaro.org> From: Keith Packard <keithp@keithp.com> Adapt the arm semihosting support code for RISCV. This implementation is based on the standard for RISC-V semihosting version 0.2 as documented in https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2 Signed-off-by: Keith Packard <keithp@keithp.com> Message-Id: <20210107170717.2098982-6-keithp@keithp.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- default-configs/devices/riscv32-softmmu.mak | 2 + default-configs/devices/riscv64-softmmu.mak | 2 + .../targets/riscv32-linux-user.mak | 1 + .../targets/riscv64-linux-user.mak | 1 + hw/semihosting/common-semi.h | 5 +- linux-user/qemu.h | 4 +- target/riscv/cpu_bits.h | 1 + hw/semihosting/common-semi.c | 82 ++++++++++++++++++- linux-user/semihost.c | 8 +- target/riscv/cpu_helper.c | 10 +++ target/riscv/translate.c | 11 +++ .../riscv/insn_trans/trans_privileged.c.inc | 37 ++++++++- qemu-options.hx | 10 ++- 13 files changed, 162 insertions(+), 12 deletions(-) diff --git a/default-configs/devices/riscv32-softmmu.mak b/default-configs/devices/riscv32-softmmu.mak index 94a236c9c2..d847bd5692 100644 --- a/default-configs/devices/riscv32-softmmu.mak +++ b/default-configs/devices/riscv32-softmmu.mak @@ -3,6 +3,8 @@ # Uncomment the following lines to disable these optional devices: # #CONFIG_PCI_DEVICES=n +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y # Boards: # diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak index 76b6195648..d5eec75f05 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -3,6 +3,8 @@ # Uncomment the following lines to disable these optional devices: # #CONFIG_PCI_DEVICES=n +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y # Boards: # diff --git a/default-configs/targets/riscv32-linux-user.mak b/default-configs/targets/riscv32-linux-user.mak index dfb259e8aa..6a9d1b1bc1 100644 --- a/default-configs/targets/riscv32-linux-user.mak +++ b/default-configs/targets/riscv32-linux-user.mak @@ -2,3 +2,4 @@ TARGET_ARCH=riscv32 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml gdb-xml/riscv-32bit-virtual.xml +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/default-configs/targets/riscv64-linux-user.mak b/default-configs/targets/riscv64-linux-user.mak index b13895f3b0..0a92849a1b 100644 --- a/default-configs/targets/riscv64-linux-user.mak +++ b/default-configs/targets/riscv64-linux-user.mak @@ -2,3 +2,4 @@ TARGET_ARCH=riscv64 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml gdb-xml/riscv-64bit-virtual.xml +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h index bc53e92c79..0bfab1c669 100644 --- a/hw/semihosting/common-semi.h +++ b/hw/semihosting/common-semi.h @@ -1,6 +1,6 @@ /* * Semihosting support for systems modeled on the Arm "Angel" - * semihosting syscalls design. + * semihosting syscalls design. This includes Arm and RISC-V processors * * Copyright (c) 2005, 2007 CodeSourcery. * Copyright (c) 2019 Linaro @@ -26,6 +26,9 @@ * Semihosting for AArch32 and AArch64 Release 2.0 * https://static.docs.arm.com/100863/0200/semihosting.pdf * + * RISC-V Semihosting is documented in: + * RISC-V Semihosting + * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc */ #ifndef COMMON_SEMI_H diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 534753ca12..17aa992165 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -109,6 +109,8 @@ typedef struct TaskState { /* FPA state */ FPA11 fpa; # endif +#endif +#if defined(TARGET_ARM) || defined(TARGET_RISCV) int swi_errno; #endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) @@ -122,7 +124,7 @@ typedef struct TaskState { #ifdef TARGET_M68K abi_ulong tp_value; #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV) /* Extra fields for semihosted binaries. */ abi_ulong heap_base; abi_ulong heap_limit; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index b41e8836c3..4196ef8b69 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -542,6 +542,7 @@ #define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ #define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ #define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ +#define RISCV_EXCP_SEMIHOST 0x10 #define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14 #define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15 #define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16 diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c index 293791f721..5fcb8663c6 100644 --- a/hw/semihosting/common-semi.c +++ b/hw/semihosting/common-semi.c @@ -1,6 +1,6 @@ /* * Semihosting support for systems modeled on the Arm "Angel" - * semihosting syscalls design. + * semihosting syscalls design. This includes Arm and RISC-V processors * * Copyright (c) 2005, 2007 CodeSourcery. * Copyright (c) 2019 Linaro @@ -25,6 +25,10 @@ * ARM Semihosting is documented in: * Semihosting for AArch32 and AArch64 Release 2.0 * https://static.docs.arm.com/100863/0200/semihosting.pdf + * + * RISC-V Semihosting is documented in: + * RISC-V Semihosting + * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc */ #include "qemu/osdep.h" @@ -222,6 +226,42 @@ common_semi_rambase(CPUState *cs) #endif /* TARGET_ARM */ +#ifdef TARGET_RISCV +static inline target_ulong +common_semi_arg(CPUState *cs, int argno) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return env->gpr[xA0 + argno]; +} + +static inline void +common_semi_set_ret(CPUState *cs, target_ulong ret) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + env->gpr[xA0] = ret; +} + +static inline bool +common_semi_sys_exit_extended(CPUState *cs, int nr) +{ + return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); +} + +#ifndef CONFIG_USER_ONLY + +static inline target_ulong +common_semi_rambase(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return common_semi_find_region_base(env->gpr[xSP]); +} +#endif + +#endif + /* * Allocate a new guest file descriptor and return it; if we * couldn't allocate a new fd then return -1. @@ -398,6 +438,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs) sp = env->regs[13]; } #endif +#ifdef TARGET_RISCV + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + sp = env->gpr[xSP]; +#endif return sp - 64; } @@ -741,6 +787,37 @@ static const GuestFDFunctions guestfd_fns[] = { put_user_u32(val, args + (n) * 4)) #endif +#ifdef TARGET_RISCV + +/* + * get_user_ual is defined as get_user_u32 in softmmu-semi.h, + * we need a macro that fetches a target_ulong + */ +#define get_user_utl(arg, p) \ + ((sizeof(target_ulong) == 8) ? \ + get_user_u64(arg, p) : \ + get_user_u32(arg, p)) + +/* + * put_user_ual is defined as put_user_u32 in softmmu-semi.h, + * we need a macro that stores a target_ulong + */ +#define put_user_utl(arg, p) \ + ((sizeof(target_ulong) == 8) ? \ + put_user_u64(arg, p) : \ + put_user_u32(arg, p)) + +#define GET_ARG(n) do { \ + if (get_user_utl(arg ## n, args + (n) * sizeof(target_ulong))) { \ + errno = EFAULT; \ + return set_swi_errno(cs, -1); \ + } \ + } while (0) + +#define SET_ARG(n, val) \ + put_user_utl(val, args + (n) * sizeof(target_ulong)) +#endif + /* * Do a semihosting call. * @@ -1179,6 +1256,9 @@ target_ulong do_common_semihosting(CPUState *cs) if (is_a64(cs->env_ptr)) { return 0; } +#endif +#ifdef TARGET_RISCV + return 0; #endif /* fall through -- invalid for A32/T32 */ default: diff --git a/linux-user/semihost.c b/linux-user/semihost.c index a1f0f6050e..c0015ee7f6 100644 --- a/linux-user/semihost.c +++ b/linux-user/semihost.c @@ -1,11 +1,11 @@ /* - * ARM Semihosting Console Support + * ARM Compatible Semihosting Console Support. * * Copyright (c) 2019 Linaro Ltd * - * Currently ARM is unique in having support for semihosting support - * in linux-user. So for now we implement the common console API but - * just for arm linux-user. + * Currently ARM and RISC-V are unique in having support for + * semihosting support in linux-user. So for now we implement the + * common console API but just for arm and risc-v linux-user. * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index a2afb95fa1..f8350f5f78 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "trace.h" +#include "hw/semihosting/common-semi.h" int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) { @@ -847,6 +848,15 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong htval = 0; target_ulong mtval2 = 0; + if (cause == RISCV_EXCP_SEMIHOST) { + if (env->priv >= PRV_S) { + env->gpr[xA0] = do_common_semihosting(cs); + env->pc += 4; + return; + } + cause = RISCV_EXCP_BREAKPOINT; + } + if (!async) { /* set tval to badaddr for traps with address information */ switch (cause) { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 554d52a4be..0f28b5f41e 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -64,6 +64,7 @@ typedef struct DisasContext { uint16_t vlen; uint16_t mlen; bool vl_eq_vlmax; + CPUState *cs; } DisasContext; #ifdef TARGET_RISCV64 @@ -747,6 +748,15 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, return true; } +static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUState *cpu = ctx->cs; + CPURISCVState *env = cpu->env_ptr; + + return cpu_ldl_code(env, pc); +} + /* Include insn module translation function */ #include "insn_trans/trans_rvi.c.inc" #include "insn_trans/trans_rvm.c.inc" @@ -814,6 +824,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL); ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); + ctx->cs = cs; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 2a61a853bf..32312be202 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -29,7 +29,42 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a) static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) { - generate_exception(ctx, RISCV_EXCP_BREAKPOINT); + target_ulong ebreak_addr = ctx->base.pc_next; + target_ulong pre_addr = ebreak_addr - 4; + target_ulong post_addr = ebreak_addr + 4; + uint32_t pre = 0; + uint32_t ebreak = 0; + uint32_t post = 0; + + /* + * The RISC-V semihosting spec specifies the following + * three-instruction sequence to flag a semihosting call: + * + * slli zero, zero, 0x1f 0x01f01013 + * ebreak 0x00100073 + * srai zero, zero, 0x7 0x40705013 + * + * The two shift operations on the zero register are no-ops, used + * here to signify a semihosting exception, rather than a breakpoint. + * + * Uncompressed instructions are required so that the sequence is easy + * to validate. + * + * The three instructions are required to lie in the same page so + * that no exception will be raised when fetching them. + */ + + if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) { + pre = opcode_at(&ctx->base, pre_addr); + ebreak = opcode_at(&ctx->base, ebreak_addr); + post = opcode_at(&ctx->base, post_addr); + } + + if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) { + generate_exception(ctx, RISCV_EXCP_SEMIHOST); + } else { + generate_exception(ctx, RISCV_EXCP_BREAKPOINT); + } exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; diff --git a/qemu-options.hx b/qemu-options.hx index 1698a0c751..263caa21ec 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4197,10 +4197,10 @@ ERST DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | - QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) + QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting`` - Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only). + Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4212,10 +4212,10 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ " semihosting configuration\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | -QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) +QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II + Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). Note that this allows guest direct access to the host filesystem, so @@ -4230,6 +4230,8 @@ SRST open/read/write/seek/select. Tensilica baremetal libc for ISS and linux platform "sim" use this interface. + On RISC-V this implements the standard semihosting API, version 0.2. + ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU (``native``) or to GDB (``gdb``). The default is ``auto``, which -- 2.20.1
WARNING: multiple messages have this Message-ID (diff)
From: "Alex Bennée" <alex.bennee@linaro.org> To: qemu-devel@nongnu.org Cc: "Keith Packard" <keithp@keithp.com>, "Alex Bennée" <alex.bennee@linaro.org>, "Laurent Vivier" <laurent@vivier.eu>, "Palmer Dabbelt" <palmer@dabbelt.com>, "Alistair Francis" <Alistair.Francis@wdc.com>, "Sagar Karandikar" <sagark@eecs.berkeley.edu>, "Bastian Koppelmann" <kbastian@mail.uni-paderborn.de>, qemu-riscv@nongnu.org (open list:RISC-V TCG CPUs) Subject: [PATCH v1 16/20] riscv: Add semihosting support Date: Fri, 8 Jan 2021 22:42:52 +0000 [thread overview] Message-ID: <20210108224256.2321-17-alex.bennee@linaro.org> (raw) In-Reply-To: <20210108224256.2321-1-alex.bennee@linaro.org> From: Keith Packard <keithp@keithp.com> Adapt the arm semihosting support code for RISCV. This implementation is based on the standard for RISC-V semihosting version 0.2 as documented in https://github.com/riscv/riscv-semihosting-spec/releases/tag/0.2 Signed-off-by: Keith Packard <keithp@keithp.com> Message-Id: <20210107170717.2098982-6-keithp@keithp.com> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> --- default-configs/devices/riscv32-softmmu.mak | 2 + default-configs/devices/riscv64-softmmu.mak | 2 + .../targets/riscv32-linux-user.mak | 1 + .../targets/riscv64-linux-user.mak | 1 + hw/semihosting/common-semi.h | 5 +- linux-user/qemu.h | 4 +- target/riscv/cpu_bits.h | 1 + hw/semihosting/common-semi.c | 82 ++++++++++++++++++- linux-user/semihost.c | 8 +- target/riscv/cpu_helper.c | 10 +++ target/riscv/translate.c | 11 +++ .../riscv/insn_trans/trans_privileged.c.inc | 37 ++++++++- qemu-options.hx | 10 ++- 13 files changed, 162 insertions(+), 12 deletions(-) diff --git a/default-configs/devices/riscv32-softmmu.mak b/default-configs/devices/riscv32-softmmu.mak index 94a236c9c2..d847bd5692 100644 --- a/default-configs/devices/riscv32-softmmu.mak +++ b/default-configs/devices/riscv32-softmmu.mak @@ -3,6 +3,8 @@ # Uncomment the following lines to disable these optional devices: # #CONFIG_PCI_DEVICES=n +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y # Boards: # diff --git a/default-configs/devices/riscv64-softmmu.mak b/default-configs/devices/riscv64-softmmu.mak index 76b6195648..d5eec75f05 100644 --- a/default-configs/devices/riscv64-softmmu.mak +++ b/default-configs/devices/riscv64-softmmu.mak @@ -3,6 +3,8 @@ # Uncomment the following lines to disable these optional devices: # #CONFIG_PCI_DEVICES=n +CONFIG_SEMIHOSTING=y +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y # Boards: # diff --git a/default-configs/targets/riscv32-linux-user.mak b/default-configs/targets/riscv32-linux-user.mak index dfb259e8aa..6a9d1b1bc1 100644 --- a/default-configs/targets/riscv32-linux-user.mak +++ b/default-configs/targets/riscv32-linux-user.mak @@ -2,3 +2,4 @@ TARGET_ARCH=riscv32 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-32bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-32bit-csr.xml gdb-xml/riscv-32bit-virtual.xml +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/default-configs/targets/riscv64-linux-user.mak b/default-configs/targets/riscv64-linux-user.mak index b13895f3b0..0a92849a1b 100644 --- a/default-configs/targets/riscv64-linux-user.mak +++ b/default-configs/targets/riscv64-linux-user.mak @@ -2,3 +2,4 @@ TARGET_ARCH=riscv64 TARGET_BASE_ARCH=riscv TARGET_ABI_DIR=riscv TARGET_XML_FILES= gdb-xml/riscv-64bit-cpu.xml gdb-xml/riscv-32bit-fpu.xml gdb-xml/riscv-64bit-fpu.xml gdb-xml/riscv-64bit-csr.xml gdb-xml/riscv-64bit-virtual.xml +CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y diff --git a/hw/semihosting/common-semi.h b/hw/semihosting/common-semi.h index bc53e92c79..0bfab1c669 100644 --- a/hw/semihosting/common-semi.h +++ b/hw/semihosting/common-semi.h @@ -1,6 +1,6 @@ /* * Semihosting support for systems modeled on the Arm "Angel" - * semihosting syscalls design. + * semihosting syscalls design. This includes Arm and RISC-V processors * * Copyright (c) 2005, 2007 CodeSourcery. * Copyright (c) 2019 Linaro @@ -26,6 +26,9 @@ * Semihosting for AArch32 and AArch64 Release 2.0 * https://static.docs.arm.com/100863/0200/semihosting.pdf * + * RISC-V Semihosting is documented in: + * RISC-V Semihosting + * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc */ #ifndef COMMON_SEMI_H diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 534753ca12..17aa992165 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -109,6 +109,8 @@ typedef struct TaskState { /* FPA state */ FPA11 fpa; # endif +#endif +#if defined(TARGET_ARM) || defined(TARGET_RISCV) int swi_errno; #endif #if defined(TARGET_I386) && !defined(TARGET_X86_64) @@ -122,7 +124,7 @@ typedef struct TaskState { #ifdef TARGET_M68K abi_ulong tp_value; #endif -#if defined(TARGET_ARM) || defined(TARGET_M68K) +#if defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_RISCV) /* Extra fields for semihosted binaries. */ abi_ulong heap_base; abi_ulong heap_limit; diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index b41e8836c3..4196ef8b69 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -542,6 +542,7 @@ #define RISCV_EXCP_INST_PAGE_FAULT 0xc /* since: priv-1.10.0 */ #define RISCV_EXCP_LOAD_PAGE_FAULT 0xd /* since: priv-1.10.0 */ #define RISCV_EXCP_STORE_PAGE_FAULT 0xf /* since: priv-1.10.0 */ +#define RISCV_EXCP_SEMIHOST 0x10 #define RISCV_EXCP_INST_GUEST_PAGE_FAULT 0x14 #define RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT 0x15 #define RISCV_EXCP_VIRT_INSTRUCTION_FAULT 0x16 diff --git a/hw/semihosting/common-semi.c b/hw/semihosting/common-semi.c index 293791f721..5fcb8663c6 100644 --- a/hw/semihosting/common-semi.c +++ b/hw/semihosting/common-semi.c @@ -1,6 +1,6 @@ /* * Semihosting support for systems modeled on the Arm "Angel" - * semihosting syscalls design. + * semihosting syscalls design. This includes Arm and RISC-V processors * * Copyright (c) 2005, 2007 CodeSourcery. * Copyright (c) 2019 Linaro @@ -25,6 +25,10 @@ * ARM Semihosting is documented in: * Semihosting for AArch32 and AArch64 Release 2.0 * https://static.docs.arm.com/100863/0200/semihosting.pdf + * + * RISC-V Semihosting is documented in: + * RISC-V Semihosting + * https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc */ #include "qemu/osdep.h" @@ -222,6 +226,42 @@ common_semi_rambase(CPUState *cs) #endif /* TARGET_ARM */ +#ifdef TARGET_RISCV +static inline target_ulong +common_semi_arg(CPUState *cs, int argno) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return env->gpr[xA0 + argno]; +} + +static inline void +common_semi_set_ret(CPUState *cs, target_ulong ret) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + env->gpr[xA0] = ret; +} + +static inline bool +common_semi_sys_exit_extended(CPUState *cs, int nr) +{ + return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8); +} + +#ifndef CONFIG_USER_ONLY + +static inline target_ulong +common_semi_rambase(CPUState *cs) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + return common_semi_find_region_base(env->gpr[xSP]); +} +#endif + +#endif + /* * Allocate a new guest file descriptor and return it; if we * couldn't allocate a new fd then return -1. @@ -398,6 +438,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs) sp = env->regs[13]; } #endif +#ifdef TARGET_RISCV + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + sp = env->gpr[xSP]; +#endif return sp - 64; } @@ -741,6 +787,37 @@ static const GuestFDFunctions guestfd_fns[] = { put_user_u32(val, args + (n) * 4)) #endif +#ifdef TARGET_RISCV + +/* + * get_user_ual is defined as get_user_u32 in softmmu-semi.h, + * we need a macro that fetches a target_ulong + */ +#define get_user_utl(arg, p) \ + ((sizeof(target_ulong) == 8) ? \ + get_user_u64(arg, p) : \ + get_user_u32(arg, p)) + +/* + * put_user_ual is defined as put_user_u32 in softmmu-semi.h, + * we need a macro that stores a target_ulong + */ +#define put_user_utl(arg, p) \ + ((sizeof(target_ulong) == 8) ? \ + put_user_u64(arg, p) : \ + put_user_u32(arg, p)) + +#define GET_ARG(n) do { \ + if (get_user_utl(arg ## n, args + (n) * sizeof(target_ulong))) { \ + errno = EFAULT; \ + return set_swi_errno(cs, -1); \ + } \ + } while (0) + +#define SET_ARG(n, val) \ + put_user_utl(val, args + (n) * sizeof(target_ulong)) +#endif + /* * Do a semihosting call. * @@ -1179,6 +1256,9 @@ target_ulong do_common_semihosting(CPUState *cs) if (is_a64(cs->env_ptr)) { return 0; } +#endif +#ifdef TARGET_RISCV + return 0; #endif /* fall through -- invalid for A32/T32 */ default: diff --git a/linux-user/semihost.c b/linux-user/semihost.c index a1f0f6050e..c0015ee7f6 100644 --- a/linux-user/semihost.c +++ b/linux-user/semihost.c @@ -1,11 +1,11 @@ /* - * ARM Semihosting Console Support + * ARM Compatible Semihosting Console Support. * * Copyright (c) 2019 Linaro Ltd * - * Currently ARM is unique in having support for semihosting support - * in linux-user. So for now we implement the common console API but - * just for arm linux-user. + * Currently ARM and RISC-V are unique in having support for + * semihosting support in linux-user. So for now we implement the + * common console API but just for arm and risc-v linux-user. * * SPDX-License-Identifier: GPL-2.0-or-later */ diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index a2afb95fa1..f8350f5f78 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -24,6 +24,7 @@ #include "exec/exec-all.h" #include "tcg/tcg-op.h" #include "trace.h" +#include "hw/semihosting/common-semi.h" int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) { @@ -847,6 +848,15 @@ void riscv_cpu_do_interrupt(CPUState *cs) target_ulong htval = 0; target_ulong mtval2 = 0; + if (cause == RISCV_EXCP_SEMIHOST) { + if (env->priv >= PRV_S) { + env->gpr[xA0] = do_common_semihosting(cs); + env->pc += 4; + return; + } + cause = RISCV_EXCP_BREAKPOINT; + } + if (!async) { /* set tval to badaddr for traps with address information */ switch (cause) { diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 554d52a4be..0f28b5f41e 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -64,6 +64,7 @@ typedef struct DisasContext { uint16_t vlen; uint16_t mlen; bool vl_eq_vlmax; + CPUState *cs; } DisasContext; #ifdef TARGET_RISCV64 @@ -747,6 +748,15 @@ static bool gen_shift(DisasContext *ctx, arg_r *a, return true; } +static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc) +{ + DisasContext *ctx = container_of(dcbase, DisasContext, base); + CPUState *cpu = ctx->cs; + CPURISCVState *env = cpu->env_ptr; + + return cpu_ldl_code(env, pc); +} + /* Include insn module translation function */ #include "insn_trans/trans_rvi.c.inc" #include "insn_trans/trans_rvm.c.inc" @@ -814,6 +824,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->lmul = FIELD_EX32(tb_flags, TB_FLAGS, LMUL); ctx->mlen = 1 << (ctx->sew + 3 - ctx->lmul); ctx->vl_eq_vlmax = FIELD_EX32(tb_flags, TB_FLAGS, VL_EQ_VLMAX); + ctx->cs = cs; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 2a61a853bf..32312be202 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -29,7 +29,42 @@ static bool trans_ecall(DisasContext *ctx, arg_ecall *a) static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) { - generate_exception(ctx, RISCV_EXCP_BREAKPOINT); + target_ulong ebreak_addr = ctx->base.pc_next; + target_ulong pre_addr = ebreak_addr - 4; + target_ulong post_addr = ebreak_addr + 4; + uint32_t pre = 0; + uint32_t ebreak = 0; + uint32_t post = 0; + + /* + * The RISC-V semihosting spec specifies the following + * three-instruction sequence to flag a semihosting call: + * + * slli zero, zero, 0x1f 0x01f01013 + * ebreak 0x00100073 + * srai zero, zero, 0x7 0x40705013 + * + * The two shift operations on the zero register are no-ops, used + * here to signify a semihosting exception, rather than a breakpoint. + * + * Uncompressed instructions are required so that the sequence is easy + * to validate. + * + * The three instructions are required to lie in the same page so + * that no exception will be raised when fetching them. + */ + + if ((pre_addr & TARGET_PAGE_MASK) == (post_addr & TARGET_PAGE_MASK)) { + pre = opcode_at(&ctx->base, pre_addr); + ebreak = opcode_at(&ctx->base, ebreak_addr); + post = opcode_at(&ctx->base, post_addr); + } + + if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) { + generate_exception(ctx, RISCV_EXCP_SEMIHOST); + } else { + generate_exception(ctx, RISCV_EXCP_BREAKPOINT); + } exit_tb(ctx); /* no chaining */ ctx->base.is_jmp = DISAS_NORETURN; return true; diff --git a/qemu-options.hx b/qemu-options.hx index 1698a0c751..263caa21ec 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4197,10 +4197,10 @@ ERST DEF("semihosting", 0, QEMU_OPTION_semihosting, "-semihosting semihosting mode\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | - QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) + QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting`` - Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II only). + Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). Note that this allows guest direct access to the host filesystem, so should only be used with a trusted guest OS. @@ -4212,10 +4212,10 @@ DEF("semihosting-config", HAS_ARG, QEMU_OPTION_semihosting_config, "-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]\n" \ " semihosting configuration\n", QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_LM32 | -QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2) +QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV) SRST ``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]`` - Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II + Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only). Note that this allows guest direct access to the host filesystem, so @@ -4230,6 +4230,8 @@ SRST open/read/write/seek/select. Tensilica baremetal libc for ISS and linux platform "sim" use this interface. + On RISC-V this implements the standard semihosting API, version 0.2. + ``target=native|gdb|auto`` Defines where the semihosting calls will be addressed, to QEMU (``native``) or to GDB (``gdb``). The default is ``auto``, which -- 2.20.1
next prev parent reply other threads:[~2021-01-08 23:07 UTC|newest] Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top 2021-01-08 22:42 [PATCH v1 00/20] gdbstub, semihosting and test/tool updates (pre PR) Alex Bennée 2021-01-08 22:42 ` [PATCH v1 01/20] tests/docker: Remove Debian 9 remnant lines Alex Bennée 2021-01-08 22:42 ` [PATCH v1 02/20] test/guest-debug: echo QEMU command as well Alex Bennée 2021-01-11 15:27 ` Philippe Mathieu-Daudé 2021-01-08 22:42 ` [PATCH v1 03/20] configure: gate our use of GDB to 8.3.1 or above Alex Bennée 2021-01-08 22:42 ` [PATCH v1 04/20] Revert "tests/tcg/multiarch/Makefile.target: Disable run-gdbstub-sha1 test" Alex Bennée 2021-01-08 22:42 ` [PATCH v1 05/20] gdbstub: implement a softmmu based test Alex Bennée 2021-01-08 22:42 ` [PATCH v1 06/20] gdbstub: add support to Xfer:auxv:read: packet Alex Bennée 2021-01-08 22:42 ` [PATCH v1 07/20] gdbstub: drop CPUEnv from gdb_exit() Alex Bennée 2021-01-08 22:42 ` [PATCH v1 08/20] gdbstub: drop gdbserver_cleanup in favour of gdb_exit Alex Bennée 2021-01-08 22:42 ` [PATCH v1 09/20] gdbstub: ensure we clean-up when terminated Alex Bennée 2021-01-08 22:42 ` [PATCH v1 10/20] target/arm: use official org.gnu.gdb.aarch64.sve layout for registers Alex Bennée 2021-01-11 13:20 ` Luis Machado 2021-01-11 14:36 ` Alex Bennée 2021-01-11 14:50 ` Luis Machado 2021-01-08 22:42 ` [PATCH v1 11/20] Makefile: add GNU global tags support Alex Bennée 2021-01-08 22:42 ` [PATCH v1 12/20] semihosting: Move ARM semihosting code to shared directories Alex Bennée 2021-01-11 15:30 ` Philippe Mathieu-Daudé 2021-01-11 15:32 ` Philippe Mathieu-Daudé 2021-01-11 15:46 ` Philippe Mathieu-Daudé 2021-01-08 22:42 ` [PATCH v1 13/20] semihosting: Change common-semi API to be architecture-independent Alex Bennée 2021-01-11 15:34 ` Philippe Mathieu-Daudé 2021-01-08 22:42 ` [PATCH v1 14/20] semihosting: Change internal common-semi interfaces to use CPUState * Alex Bennée 2021-01-08 22:42 ` [PATCH v1 15/20] semihosting: Support SYS_HEAPINFO when env->boot_info is not set Alex Bennée 2021-01-08 22:42 ` Alex Bennée [this message] 2021-01-08 22:42 ` [PATCH v1 16/20] riscv: Add semihosting support Alex Bennée 2021-01-08 23:30 ` Alistair Francis 2021-01-08 23:30 ` Alistair Francis 2021-01-09 0:44 ` Keith Packard via 2021-01-09 0:44 ` Keith Packard 2021-01-08 22:42 ` [PATCH v1 17/20] riscv: Add semihosting support for user mode Alex Bennée 2021-01-08 23:32 ` Alistair Francis 2021-01-11 15:48 ` Philippe Mathieu-Daudé 2021-01-08 22:42 ` [PATCH v1 18/20] semihosting: Implement SYS_ELAPSED and SYS_TICKFREQ Alex Bennée 2021-01-08 22:42 ` [PATCH v1 19/20] semihosting: Implement SYS_TMPNAM Alex Bennée 2021-01-08 22:42 ` [PATCH v1 20/20] semihosting: Implement SYS_ISERROR Alex Bennée
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20210108224256.2321-17-alex.bennee@linaro.org \ --to=alex.bennee@linaro.org \ --cc=Alistair.Francis@wdc.com \ --cc=kbastian@mail.uni-paderborn.de \ --cc=keithp@keithp.com \ --cc=laurent@vivier.eu \ --cc=palmer@dabbelt.com \ --cc=qemu-devel@nongnu.org \ --cc=qemu-riscv@nongnu.org \ --cc=sagark@eecs.berkeley.edu \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.