diff options
-rw-r--r-- | linux-user/main.c | 3 | ||||
-rw-r--r-- | target-arm/cpu.h | 1 | ||||
-rw-r--r-- | target-arm/helper-a64.c | 6 | ||||
-rw-r--r-- | target-arm/internals.h | 2 | ||||
-rw-r--r-- | target-arm/translate-a64.c | 24 |
5 files changed, 34 insertions, 2 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 2c9658e90d..06dd296a43 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -1052,6 +1052,9 @@ void cpu_loop(CPUARMState *env) queue_signal(env, info.si_signo, &info); } break; + case EXCP_SEMIHOST: + env->xregs[0] = do_arm_semihosting(env); + break; default: fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", trapnr); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0a2533543f..c794afcdbf 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -56,6 +56,7 @@ #define EXCP_SMC 13 /* Secure Monitor Call */ #define EXCP_VIRQ 14 #define EXCP_VFIQ 15 +#define EXCP_SEMIHOST 16 /* semihosting call (A64 only) */ #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c index 08c95a3f52..02fc9b4a29 100644 --- a/target-arm/helper-a64.c +++ b/target-arm/helper-a64.c @@ -514,6 +514,12 @@ void aarch64_cpu_do_interrupt(CPUState *cs) case EXCP_VFIQ: addr += 0x100; break; + case EXCP_SEMIHOST: + qemu_log_mask(CPU_LOG_INT, + "...handling as semihosting call 0x%" PRIx64 "\n", + env->xregs[0]); + env->xregs[0] = do_arm_semihosting(env); + return; default: cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); } diff --git a/target-arm/internals.h b/target-arm/internals.h index 924aff9d04..36a56aadb0 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -36,6 +36,7 @@ static inline bool excp_is_internal(int excp) || excp == EXCP_HALTED || excp == EXCP_EXCEPTION_EXIT || excp == EXCP_KERNEL_TRAP + || excp == EXCP_SEMIHOST || excp == EXCP_STREX; } @@ -58,6 +59,7 @@ static const char * const excnames[] = { [EXCP_SMC] = "Secure Monitor Call", [EXCP_VIRQ] = "Virtual IRQ", [EXCP_VFIQ] = "Virtual FIQ", + [EXCP_SEMIHOST] = "Semihosting call", }; static inline void arm_log_exception(int idx) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index 5c13e153d4..529bb0c41d 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -30,6 +30,7 @@ #include "internals.h" #include "qemu/host-utils.h" +#include "exec/semihost.h" #include "exec/gen-icount.h" #include "exec/helper-proto.h" @@ -1553,8 +1554,27 @@ static void disas_exc(DisasContext *s, uint32_t insn) unallocated_encoding(s); break; } - /* HLT */ - unsupported_encoding(s, insn); + /* HLT. This has two purposes. + * Architecturally, it is an external halting debug instruction. + * Since QEMU doesn't implement external debug, we treat this as + * it is required for halting debug disabled: it will UNDEF. + * Secondly, "HLT 0xf000" is the A64 semihosting syscall instruction. + */ + if (semihosting_enabled() && imm16 == 0xf000) { +#ifndef CONFIG_USER_ONLY + /* In system mode, don't allow userspace access to semihosting, + * to provide some semblance of security (and for consistency + * with our 32-bit semihosting). + */ + if (s->current_el == 0) { + unsupported_encoding(s, insn); + break; + } +#endif + gen_exception_internal_insn(s, 0, EXCP_SEMIHOST); + } else { + unsupported_encoding(s, insn); + } break; case 5: if (op2_ll < 1 || op2_ll > 3) { |