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:
Keith Packard 2021-01-08 22:42:52 +00:00 committed by Alex Bennée
parent 095f8c0293
commit a10b9d93ec
13 changed files with 162 additions and 12 deletions

View file

@ -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;