[RFC PATCH 1/3] target/openrisc: Add basic support for semihosting

Stafford Horne
2022-05-27T17:27:46Z

For OpenRISC we currently only use semihosting for system exit and
reset. This patch implements that.

The implementation uses a helper to delegate to the semihosting
facility. The helper is marked as having side effects but currently
does not have any. I have defined it like this as our other
unimplemented semihosting calls will have side effects and return
results in register r11.

Signed-off-by: Stafford Horne <shorne@gmail.com>
---
configs/devices/or1k-softmmu/default.mak | 2 +
qemu-options.hx | 16 ++++---
target/openrisc/cpu.h | 2 +
target/openrisc/helper.h | 1 +
target/openrisc/meson.build | 1 +
target/openrisc/openrisc-semi.c | 54 ++++++++++++++++++++++++
target/openrisc/sys_helper.c | 5 +++
target/openrisc/translate.c | 6 +++
8 files changed, 82 insertions(+), 5 deletions(-)
create mode 100644 target/openrisc/openrisc-semi.c

diff --git a/configs/devices/or1k-softmmu/default.mak b/configs/devices/or1k-softmmu/default.mak
index 168101c39a..5b3ac89491 100644
--- a/configs/devices/or1k-softmmu/default.mak
+++ b/configs/devices/or1k-softmmu/default.mak
@@ -1,5 +1,7 @@
# Default configuration for or1k-softmmu

+CONFIG_SEMIHOSTING=y
+
# Boards:
#
CONFIG_OR1K_SIM=y
diff --git a/qemu-options.hx b/qemu-options.hx
index b484640067..312c68b065 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4566,10 +4566,12 @@ ERST
DEF("semihosting", 0, QEMU_OPTION_semihosting,
"-semihosting semihosting mode\n",
QEMU_ARCH_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA |
- QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
+ QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV |
+ QEMU_ARCH_OPENRISC)
SRST
``-semihosting``
- Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V only).
+ Enable semihosting mode (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V,
+ OpenRISC only).

Note that this allows guest direct access to the host filesystem, so
should only be used with a trusted guest OS.
@@ -4581,11 +4583,12 @@ 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_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV)
+QEMU_ARCH_MIPS | QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV |
+QEMU_ARCH_OPENRISC)
SRST
``-semihosting-config [enable=on|off][,target=native|gdb|auto][,chardev=id][,arg=str[,...]]``
- Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V
- only).
+ Enable and configure semihosting (ARM, M68K, Xtensa, MIPS, Nios II, RISC-V,
+ OpenRISC only).

Note that this allows guest direct access to the host filesystem, so
should only be used with a trusted guest OS.
@@ -4601,6 +4604,9 @@ SRST

On RISC-V this implements the standard semihosting API, version 0.2.

+ On OpenRISC this only supports providing simulation exit and reset
+ facilities.
+
``target=native|gdb|auto``
Defines where the semihosting calls will be addressed, to QEMU
(``native``) or to GDB (``gdb``). The default is ``auto``, which
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index b9584f10d4..4617f1272b 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -407,4 +407,6 @@ void cpu_set_fpcsr(CPUOpenRISCState *env, uint32_t val);

#define CPU_INTERRUPT_TIMER CPU_INTERRUPT_TGT_INT_0

+void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k);
+
#endif /* OPENRISC_CPU_H */
diff --git a/target/openrisc/helper.h b/target/openrisc/helper.h
index d847814a28..2fe3e4e4ca 100644
--- a/target/openrisc/helper.h
+++ b/target/openrisc/helper.h
@@ -64,3 +64,4 @@ DEF_HELPER_FLAGS_1(rfe, 0, void, env)
/* sys */
DEF_HELPER_FLAGS_3(mtspr, 0, void, env, tl, tl)
DEF_HELPER_FLAGS_3(mfspr, TCG_CALL_NO_WG, tl, env, tl, tl)
+DEF_HELPER_FLAGS_2(nop, 0, void, env, i32)
diff --git a/target/openrisc/meson.build b/target/openrisc/meson.build
index 84322086ec..1c1758b846 100644
--- a/target/openrisc/meson.build
+++ b/target/openrisc/meson.build
@@ -10,6 +10,7 @@ openrisc_ss.add(files(
'fpu_helper.c',
'gdbstub.c',
'interrupt_helper.c',
+ 'openrisc-semi.c',
'sys_helper.c',
'translate.c',
))
diff --git a/target/openrisc/openrisc-semi.c b/target/openrisc/openrisc-semi.c
new file mode 100644
index 0000000000..97d6aaacdb
--- /dev/null
+++ b/target/openrisc/openrisc-semi.c
@@ -0,0 +1,54 @@
+/*
+ * OpenRISC Semihosting syscall interface.
+ *
+ * Copyright (c) 2022 Stafford Horne
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+
+#include "cpu.h"
+#include "exec/gdbstub.h"
+#include "sysemu/runstate.h"
+#include "qemu/log.h"
+
+#define HOSTED_EXIT 1
+#define HOSTED_RESET 13
+
+static void or1k_semi_return_u32(CPUOpenRISCState *env, uint32_t ret)
+{
+ cpu_set_gpr(env, 11, ret);
+}
+
+void do_or1k_semihosting(CPUOpenRISCState *env, uint32_t k)
+{
+ uint32_t result;
+
+ switch (k) {
+ case HOSTED_EXIT:
+ gdb_exit(cpu_get_gpr(env, 3));
+ exit(cpu_get_gpr(env, 3));
+ case HOSTED_RESET:
+#ifndef CONFIG_USER_ONLY
+ qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+ return;
+#endif
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "or1k-semihosting: unsupported "
+ "semihosting syscall %d\n", k);
+ result = 0;
+ }
+ or1k_semi_return_u32(env, result);
+}
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index 48674231e7..eb698a527e 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -314,3 +314,8 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env, target_ulong rd,
/* for rd is passed in, if rd unchanged, just keep it back. */
return rd;
}
+
+void HELPER(nop)(CPUOpenRISCState *env, target_ulong k)
+{
+ do_or1k_semihosting(env, k);
+}
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 7b8ad43d5f..ec7b3b46ad 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -28,6 +28,7 @@
#include "qemu/qemu-print.h"
#include "exec/cpu_ldst.h"
#include "exec/translator.h"
+#include "semihosting/semihost.h"

#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
@@ -780,6 +781,11 @@ static bool trans_l_sh(DisasContext *dc, arg_store *a)

static bool trans_l_nop(DisasContext *dc, arg_l_nop *a)
{
+ if (semihosting_enabled() &&
+ a->k != 0) {
+ gen_helper_nop(cpu_env, tcg_constant_i32(a->k));
+ }
+
return true;
}

--
2.31.1