[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFC 02/14] Added semihosting support for A64 in full-syste
From: |
Christopher Covington |
Subject: |
[Qemu-devel] [RFC 02/14] Added semihosting support for A64 in full-system mode |
Date: |
Wed, 5 Aug 2015 12:51:11 -0400 |
This is for full-system only; not implemented in user mode
Written by Derek Hower.
Signed-off-by: Christopher Covington <address@hidden>
---
include/exec/softmmu-semi.h | 21 ++++++-
target-arm/arm-semi.c | 142 ++++++++++++++++++++++++++++++++++++--------
target-arm/cpu.h | 3 +-
target-arm/helper-a64.c | 28 ++++++++-
target-arm/helper.c | 1 +
target-arm/internals.h | 8 +++
target-arm/translate-a64.c | 2 +-
7 files changed, 174 insertions(+), 31 deletions(-)
diff --git a/include/exec/softmmu-semi.h b/include/exec/softmmu-semi.h
index 8401f7d..9ab8353 100644
--- a/include/exec/softmmu-semi.h
+++ b/include/exec/softmmu-semi.h
@@ -9,6 +9,13 @@
#ifndef SOFTMMU_SEMI_H
#define SOFTMMU_SEMI_H 1
+static inline uint64_t softmmu_tget64(CPUArchState *env, uint64_t addr)
+{
+ uint64_t val;
+
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 8, 0);
+ return tswap64(val);
+}
static inline uint32_t softmmu_tget32(CPUArchState *env, uint32_t addr)
{
uint32_t val;
@@ -24,19 +31,27 @@ static inline uint32_t softmmu_tget8(CPUArchState *env,
uint32_t addr)
return val;
}
+#define get_user_u64(arg, p) ({ arg = softmmu_tget64(env, p) ; 0; })
#define get_user_u32(arg, p) ({ arg = softmmu_tget32(env, p) ; 0; })
#define get_user_u8(arg, p) ({ arg = softmmu_tget8(env, p) ; 0; })
#define get_user_ual(arg, p) get_user_u32(arg, p)
+static inline void softmmu_tput64(CPUArchState *env, uint64_t addr, uint64_t
val)
+{
+ val = tswap64(val);
+ cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 8, 1);
+}
+
static inline void softmmu_tput32(CPUArchState *env, uint32_t addr, uint32_t
val)
{
val = tswap32(val);
cpu_memory_rw_debug(ENV_GET_CPU(env), addr, (uint8_t *)&val, 4, 1);
}
+#define put_user_u64(arg, p) ({ softmmu_tput64(env, p, arg) ; 0; })
#define put_user_u32(arg, p) ({ softmmu_tput32(env, p, arg) ; 0; })
#define put_user_ual(arg, p) put_user_u32(arg, p)
-static void *softmmu_lock_user(CPUArchState *env, uint32_t addr, uint32_t len,
+static void *softmmu_lock_user(CPUArchState *env, target_ulong addr, uint32_t
len,
int copy)
{
uint8_t *p;
@@ -48,11 +63,11 @@ static void *softmmu_lock_user(CPUArchState *env, uint32_t
addr, uint32_t len,
return p;
}
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
-static char *softmmu_lock_user_string(CPUArchState *env, uint32_t addr)
+static char *softmmu_lock_user_string(CPUArchState *env, target_ulong addr)
{
char *p;
char *s;
- uint8_t c;
+ uint8_t c = 0;
/* TODO: Make this something that isn't fixed size. */
s = p = malloc(1024);
if (!s) {
diff --git a/target-arm/arm-semi.c b/target-arm/arm-semi.c
index bcc70ec..b89ea8f 100644
--- a/target-arm/arm-semi.c
+++ b/target-arm/arm-semi.c
@@ -4,6 +4,9 @@
* Copyright (c) 2005, 2007 CodeSourcery.
* Written by Paul Brook.
*
+ * Copyright (c) 2015 the Linux Foundation.
+ * Written by Derek Hower.
+ *
* 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
@@ -140,19 +143,35 @@ static void arm_semi_cb(CPUState *cs, target_ulong ret,
target_ulong err)
#else
syscall_err = err;
#endif
- env->regs[0] = ret;
+ if (env->aarch64) {
+ env->xregs[0] = ret;
+ } else {
+ env->regs[0] = ret;
+ }
} else {
/* Fixup syscalls that use nonstardard return conventions. */
switch (env->regs[0]) {
case TARGET_SYS_WRITE:
case TARGET_SYS_READ:
+ if (env->aarch64) {
+ env->xregs[0] = arm_semi_syscall_len - ret;
+ } else {
env->regs[0] = arm_semi_syscall_len - ret;
+ }
break;
case TARGET_SYS_SEEK:
+ if (env->aarch64) {
+ env->xregs[0] = 0;
+ } else {
env->regs[0] = 0;
+ }
break;
default:
+ if (env->aarch64) {
+ env->xregs[0] = ret;
+ } else {
env->regs[0] = ret;
+ }
break;
}
}
@@ -165,8 +184,13 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong
ret, target_ulong err)
/* The size is always stored in big-endian order, extract
the value. We assume the size always fit in 32 bits. */
uint32_t size;
- cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
- env->regs[0] = be32_to_cpu(size);
+ if (env->aarch64) {
+ cpu_memory_rw_debug(cs, env->pc-64+32, (uint8_t *)&size, 4, 0);
+ env->xregs[0] = be32_to_cpu(size);
+ } else {
+ cpu_memory_rw_debug(cs, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
+ env->regs[0] = be32_to_cpu(size);
+ }
#ifdef CONFIG_USER_ONLY
((TaskState *)cs->opaque)->swi_errno = err;
#else
@@ -177,14 +201,28 @@ static void arm_semi_flen_cb(CPUState *cs, target_ulong
ret, target_ulong err)
/* Read the input value from the argument block; fail the semihosting
* call if the memory read fails.
*/
-#define GET_ARG(n) do { \
- if (get_user_ual(arg ## n, args + (n) * 4)) { \
- return (uint32_t)-1; \
+#define GET_ARG(n) do { \
+ if (env->aarch64) { \
+ if (get_user_u64(arg ## n, args + (n) * 8)) { \
+ return (target_ulong)-1; \
+ } \
+ } else { \
+ if (get_user_ual(arg ## n, (uint32_t) args + (n) * 4)) { \
+ return (target_ulong)-1; \
+ } \
+ } \
+ } while (0)
+
+#define SET_ARG(n, val) \
+ ({ \
+ if (env->aarch64) { \
+ ret = put_user_u64(val, args + (n) * 8); \
+ } else { \
+ ret = put_user_ual(val, args + (n) * 4); \
} \
-} while (0)
-
-#define SET_ARG(n, val) put_user_ual(val, args + (n) * 4)
-uint32_t do_arm_semihosting(CPUARMState *env)
+ 0; \
+ })
+target_ulong do_arm_semihosting(CPUARMState *env)
{
target_ulong args;
target_ulong arg0, arg1, arg2, arg3;
@@ -200,8 +238,13 @@ uint32_t do_arm_semihosting(CPUARMState *env)
CPUARMState *ts = env;
#endif
- nr = env->regs[0];
- args = env->regs[1];
+ if (env->aarch64) {
+ nr = env->xregs[0];
+ args = env->xregs[1];
+ } else {
+ nr = env->regs[0];
+ args = env->regs[1];
+ }
switch (nr) {
case TARGET_SYS_OPEN:
GET_ARG(0);
@@ -224,9 +267,13 @@ uint32_t do_arm_semihosting(CPUARMState *env)
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", arg0,
(int)arg2+1, gdb_open_modeflags[arg1]);
- ret = env->regs[0];
+ if (env->aarch64) {
+ ret = env->xregs[0];
+ } else {
+ ret = env->regs[0];
+ }
} else {
- ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
+ ret = set_swi_errno(ts, open(s, open_modeflags[arg1], 0644));
}
unlock_user(s, arg0, 0);
return ret;
@@ -234,7 +281,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(0);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "close,%x", arg0);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
return set_swi_errno(ts, close(arg0));
}
@@ -248,7 +299,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
/* Write to debug console. stderr is near enough. */
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
return write(STDERR_FILENO, &c, 1);
}
@@ -260,7 +315,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
len = strlen(s);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
- ret = env->regs[0];
+ if (env->aarch64) {
+ ret = env->xregs[0];
+ } else {
+ ret = env->regs[0];
+ }
} else {
ret = write(STDERR_FILENO, s, len);
}
@@ -274,7 +333,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", arg0, arg1, len);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
s = lock_user(VERIFY_READ, arg1, len, 1);
if (!s) {
@@ -295,7 +358,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
if (use_gdb_syscalls()) {
arm_semi_syscall_len = len;
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", arg0, arg1, len);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
s = lock_user(VERIFY_WRITE, arg1, len, 0);
if (!s) {
@@ -317,7 +384,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(0);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "isatty,%x", arg0);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
return isatty(arg0);
}
@@ -326,7 +397,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", arg0, arg1);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
ret = set_swi_errno(ts, lseek(arg0, arg1, SEEK_SET));
if (ret == (uint32_t)-1)
@@ -336,9 +411,16 @@ uint32_t do_arm_semihosting(CPUARMState *env)
case TARGET_SYS_FLEN:
GET_ARG(0);
if (use_gdb_syscalls()) {
+ if (env->aarch64) {
+ gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
+ arg0, env->pc-64);
+ return env->xregs[0];
+
+ } else {
gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
arg0, env->regs[13]-64);
return env->regs[0];
+ }
} else {
struct stat buf;
ret = set_swi_errno(ts, fstat(arg0, &buf));
@@ -354,7 +436,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "unlink,%s", arg0, (int)arg1+1);
- ret = env->regs[0];
+ if (env->aarch64) {
+ ret = env->xregs[0];
+ } else {
+ ret = env->regs[0];
+ }
} else {
s = lock_user_string(arg0);
if (!s) {
@@ -373,7 +459,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
arg0, (int)arg1+1, arg2, (int)arg3+1);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
char *s2;
s = lock_user_string(arg0);
@@ -398,7 +488,11 @@ uint32_t do_arm_semihosting(CPUARMState *env)
GET_ARG(1);
if (use_gdb_syscalls()) {
gdb_do_syscall(arm_semi_cb, "system,%s", arg0, (int)arg1+1);
- return env->regs[0];
+ if (env->aarch64) {
+ return env->xregs[0];
+ } else {
+ return env->regs[0];
+ }
} else {
s = lock_user_string(arg0);
if (!s) {
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index d4a5899..2525569 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_ARMV8_HLT 16 /* avoid conflict with cpu-defs.h:EXCP_HLT */
#define ARMV7M_EXCP_RESET 1
#define ARMV7M_EXCP_NMI 2
@@ -489,7 +490,7 @@ typedef struct CPUARMState {
ARMCPU *cpu_arm_init(const char *cpu_model);
int cpu_arm_exec(CPUARMState *s);
-uint32_t do_arm_semihosting(CPUARMState *env);
+target_ulong do_arm_semihosting(CPUARMState *env);
void aarch64_sync_32_to_64(CPUARMState *env);
void aarch64_sync_64_to_32(CPUARMState *env);
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 861f6fa..8803293 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -466,6 +466,14 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
unsigned int new_el = arm_excp_target_el(cs, cs->exception_index);
target_ulong addr = env->cp15.vbar_el[new_el];
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
+#ifndef CONFIG_USER_ONLY
+ uint64_t mask;
+#endif
+
+ uint32_t syndrome =
+ cs->exception_index == EXCP_ARMV8_HLT ?
+ env->exception.syndrome & ~0xffff :
+ env->exception.syndrome;
if (arm_current_el(env) < new_el) {
if (env->aarch64) {
@@ -482,7 +490,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
- env->exception.syndrome);
+ syndrome);
}
if (arm_is_psci_call(cpu, cs->exception_index)) {
@@ -504,8 +512,24 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
case EXCP_HVC:
case EXCP_HYP_TRAP:
case EXCP_SMC:
- env->cp15.esr_el[new_el] = env->exception.syndrome;
+ env->cp15.esr_el[new_el] = syndrome;
break;
+#ifndef CONFIG_USER_ONLY
+ case EXCP_ARMV8_HLT:
+ if (env->aarch64) {
+ if (semihosting_enabled) {
+ mask = env->exception.syndrome & 0xffff;
+ if (mask == 0xf000 ) {
+ env->xregs[0] = do_arm_semihosting(env);
+ qemu_log_mask(CPU_LOG_INT, "...handled a semihosting call\n");
+ return;
+ }
+ } else {
+ cpu_abort(cs, "Skipping semihosting call!\n");
+ }
+ }
+ break;
+#endif
case EXCP_IRQ:
case EXCP_VIRQ:
addr += 0x80;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e4e4931..4491b05 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -12,6 +12,7 @@
#include <zlib.h> /* For crc32 */
#ifndef CONFIG_USER_ONLY
+
static inline int get_phys_addr(CPUARMState *env, target_ulong address,
int access_type, ARMMMUIdx mmu_idx,
hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot,
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 2cc3017..ddbbc0f 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -50,6 +50,7 @@ static const char * const excnames[] = {
[EXCP_IRQ] = "IRQ",
[EXCP_FIQ] = "FIQ",
[EXCP_BKPT] = "Breakpoint",
+ [EXCP_ARMV8_HLT] = "HLT",
[EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
[EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
[EXCP_STREX] = "QEMU intercept of STREX",
@@ -260,6 +261,13 @@ static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool
is_thumb)
| (is_thumb ? 0 : ARM_EL_IL);
}
+static inline uint32_t syn_aa64_hlt(uint32_t imm16)
+{
+ // architecturally, the syndrome is uncategorized. We add the imm16 field so
+ // that it can be accessed later for semihosting
+ return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 &
0xffff);
+}
+
static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
int crn, int crm, int rt,
int isread)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0b192a1..14a501c 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1544,7 +1544,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
break;
}
/* HLT */
- unsupported_encoding(s, insn);
+ gen_exception_insn(s, 0, EXCP_ARMV8_HLT, syn_aa64_hlt(imm16));
break;
case 5:
if (op2_ll < 1 || op2_ll > 3) {
--
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
- [Qemu-devel] RFC: ARM Semihosting, PMU, and BBV Changes, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 01/14] Make unknown semihosting calls non-fatal, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 03/14] Fix makefile, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 04/14] Modify load exclusive/store exclusive to use physical addresses with the monitor, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 02/14] Added semihosting support for A64 in full-system mode,
Christopher Covington <=
- [Qemu-devel] [RFC 05/14] Fixed TLB invalidate ops., Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 12/14] bbvec: Detect mode changes after uncached_cpsr update, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 10/14] bbvec: Move mode/PID change detection to register writes, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 07/14] Add PMU to ARM virt platform, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 08/14] Add instruction-counting infrastructure to target-arm, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 13/14] Enable negative icount values for QEMU., Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 11/14] Print bbvec stats on 'magic' exceptions, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 09/14] Implement remaining PMU functionality, Christopher Covington, 2015/08/05
- [Qemu-devel] [RFC 06/14] Added support for block profiling for AArch32 and Aarch64, Christopher Covington, 2015/08/05