From: Christopher Covington <cov@codeaurora.org>
To: qemu-devel@nongnu.org
Cc: Christopher Covington <cov@codeaurora.org>
Subject: [Qemu-devel] [RFC 02/14] Added semihosting support for A64 in full-system mode
Date: Wed, 5 Aug 2015 12:51:11 -0400 [thread overview]
Message-ID: <1438793483-12721-3-git-send-email-cov@codeaurora.org> (raw)
In-Reply-To: <1438793483-12721-1-git-send-email-cov@codeaurora.org>
This is for full-system only; not implemented in user mode
Written by Derek Hower.
Signed-off-by: Christopher Covington <cov@codeaurora.org>
---
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
next prev parent reply other threads:[~2015-08-05 16:51 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-05 16:51 [Qemu-devel] RFC: ARM Semihosting, PMU, and BBV Changes Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 01/14] Make unknown semihosting calls non-fatal Christopher Covington
2015-08-06 9:11 ` Alex Bennée
2015-08-06 17:59 ` Christopher Covington
2015-08-05 16:51 ` Christopher Covington [this message]
2015-08-11 18:16 ` [Qemu-devel] [RFC 02/14] Added semihosting support for A64 in full-system mode Peter Maydell
2015-08-05 16:51 ` [Qemu-devel] [RFC 03/14] Fix makefile Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 04/14] Modify load exclusive/store exclusive to use physical addresses with the monitor Christopher Covington
2015-09-23 17:19 ` [Qemu-devel] [PATCHv2] target-arm: Use physical addresses for ldrex/strex Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 05/14] Fixed TLB invalidate ops Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 06/14] Added support for block profiling for AArch32 and Aarch64 Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 07/14] Add PMU to ARM virt platform Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 08/14] Add instruction-counting infrastructure to target-arm Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 09/14] Implement remaining PMU functionality Christopher Covington
2016-02-02 21:22 ` Alistair Francis
2016-02-02 23:01 ` Christopher Covington
2016-02-02 23:22 ` Alistair Francis
2016-02-03 18:37 ` Peter Maydell
2016-02-04 0:37 ` Alistair Francis
2015-08-05 16:51 ` [Qemu-devel] [RFC 10/14] bbvec: Move mode/PID change detection to register writes Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 11/14] Print bbvec stats on 'magic' exceptions Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 12/14] bbvec: Detect mode changes after uncached_cpsr update Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 13/14] Enable negative icount values for QEMU Christopher Covington
2015-08-05 16:51 ` [Qemu-devel] [RFC 14/14] bbvec: Properly detect conditional thumb2 branching instructions Christopher Covington
2015-08-11 15:27 ` [Qemu-devel] RFC: ARM Semihosting, PMU, and BBV Changes Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1438793483-12721-3-git-send-email-cov@codeaurora.org \
--to=cov@codeaurora.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.