On 4/18/22 21:10, Leandro Lupori wrote:
Add semihosting support for PPC64. This implementation is
based on the standard for ARM semihosting version 2.0, as
implemented by QEMU and documented in
https://github.com/ARM-software/abi-aa/releases
The PPC64 specific differences are the following:
Semihosting Trap Instruction: sc 7
Operation Number Register: r3
Parameter Register: r4
Return Register: r3
Data block field size: 64 bits
'sc' is a good way to implement semi hosting but we should make sure
that it is not colliding with future extensions, at least with the
next POWERPC processor. Is that the case ? if not, then the lev could
be reserved.
I think the part adding POWERPC_EXCP_SEMIHOST should be proposed in a
separate patch.
Signed-off-by: Leandro Lupori <leandro.lup...@eldorado.org.br>
---
configs/devices/ppc64-softmmu/default.mak | 3 +++
qemu-options.hx | 18 ++++++++-----
semihosting/arm-compat-semi.c | 33 +++++++++++++++++++++++
target/ppc/cpu.h | 3 ++-
target/ppc/excp_helper.c | 9 +++++++
target/ppc/translate.c | 14 ++++++++++
6 files changed, 72 insertions(+), 8 deletions(-)
diff --git a/configs/devices/ppc64-softmmu/default.mak
b/configs/devices/ppc64-softmmu/default.mak
index b90e5bf455..43b618fa32 100644
--- a/configs/devices/ppc64-softmmu/default.mak
+++ b/configs/devices/ppc64-softmmu/default.mak
@@ -8,3 +8,6 @@ CONFIG_POWERNV=y
# For pSeries
CONFIG_PSERIES=y
+
+CONFIG_SEMIHOSTING=y
+CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
diff --git a/qemu-options.hx b/qemu-options.hx
index 34e9b32a5c..6e76f7de96 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4527,11 +4527,12 @@ SRST
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_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS |
+ QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | QEMU_ARCH_PPC)
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 and
+ PPC only).
Note that this allows guest direct access to the host filesystem, so
should only be used with a trusted guest OS.
@@ -4542,12 +4543,12 @@ ERST
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_ARM | QEMU_ARCH_M68K | QEMU_ARCH_XTENSA | QEMU_ARCH_MIPS |
+QEMU_ARCH_NIOS2 | QEMU_ARCH_RISCV | QEMU_ARCH_PPC)
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, PPC only).
Note that this allows guest direct access to the host filesystem, so
should only be used with a trusted guest OS.
@@ -4563,6 +4564,9 @@ SRST
On RISC-V this implements the standard semihosting API, version 0.2.
+ On PPC this implements the standard Arm semihosting API, version 2.0,
+ with only the trap instruction and register definitions changed.
+
``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/semihosting/arm-compat-semi.c b/semihosting/arm-compat-semi.c
index 7a51fd0737..e1279c316c 100644
--- a/semihosting/arm-compat-semi.c
+++ b/semihosting/arm-compat-semi.c
@@ -268,6 +268,31 @@ common_semi_sys_exit_extended(CPUState *cs, int nr)
#endif
+#ifdef TARGET_PPC64
This PPC ifdef in an ARM file seems wrong.
The rest looks OK.
Thanks,
C.
+static inline target_ulong
+common_semi_arg(CPUState *cs, int argno)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ return env->gpr[3 + argno];
+}
+
+static inline void
+common_semi_set_ret(CPUState *cs, target_ulong ret)
+{
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+ env->gpr[3] = ret;
+}
+
+static inline bool
+common_semi_sys_exit_extended(CPUState *cs, int nr)
+{
+ return (nr == TARGET_SYS_EXIT_EXTENDED || sizeof(target_ulong) == 8);
+}
+
+#endif
+
/*
* Allocate a new guest file descriptor and return it; if we
* couldn't allocate a new fd then return -1.
@@ -450,6 +475,12 @@ static target_ulong common_semi_flen_buf(CPUState *cs)
sp = env->gpr[xSP];
#endif
+#ifdef TARGET_PPC64
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+ CPUPPCState *env = &cpu->env;
+
+ sp = env->gpr[1];
+#endif
return sp - 64;
}
@@ -780,6 +811,8 @@ static inline bool is_64bit_semihosting(CPUArchState *env)
return is_a64(env);
#elif defined(TARGET_RISCV)
return riscv_cpu_mxl(env) != MXL_RV32;
+#elif defined(TARGET_PPC64)
+ return true;
#else
#error un-handled architecture
#endif
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index 047b24ba50..349104ad79 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -129,8 +129,9 @@ enum {
POWERPC_EXCP_SYSCALL_VECTORED = 102, /* scv exception
*/
POWERPC_EXCP_PERFM_EBB = 103, /* Performance Monitor EBB Exception
*/
POWERPC_EXCP_EXTERNAL_EBB = 104, /* External EBB Exception
*/
+ POWERPC_EXCP_SEMIHOST = 105, /* Semihosting Exception */
/* EOL
*/
- POWERPC_EXCP_NB = 105,
+ POWERPC_EXCP_NB = 106,
/* QEMU exceptions: special cases we want to stop translation
*/
POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only
*/
};
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index d3e2cfcd71..af34a57082 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -25,6 +25,7 @@
#include "helper_regs.h"
#include "trace.h"
+#include "semihosting/common-semi.h"
#ifdef CONFIG_TCG
#include "exec/helper-proto.h"
@@ -100,6 +101,7 @@ static const char *powerpc_excp_name(int excp)
case POWERPC_EXCP_SDOOR_HV: return "SDOOR_HV";
case POWERPC_EXCP_HVIRT: return "HVIRT";
case POWERPC_EXCP_SYSCALL_VECTORED: return "SYSCALL_VECTORED";
+ case POWERPC_EXCP_SEMIHOST: return "SEMIHOST";
default:
g_assert_not_reached();
}
@@ -1327,6 +1329,13 @@ static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
target_ulong msr, new_msr, vector;
int srr0, srr1, lev = -1;
+ /* Handle semihost exceptions first */
+ if (excp == POWERPC_EXCP_SEMIHOST) {
+ env->gpr[3] = do_common_semihosting(cs);
+ env->nip += 4;
+ return;
+ }
+
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index 408ae26173..c013889a84 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -4520,6 +4520,20 @@ static void gen_sc(DisasContext *ctx)
uint32_t lev;
lev = (ctx->opcode >> 5) & 0x7F;
+
+#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
+ /*
+ * PowerPC semihosting uses the following
+ * instruction to flag a semihosting call:
+ *
+ * sc 7 0x440000e2
+ */
+ if (lev == 7) {
+ gen_exception(ctx, POWERPC_EXCP_SEMIHOST);
+ return;
+ }
+#endif
+
gen_exception_err(ctx, POWERPC_SYSCALL, lev);
}