qemu-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]