riscv: Add semihosting support
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> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-Id: <20210107170717.2098982-6-keithp@keithp.com> Message-Id: <20210108224256.2321-17-alex.bennee@linaro.org>
This commit is contained in:
parent
095f8c0293
commit
a10b9d93ec
@ -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:
|
||||
#
|
||||
|
@ -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:
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -4207,10 +4207,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.
|
||||
@ -4222,10 +4222,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
|
||||
@ -4240,6 +4240,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
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user