All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!)
@ 2014-03-06 19:32 Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h Peter Maydell
                   ` (21 more replies)
  0 siblings, 22 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

This is v4 of the AArch64 system emulation patches, and it's
an important milestone -- this is enough to boot a Linux kernel.

Changes v3->v4:
 * reviewed patches from bottom of stack got committed to master
 * new patches at top of stack
 * addressed review issues on v8 mmu translation patch and DAIF patch

RTH: you'll probably be interested in reviewing the DC ZVA patch,
 and maybe also the syndrome info/FP fault/VFP enable patches.

This patchset owes much more to Rob Herring than the raw patch
authorship stats would suggest -- he did all the "get the thing
actually booting" work and tracked down some nasty "intermittent
hang" bugs. I did most of the syndrome related bits and some
cleanup work.

Apart from the slightly questionable use of a15mpcore_priv
in the virt patch at the end, I'm generally happy with this code.
It'll have to wait for end of hardfreeze, though.

Possible "bugfix" candidates from here would be the ARM946
patch, and implementing DC ZVA (this is a huge speedup on
linux-user code if the guest makes much use of it at all).
We also fix a problem with handling of SP in KVM AArch64,
which will be noticeable if trying to use gdb. (This is
the one Claudio reported.)

thanks
-- PMM

Peter Maydell (17):
  target-arm: Split out private-to-target functions into internals.h
  target-arm: Implement AArch64 DAIF system register
  target-arm: Define exception record for AArch64 exceptions
  target-arm: Provide correct syndrome information for cpreg access
    traps
  target-arm: Add support for generating exceptions with syndrome
    information
  target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set
  target-arm: A64: Add assertion that FP access was checked
  target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1
  target-arm: Don't mention PMU in debug feature register
  target-arm: A64: Implement DC ZVA
  target-arm: Use dedicated CPU state fields for ARM946 access bit
    registers
  target-arm: Add AArch64 ELR_EL1 register.
  target-arm: Implement SP_EL0, SP_EL1
  target-arm: Implement AArch64 SPSR_EL1
  target-arm: Move arm_log_exception() into internals.h
  target-arm: Add Cortex-A57 processor
  hw/arm/virt: Add support for Cortex-A57

Rob Herring (4):
  target-arm: Provide syndrome information for MMU faults
  target-arm: Add v8 mmu translation support
  target-arm: Implement AArch64 views of fault status and data registers
  target-arm: Implement AArch64 EL1 exception handling

 hw/arm/virt.c               |   8 +
 include/exec/softmmu_exec.h |  36 ++++
 linux-user/main.c           |  56 +++---
 target-arm/cpu-qom.h        |   4 +
 target-arm/cpu.c            |  10 +-
 target-arm/cpu.h            |  74 +++++---
 target-arm/cpu64.c          |  45 +++++
 target-arm/helper-a64.c     |  75 ++++++++
 target-arm/helper.c         | 419 ++++++++++++++++++++++++++++++++++----------
 target-arm/helper.h         |   7 +-
 target-arm/internals.h      | 267 ++++++++++++++++++++++++++++
 target-arm/kvm32.c          |  19 +-
 target-arm/kvm64.c          |  71 +++++++-
 target-arm/machine.c        |  13 +-
 target-arm/op_helper.c      |  90 +++++++++-
 target-arm/translate-a64.c  | 383 +++++++++++++++++++++++++++++++++++-----
 target-arm/translate.c      | 168 +++++++++++++-----
 target-arm/translate.h      |  15 +-
 18 files changed, 1499 insertions(+), 261 deletions(-)
 create mode 100644 target-arm/internals.h

-- 
1.9.0

^ permalink raw reply	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  7:13   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register Peter Maydell
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Currently cpu.h defines a mixture of functions and types needed by
the rest of QEMU and those needed only by files within target-arm/.
Split the latter out into a new header so they aren't needlessly
exposed further than required.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.c           |  1 +
 target-arm/cpu.h           | 20 -------------------
 target-arm/helper.c        |  1 +
 target-arm/internals.h     | 49 ++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/kvm32.c         |  1 +
 target-arm/op_helper.c     |  1 +
 target-arm/translate-a64.c |  1 +
 target-arm/translate.c     |  1 +
 8 files changed, 55 insertions(+), 20 deletions(-)
 create mode 100644 target-arm/internals.h

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 1ce8a9b..bc8eac9 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -19,6 +19,7 @@
  */
 
 #include "cpu.h"
+#include "internals.h"
 #include "qemu-common.h"
 #include "hw/qdev-properties.h"
 #include "qapi/qmp/qerror.h"
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 49fef3f..6252ff3 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -111,11 +111,6 @@ typedef struct ARMGenericTimer {
 #define GTIMER_VIRT 1
 #define NUM_GTIMERS 2
 
-/* Scale factor for generic timers, ie number of ns per tick.
- * This gives a 62.5MHz timer.
- */
-#define GTIMER_SCALE 16
-
 typedef struct CPUARMState {
     /* Regs for current mode.  */
     uint32_t regs[16];
@@ -318,11 +313,7 @@ typedef struct CPUARMState {
 #include "cpu-qom.h"
 
 ARMCPU *cpu_arm_init(const char *cpu_model);
-void arm_translate_init(void);
-void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
 int cpu_arm_exec(CPUARMState *s);
-int bank_number(int mode);
-void switch_mode(CPUARMState *, int);
 uint32_t do_arm_semihosting(CPUARMState *env);
 
 static inline bool is_a64(CPUARMState *env)
@@ -545,17 +536,6 @@ static inline void vfp_set_fpcr(CPUARMState *env, uint32_t val)
     vfp_set_fpscr(env, new_fpscr);
 }
 
-enum arm_fprounding {
-    FPROUNDING_TIEEVEN,
-    FPROUNDING_POSINF,
-    FPROUNDING_NEGINF,
-    FPROUNDING_ZERO,
-    FPROUNDING_TIEAWAY,
-    FPROUNDING_ODD
-};
-
-int arm_rmode_to_sf(int rmode);
-
 enum arm_cpu_mode {
   ARM_CPU_MODE_USR = 0x10,
   ARM_CPU_MODE_FIQ = 0x11,
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d44e603..3d65bae 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1,4 +1,5 @@
 #include "cpu.h"
+#include "internals.h"
 #include "exec/gdbstub.h"
 #include "helper.h"
 #include "qemu/host-utils.h"
diff --git a/target-arm/internals.h b/target-arm/internals.h
new file mode 100644
index 0000000..a38a57f
--- /dev/null
+++ b/target-arm/internals.h
@@ -0,0 +1,49 @@
+/*
+ * QEMU ARM CPU -- internal functions and types
+ *
+ * Copyright (c) 2014 Linaro Ltd
+ *
+ * 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 (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see
+ * <http://www.gnu.org/licenses/gpl-2.0.html>
+ *
+ * This header defines functions, types, etc which need to be shared
+ * between different source files within target-arm/ but which are
+ * private to it and not required by the rest of QEMU.
+ */
+
+#ifndef TARGET_ARM_INTERNALS_H
+#define TARGET_ARM_INTERNALS_H
+
+/* Scale factor for generic timers, ie number of ns per tick.
+ * This gives a 62.5MHz timer.
+ */
+#define GTIMER_SCALE 16
+
+int bank_number(int mode);
+void switch_mode(CPUARMState *, int);
+void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
+void arm_translate_init(void);
+
+enum arm_fprounding {
+    FPROUNDING_TIEEVEN,
+    FPROUNDING_POSINF,
+    FPROUNDING_NEGINF,
+    FPROUNDING_ZERO,
+    FPROUNDING_TIEAWAY,
+    FPROUNDING_ODD
+};
+
+int arm_rmode_to_sf(int rmode);
+
+#endif
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index a4fde07..b21f844 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -21,6 +21,7 @@
 #include "sysemu/kvm.h"
 #include "kvm_arm.h"
 #include "cpu.h"
+#include "internals.h"
 #include "hw/arm/arm.h"
 
 static inline void set_feature(uint64_t *features, int feature)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 7d06d2f..1458cd3 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -18,6 +18,7 @@
  */
 #include "cpu.h"
 #include "helper.h"
+#include "internals.h"
 
 #define SIGNBIT (uint32_t)0x80000000
 #define SIGNBIT64 ((uint64_t)1 << 63)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index f89b0a5..156fda2 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -26,6 +26,7 @@
 #include "tcg-op.h"
 #include "qemu/log.h"
 #include "translate.h"
+#include "internals.h"
 #include "qemu/host-utils.h"
 
 #include "exec/gen-icount.h"
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9612da7..4a53313 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -25,6 +25,7 @@
 #include <inttypes.h>
 
 #include "cpu.h"
+#include "internals.h"
 #include "disas/disas.h"
 #include "tcg-op.h"
 #include "qemu/log.h"
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  2:30   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions Peter Maydell
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Implement the DAIF system register which is a view of the
DAIF bits in PSTATE. To avoid needing a readfn, we widen
the daif field in CPUARMState to uint64_t.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h    |  2 +-
 target-arm/helper.c | 20 ++++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 6252ff3..45eb6a2 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -160,7 +160,7 @@ typedef struct CPUARMState {
     uint32_t GE; /* cpsr[19:16] */
     uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
     uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
-    uint32_t daif; /* exception masks, in the bits they are in in PSTATE */
+    uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
 
     /* System control coprocessor (cp15) */
     struct {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3d65bae..f7168c1 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1593,6 +1593,20 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
     vfp_set_fpsr(env, value);
 }
 
+static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
+        return CP_ACCESS_TRAP;
+    }
+    return CP_ACCESS_OK;
+}
+
+static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                            uint64_t value)
+{
+    env->daif = value & PSTATE_DAIF;
+}
+
 static CPAccessResult aa64_cacheop_access(CPUARMState *env,
                                           const ARMCPRegInfo *ri)
 {
@@ -1636,6 +1650,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     { .name = "NZCV", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
       .access = PL0_RW, .type = ARM_CP_NZCV },
+    { .name = "DAIF", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 2,
+      .type = ARM_CP_NO_MIGRATE,
+      .access = PL0_RW, .accessfn = aa64_daif_access,
+      .fieldoffset = offsetof(CPUARMState, daif),
+      .writefn = aa64_daif_write, .resetfn = arm_cp_reset_ignore },
     { .name = "FPCR", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
       .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  2:53   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps Peter Maydell
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

For AArch32 exceptions, the only information provided about
the cause of an exception is the individual exception type (data
abort, undef, etc), which we store in env->exception_index. For
AArch64, the CPU provides much more detail about the cause of
the exception, which can be found in the syndrome register.
Create a set of fields in CPUARMState which must be filled in
whenever an exception is raised, so that exception entry can
correctly fill in the syndrome register for the guest.
This includes the information which in AArch32 appears in
the DFAR and IFAR (fault address registers) and the DFSR
and IFSR (fault status registers) for data aborts and
prefetch aborts, since if we end up taking the MMU fault
to AArch64 rather than AArch32 this will need to end up
in different system registers.

This patch does a refactoring which moves the setting of the
AArch32 DFAR/DFSR/IFAR/IFSR from the point where the exception
is raised to the point where it is taken. (This is no change
for cores with an MMU, retains the existing clearly incorrect
behaviour for ARM946 of trashing the MP access permissions
registers which share the c5_data and c5_insn state fields,
and has no effect for v7M because we don't implement its
MPU fault status or address registers.)

As a side effect of the cleanup we fix a bug in the AArch64
linux-user mode code where we were passing a 64 bit fault
address through the 32 bit c6_data/c6_insn fields: it now
goes via the always-64-bit exception.vaddress.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/main.c    | 56 ++++++++++++++++++++++------------------------------
 target-arm/cpu.h     | 15 ++++++++++++++
 target-arm/helper.c  | 23 ++++++++++++---------
 target-arm/machine.c |  3 +++
 4 files changed, 56 insertions(+), 41 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 9192977..a17ee47 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -483,17 +483,17 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
     addr = env->regs[2];
 
     if (get_user_u64(oldval, env->regs[0])) {
-        env->cp15.c6_data = env->regs[0];
+        env->exception.vaddress = env->regs[0];
         goto segv;
     };
 
     if (get_user_u64(newval, env->regs[1])) {
-        env->cp15.c6_data = env->regs[1];
+        env->exception.vaddress = env->regs[1];
         goto segv;
     };
 
     if (get_user_u64(val, addr)) {
-        env->cp15.c6_data = addr;
+        env->exception.vaddress = addr;
         goto segv;
     }
 
@@ -501,7 +501,7 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
         val = newval;
 
         if (put_user_u64(val, addr)) {
-            env->cp15.c6_data = addr;
+            env->exception.vaddress = addr;
             goto segv;
         };
 
@@ -523,7 +523,7 @@ segv:
     info.si_errno = 0;
     /* XXX: check env->error_code */
     info.si_code = TARGET_SEGV_MAPERR;
-    info._sifields._sigfault._addr = env->cp15.c6_data;
+    info._sifields._sigfault._addr = env->exception.vaddress;
     queue_signal(env, info.si_signo, &info);
 
     end_exclusive();
@@ -620,14 +620,14 @@ static int do_strex(CPUARMState *env)
         abort();
     }
     if (segv) {
-        env->cp15.c6_data = addr;
+        env->exception.vaddress = addr;
         goto done;
     }
     if (size == 3) {
         uint32_t valhi;
         segv = get_user_u32(valhi, addr + 4);
         if (segv) {
-            env->cp15.c6_data = addr + 4;
+            env->exception.vaddress = addr + 4;
             goto done;
         }
         val = deposit64(val, 32, 32, valhi);
@@ -650,14 +650,14 @@ static int do_strex(CPUARMState *env)
         break;
     }
     if (segv) {
-        env->cp15.c6_data = addr;
+        env->exception.vaddress = addr;
         goto done;
     }
     if (size == 3) {
         val = env->regs[(env->exclusive_info >> 12) & 0xf];
         segv = put_user_u32(val, addr + 4);
         if (segv) {
-            env->cp15.c6_data = addr + 4;
+            env->exception.vaddress = addr + 4;
             goto done;
         }
     }
@@ -832,12 +832,14 @@ void cpu_loop(CPUARMState *env)
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
             break;
+        case EXCP_STREX:
+            if (!do_strex(env)) {
+                break;
+            }
+            /* fall through for segv */
         case EXCP_PREFETCH_ABORT:
-            addr = env->cp15.c6_insn;
-            goto do_segv;
         case EXCP_DATA_ABORT:
-            addr = env->cp15.c6_data;
-        do_segv:
+            addr = env->exception.vaddress;
             {
                 info.si_signo = SIGSEGV;
                 info.si_errno = 0;
@@ -865,12 +867,6 @@ void cpu_loop(CPUARMState *env)
             if (do_kernel_trap(env))
               goto error;
             break;
-        case EXCP_STREX:
-            if (do_strex(env)) {
-                addr = env->cp15.c6_data;
-                goto do_segv;
-            }
-            break;
         default:
         error:
             fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
@@ -933,7 +929,7 @@ static int do_strex_a64(CPUARMState *env)
         abort();
     }
     if (segv) {
-        env->cp15.c6_data = addr;
+        env->exception.vaddress = addr;
         goto error;
     }
     if (val != env->exclusive_val) {
@@ -946,7 +942,7 @@ static int do_strex_a64(CPUARMState *env)
             segv = get_user_u64(val, addr + 8);
         }
         if (segv) {
-            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+            env->exception.vaddress = addr + (size == 2 ? 4 : 8);
             goto error;
         }
         if (val != env->exclusive_high) {
@@ -981,7 +977,7 @@ static int do_strex_a64(CPUARMState *env)
             segv = put_user_u64(val, addr + 8);
         }
         if (segv) {
-            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+            env->exception.vaddress = addr + (size == 2 ? 4 : 8);
             goto error;
         }
     }
@@ -1037,12 +1033,14 @@ void cpu_loop(CPUARMState *env)
             info._sifields._sigfault._addr = env->pc;
             queue_signal(env, info.si_signo, &info);
             break;
+        case EXCP_STREX:
+            if (!do_strex_a64(env)) {
+                break;
+            }
+            /* fall through for segv */
         case EXCP_PREFETCH_ABORT:
-            addr = env->cp15.c6_insn;
-            goto do_segv;
         case EXCP_DATA_ABORT:
-            addr = env->cp15.c6_data;
-        do_segv:
+            addr = env->exception.vaddress;
             info.si_signo = SIGSEGV;
             info.si_errno = 0;
             /* XXX: check env->error_code */
@@ -1060,12 +1058,6 @@ void cpu_loop(CPUARMState *env)
                 queue_signal(env, info.si_signo, &info);
             }
             break;
-        case EXCP_STREX:
-            if (do_strex_a64(env)) {
-                addr = env->cp15.c6_data;
-                goto do_segv;
-            }
-            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 45eb6a2..9982e47 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -229,6 +229,21 @@ typedef struct CPUARMState {
         int pending_exception;
     } v7m;
 
+    /* Information associated with an exception about to be taken:
+     * code which raises an exception must set env->exception_index and
+     * the relevant parts of this structure; the cpu_do_interrupt function
+     * will then set the guest-visible registers as part of the exception
+     * entry process.
+     */
+    struct {
+        uint32_t syndrome; /* AArch64 format syndrome register */
+        uint32_t fsr; /* AArch32 format fault status register info */
+        uint64_t vaddress; /* virtual addr associated with exception, if any */
+        /* If we implement EL2 we will also need to store information
+         * about the intermediate physical address for stage 2 faults.
+         */
+    } exception;
+
     /* Thumb-2 EE state.  */
     uint32_t teecr;
     uint32_t teehbr;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index f7168c1..2fa01ae 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2610,12 +2610,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
 int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
                               int mmu_idx)
 {
+    env->exception.vaddress = address;
     if (rw == 2) {
         env->exception_index = EXCP_PREFETCH_ABORT;
-        env->cp15.c6_insn = address;
     } else {
         env->exception_index = EXCP_DATA_ABORT;
-        env->cp15.c6_data = address;
     }
     return 1;
 }
@@ -2820,6 +2819,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
         return;
     case EXCP_PREFETCH_ABORT:
     case EXCP_DATA_ABORT:
+        /* TODO: if we implemented the MPU registers, this is where we
+         * should set the MMFAR, etc from exception.fsr and exception.vaddress.
+         */
         armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
         return;
     case EXCP_BKPT:
@@ -2934,9 +2936,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
                 return;
             }
         }
-        env->cp15.c5_insn = 2;
+        env->exception.fsr = 2;
         /* Fall through to prefetch abort.  */
     case EXCP_PREFETCH_ABORT:
+        env->cp15.c5_insn = env->exception.fsr;
+        env->cp15.c6_insn = env->exception.vaddress;
         qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
                       env->cp15.c5_insn, env->cp15.c6_insn);
         new_mode = ARM_CPU_MODE_ABT;
@@ -2945,6 +2949,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
         offset = 4;
         break;
     case EXCP_DATA_ABORT:
+        env->cp15.c5_data = env->exception.fsr;
+        env->cp15.c6_data = env->exception.vaddress;
         qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
                       env->cp15.c5_data, env->cp15.c6_data);
         new_mode = ARM_CPU_MODE_ABT;
@@ -3593,16 +3599,15 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
     }
 
     if (access_type == 2) {
-        env->cp15.c5_insn = ret;
-        env->cp15.c6_insn = address;
         env->exception_index = EXCP_PREFETCH_ABORT;
     } else {
-        env->cp15.c5_data = ret;
-        if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6))
-            env->cp15.c5_data |= (1 << 11);
-        env->cp15.c6_data = address;
+        if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) {
+            ret |= (1 << 11);
+        }
         env->exception_index = EXCP_DATA_ABORT;
     }
+    env->exception.vaddress = address;
+    env->exception.fsr = ret;
     return 1;
 }
 
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 8f9e7d4..fc8825e 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -257,6 +257,9 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT64(env.exclusive_val, ARMCPU),
         VMSTATE_UINT64(env.exclusive_high, ARMCPU),
         VMSTATE_UINT64(env.features, ARMCPU),
+        VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
+        VMSTATE_UINT32(env.exception.fsr, ARMCPU),
+        VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
         VMSTATE_END_OF_LIST()
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (2 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  3:05   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information Peter Maydell
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

For exceptions taken to AArch64, if a coprocessor/system register
access fails due to a trap or enable bit then the syndrome information
must include details of the failing instruction (crn/crm/opc1/opc2
fields, etc). Make the decoder construct the syndrome information
at translate time so it can be passed at runtime to the access-check
helper function and used as required.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.h        |   2 +-
 target-arm/internals.h     | 128 +++++++++++++++++++++++++++++++++++++++++++++
 target-arm/op_helper.c     |   8 +--
 target-arm/translate-a64.c |   8 ++-
 target-arm/translate.c     |  45 +++++++++++++++-
 5 files changed, 184 insertions(+), 7 deletions(-)

diff --git a/target-arm/helper.h b/target-arm/helper.h
index 276f3a9..7f23cb8 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -57,7 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
 DEF_HELPER_3(v7m_msr, void, env, i32, i32)
 DEF_HELPER_2(v7m_mrs, i32, env, i32)
 
-DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
+DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32)
 DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
 DEF_HELPER_2(get_cp_reg, i32, env, ptr)
 DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
diff --git a/target-arm/internals.h b/target-arm/internals.h
index a38a57f..2c0db20 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -46,4 +46,132 @@ enum arm_fprounding {
 
 int arm_rmode_to_sf(int rmode);
 
+/* Valid Syndrome Register EC field values */
+enum arm_exception_class {
+    EC_UNCATEGORIZED = 0,
+    EC_WFX_TRAP = 1,
+    EC_CP15RTTRAP = 3,
+    EC_CP15RRTTRAP = 4,
+    EC_CP14RTTRAP = 5,
+    EC_CP14DTTRAP = 6,
+    EC_ADVSIMDFPACCESSTRAP = 7,
+    EC_FPIDTRAP = 8,
+    EC_CP14RRTTRAP = 0xc,
+    EC_ILLEGALSTATE = 0xe,
+    EC_AA32_SVC = 0x11,
+    EC_AA32_HVC = 0x12,
+    EC_AA32_SMC = 0x13,
+    EC_AA64_SVC = 0x15,
+    EC_AA64_HVC = 0x16,
+    EC_AA64_SMC = 0x17,
+    EC_SYSTEMREGISTERTRAP = 0x18,
+    EC_INSNABORT = 0x20,
+    EC_INSNABORT_SAME_EL = 0x21,
+    EC_PCALIGNMENT = 0x22,
+    EC_DATAABORT = 0x24,
+    EC_DATAABORT_SAME_EL = 0x25,
+    EC_SPALIGNMENT = 0x26,
+    EC_AA32_FPTRAP = 0x28,
+    EC_AA64_FPTRAP = 0x2c,
+    EC_SERROR = 0x2f,
+    EC_BREAKPOINT = 0x30,
+    EC_BREAKPOINT_SAME_EL = 0x31,
+    EC_SOFTWARESTEP = 0x32,
+    EC_SOFTWARESTEP_SAME_EL = 0x33,
+    EC_WATCHPOINT = 0x34,
+    EC_WATCHPOINT_SAME_EL = 0x35,
+    EC_AA32_BKPT = 0x38,
+    EC_VECTORCATCH = 0x3a,
+    EC_AA64_BKPT = 0x3c,
+};
+
+#define ARM_EL_EC_SHIFT 26
+#define ARM_EL_IL_SHIFT 25
+#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
+
+/* Utility functions for constructing various kinds of syndrome value.
+ * Note that in general we follow the AArch64 syndrome values; in a
+ * few cases the value in HSR for exceptions taken to AArch32 Hyp
+ * mode differs slightly, so if we ever implemented Hyp mode then the
+ * syndrome value would need some massaging on exception entry.
+ * (One example of this is that AArch64 defaults to IL bit set for
+ * exceptions which don't specifically indicate information about the
+ * trapping instruction, whereas AArch32 defaults to IL bit clear.)
+ */
+static inline uint32_t syn_uncategorized(void)
+{
+    return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
+}
+
+static inline uint32_t syn_aa64_svc(uint32_t imm16)
+{
+    return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+}
+
+static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
+{
+    return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
+        | (is_thumb ? 0 : ARM_EL_IL);
+}
+
+static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
+{
+    return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
+}
+
+static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_thumb)
+{
+    return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
+        | (is_thumb ? 0 : ARM_EL_IL);
+}
+
+static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
+                                           int crn, int crm, int rt,
+                                           int isread)
+{
+    return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
+        | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
+        | (crm << 1) | isread;
+}
+
+static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
+                                        int crn, int crm, int rt, int isread,
+                                        bool is_thumb)
+{
+    return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
+        | (is_thumb ? 0 : ARM_EL_IL)
+        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
+        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
+}
+
+static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
+                                        int crn, int crm, int rt, int isread,
+                                        bool is_thumb)
+{
+    return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
+        | (is_thumb ? 0 : ARM_EL_IL)
+        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
+        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
+}
+
+static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
+                                         int rt, int rt2, int isread,
+                                         bool is_thumb)
+{
+    return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
+        | (is_thumb ? 0 : ARM_EL_IL)
+        | (cv << 24) | (cond << 20) | (opc1 << 16)
+        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
+}
+
+static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
+                                         int rt, int rt2, int isread,
+                                         bool is_thumb)
+{
+    return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
+        | (is_thumb ? 0 : ARM_EL_IL)
+        | (cv << 24) | (cond << 20) | (opc1 << 16)
+        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
+}
+
 #endif
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 1458cd3..bef2cf6 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -274,17 +274,17 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
     }
 }
 
-void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
+void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
 {
     const ARMCPRegInfo *ri = rip;
     switch (ri->accessfn(env, ri)) {
     case CP_ACCESS_OK:
         return;
     case CP_ACCESS_TRAP:
+        env->exception.syndrome = syndrome;
+        break;
     case CP_ACCESS_TRAP_UNCATEGORIZED:
-        /* These cases will eventually need to generate different
-         * syndrome information.
-         */
+        env->exception.syndrome = syn_uncategorized();
         break;
     default:
         g_assert_not_reached();
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 156fda2..a4f9258 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1239,10 +1239,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
          * runtime; this may result in an exception.
          */
         TCGv_ptr tmpptr;
+        TCGv_i32 tcg_syn;
+        uint32_t syndrome;
+
         gen_a64_set_pc_im(s->pc - 4);
         tmpptr = tcg_const_ptr(ri);
-        gen_helper_access_check_cp_reg(cpu_env, tmpptr);
+        syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
+        tcg_syn = tcg_const_i32(syndrome);
+        gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
         tcg_temp_free_ptr(tmpptr);
+        tcg_temp_free_i32(tcg_syn);
     }
 
     /* Handle special cases first */
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 4a53313..9a81222 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6843,10 +6843,53 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
              * runtime; this may result in an exception.
              */
             TCGv_ptr tmpptr;
+            TCGv_i32 tcg_syn;
+            uint32_t syndrome;
+
+            /* Note that since we are an implementation which takes an
+             * exception on a trapped conditional instruction only if the
+             * instruction passes its condition code check, we can take
+             * advantage of the clause in the ARM ARM that allows us to set
+             * the COND field in the instruction to 0xE in all cases.
+             * We could fish the actual condition out of the insn (ARM)
+             * or the condexec bits (Thumb) but it isn't necessary.
+             */
+            switch (cpnum) {
+            case 14:
+                if (is64) {
+                    syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
+                                                 isread, s->thumb);
+                } else {
+                    syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
+                                                rt, isread, s->thumb);
+                }
+                break;
+            case 15:
+                if (is64) {
+                    syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
+                                                 isread, s->thumb);
+                } else {
+                    syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
+                                                rt, isread, s->thumb);
+                }
+                break;
+            default:
+                /* ARMv8 defines that only coprocessors 14 and 15 exist,
+                 * so this can only happen if this is an ARMv7 or earlier CPU,
+                 * in which case the syndrome information won't actually be
+                 * guest visible.
+                 */
+                assert(!arm_feature(env, ARM_FEATURE_V8));
+                syndrome = syn_uncategorized();
+                break;
+            }
+
             gen_set_pc_im(s, s->pc);
             tmpptr = tcg_const_ptr(ri);
-            gen_helper_access_check_cp_reg(cpu_env, tmpptr);
+            tcg_syn = tcg_const_i32(syndrome);
+            gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
             tcg_temp_free_ptr(tmpptr);
+            tcg_temp_free_i32(tcg_syn);
         }
 
         /* Handle special cases first */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (3 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  3:19   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults Peter Maydell
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Add new helpers exception_with_syndrome (for generating an exception
with syndrome information) and exception_uncategorized (for generating
an exception with "Unknown or Uncategorized Reason", which have a syndrome
register value of zero), and use them to generate the correct syndrome
information for exceptions which are raised directly from generated code.

This patch includes moving the A32/T32 gen_exception_insn functions
further up in the source file; they will be needed for "VFP/Neon disabled"
exception generation later.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.h        |   3 +-
 target-arm/internals.h     |  14 ++++++
 target-arm/op_helper.c     |  19 ++++++++-
 target-arm/translate-a64.c |  49 +++++++++++++++------
 target-arm/translate.c     | 103 ++++++++++++++++++++++++++++-----------------
 target-arm/translate.h     |   4 ++
 6 files changed, 138 insertions(+), 54 deletions(-)

diff --git a/target-arm/helper.h b/target-arm/helper.h
index 7f23cb8..2729ea5 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -48,7 +48,8 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32)
 
 DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
                    i32, i32, i32, i32)
-DEF_HELPER_2(exception, void, env, i32)
+DEF_HELPER_2(exception_internal, void, env, i32)
+DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32)
 DEF_HELPER_1(wfi, void, env)
 
 DEF_HELPER_3(cpsr_write, void, env, i32, i32)
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 2c0db20..9bec4e1 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -25,6 +25,20 @@
 #ifndef TARGET_ARM_INTERNALS_H
 #define TARGET_ARM_INTERNALS_H
 
+static inline bool excp_is_internal(int excp)
+{
+    /* Return true if this exception number represents a QEMU-internal
+     * exception that will not be passed to the guest.
+     */
+    return excp == EXCP_INTERRUPT
+        || excp == EXCP_HLT
+        || excp == EXCP_DEBUG
+        || excp == EXCP_HALTED
+        || excp == EXCP_EXCEPTION_EXIT
+        || excp == EXCP_KERNEL_TRAP
+        || excp == EXCP_STREX;
+}
+
 /* Scale factor for generic timers, ie number of ns per tick.
  * This gives a 62.5MHz timer.
  */
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index bef2cf6..b1db672 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -226,9 +226,26 @@ void HELPER(wfi)(CPUARMState *env)
     cpu_loop_exit(env);
 }
 
-void HELPER(exception)(CPUARMState *env, uint32_t excp)
+/* Raise an internal-to-QEMU exception. This is limited to only
+ * those EXCP values which are special cases for QEMU to interrupt
+ * execution and not to be used for exceptions which are passed to
+ * the guest (those must all have syndrome information and thus should
+ * use exception_with_syndrome).
+ */
+void HELPER(exception_internal)(CPUARMState *env, uint32_t excp)
+{
+    assert(excp_is_internal(excp));
+    env->exception_index = excp;
+    cpu_loop_exit(env);
+}
+
+/* Raise an exception with the specified syndrome register value */
+void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
+                                     uint32_t syndrome)
 {
+    assert(!excp_is_internal(excp));
     env->exception_index = excp;
+    env->exception.syndrome = syndrome;
     cpu_loop_exit(env);
 }
 
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a4f9258..b32068e 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -173,18 +173,37 @@ void gen_a64_set_pc_im(uint64_t val)
     tcg_gen_movi_i64(cpu_pc, val);
 }
 
-static void gen_exception(int excp)
+static void gen_exception_internal(int excp)
 {
-    TCGv_i32 tmp = tcg_temp_new_i32();
-    tcg_gen_movi_i32(tmp, excp);
-    gen_helper_exception(cpu_env, tmp);
-    tcg_temp_free_i32(tmp);
+    TCGv_i32 tcg_excp = tcg_const_i32(excp);
+
+    assert(excp_is_internal(excp));
+    gen_helper_exception_internal(cpu_env, tcg_excp);
+    tcg_temp_free_i32(tcg_excp);
+}
+
+static void gen_exception(int excp, uint32_t syndrome)
+{
+    TCGv_i32 tcg_excp = tcg_const_i32(excp);
+    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
+
+    gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
+    tcg_temp_free_i32(tcg_syn);
+    tcg_temp_free_i32(tcg_excp);
+}
+
+static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
+{
+    gen_a64_set_pc_im(s->pc - offset);
+    gen_exception_internal(excp);
+    s->is_jmp = DISAS_EXC;
 }
 
-static void gen_exception_insn(DisasContext *s, int offset, int excp)
+static void gen_exception_insn(DisasContext *s, int offset, int excp,
+                               uint32_t syndrome)
 {
     gen_a64_set_pc_im(s->pc - offset);
-    gen_exception(excp);
+    gen_exception(excp, syndrome);
     s->is_jmp = DISAS_EXC;
 }
 
@@ -216,7 +235,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
     } else {
         gen_a64_set_pc_im(dest);
         if (s->singlestep_enabled) {
-            gen_exception(EXCP_DEBUG);
+            gen_exception_internal(EXCP_DEBUG);
         }
         tcg_gen_exit_tb(0);
         s->is_jmp = DISAS_JUMP;
@@ -225,7 +244,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
 
 static void unallocated_encoding(DisasContext *s)
 {
-    gen_exception_insn(s, 4, EXCP_UDEF);
+    /* Unallocated and reserved encodings are uncategorized */
+    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
 }
 
 #define unsupported_encoding(s, insn)                                    \
@@ -1370,6 +1390,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
 {
     int opc = extract32(insn, 21, 3);
     int op2_ll = extract32(insn, 0, 5);
+    int imm16 = extract32(insn, 5, 16);
 
     switch (opc) {
     case 0:
@@ -1380,7 +1401,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             break;
         }
-        gen_exception_insn(s, 0, EXCP_SWI);
+        gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16));
         break;
     case 1:
         if (op2_ll != 0) {
@@ -1388,7 +1409,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
             break;
         }
         /* BRK */
-        gen_exception_insn(s, 0, EXCP_BKPT);
+        gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16));
         break;
     case 2:
         if (op2_ll != 0) {
@@ -1537,7 +1558,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     tcg_gen_mov_i64(cpu_exclusive_test, addr);
     tcg_gen_movi_i32(cpu_exclusive_info,
                      size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14));
-    gen_exception_insn(s, 4, EXCP_STREX);
+    gen_exception_internal_insn(s, 4, EXCP_STREX);
 }
 #else
 static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
@@ -9108,7 +9129,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
-                    gen_exception_insn(dc, 0, EXCP_DEBUG);
+                    gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
                     /* Advance PC so that clearing the breakpoint will
                        invalidate this TB.  */
                     dc->pc += 2;
@@ -9171,7 +9192,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
         if (dc->is_jmp != DISAS_JUMP) {
             gen_a64_set_pc_im(dc->pc);
         }
-        gen_exception(EXCP_DEBUG);
+        gen_exception_internal(EXCP_DEBUG);
     } else {
         switch (dc->is_jmp) {
         case DISAS_NEXT:
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 9a81222..094be07 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -183,12 +183,23 @@ static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
 /* Set NZCV flags from the high 4 bits of var.  */
 #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
 
-static void gen_exception(int excp)
+static void gen_exception_internal(int excp)
 {
-    TCGv_i32 tmp = tcg_temp_new_i32();
-    tcg_gen_movi_i32(tmp, excp);
-    gen_helper_exception(cpu_env, tmp);
-    tcg_temp_free_i32(tmp);
+    TCGv_i32 tcg_excp = tcg_const_i32(excp);
+
+    assert(excp_is_internal(excp));
+    gen_helper_exception_internal(cpu_env, tcg_excp);
+    tcg_temp_free_i32(tcg_excp);
+}
+
+static void gen_exception(int excp, uint32_t syndrome)
+{
+    TCGv_i32 tcg_excp = tcg_const_i32(excp);
+    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
+
+    gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
+    tcg_temp_free_i32(tcg_syn);
+    tcg_temp_free_i32(tcg_excp);
 }
 
 static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
@@ -900,6 +911,33 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
     tcg_gen_movi_i32(cpu_R[15], val);
 }
 
+static inline void
+gen_set_condexec (DisasContext *s)
+{
+    if (s->condexec_mask) {
+        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
+        TCGv_i32 tmp = tcg_temp_new_i32();
+        tcg_gen_movi_i32(tmp, val);
+        store_cpu_field(tmp, condexec_bits);
+    }
+}
+
+static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
+{
+    gen_set_condexec(s);
+    gen_set_pc_im(s, s->pc - offset);
+    gen_exception_internal(excp);
+    s->is_jmp = DISAS_JUMP;
+}
+
+static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn)
+{
+    gen_set_condexec(s);
+    gen_set_pc_im(s, s->pc - offset);
+    gen_exception(excp, syn);
+    s->is_jmp = DISAS_JUMP;
+}
+
 /* Force a TB lookup after an instruction that changes the CPU state.  */
 static inline void gen_lookup_tb(DisasContext *s)
 {
@@ -3913,25 +3951,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
     s->is_jmp = DISAS_UPDATE;
 }
 
-static inline void
-gen_set_condexec (DisasContext *s)
-{
-    if (s->condexec_mask) {
-        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
-        TCGv_i32 tmp = tcg_temp_new_i32();
-        tcg_gen_movi_i32(tmp, val);
-        store_cpu_field(tmp, condexec_bits);
-    }
-}
-
-static void gen_exception_insn(DisasContext *s, int offset, int excp)
-{
-    gen_set_condexec(s);
-    gen_set_pc_im(s, s->pc - offset);
-    gen_exception(excp);
-    s->is_jmp = DISAS_JUMP;
-}
-
 static void gen_nop_hint(DisasContext *s, int val)
 {
     switch (val) {
@@ -7141,7 +7160,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     tcg_gen_extu_i32_i64(cpu_exclusive_test, addr);
     tcg_gen_movi_i32(cpu_exclusive_info,
                      size | (rd << 4) | (rt << 8) | (rt2 << 12));
-    gen_exception_insn(s, 4, EXCP_STREX);
+    gen_exception_internal_insn(s, 4, EXCP_STREX);
 }
 #else
 static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
@@ -7651,6 +7670,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
             store_reg(s, rd, tmp);
             break;
         case 7:
+        {
+            int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
             /* SMC instruction (op1 == 3)
                and undefined instructions (op1 == 0 || op1 == 2)
                will trap */
@@ -7659,8 +7680,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
             }
             /* bkpt */
             ARCH(5);
-            gen_exception_insn(s, 4, EXCP_BKPT);
+            gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));
             break;
+        }
         case 0x8: /* signed multiply */
         case 0xa:
         case 0xc:
@@ -8667,11 +8689,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
         case 0xf:
             /* swi */
             gen_set_pc_im(s, s->pc);
+            s->svc_imm = extract32(insn, 0, 24);
             s->is_jmp = DISAS_SWI;
             break;
         default:
         illegal_op:
-            gen_exception_insn(s, 4, EXCP_UDEF);
+            gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
             break;
         }
     }
@@ -10482,9 +10505,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
             break;
 
         case 0xe: /* bkpt */
+        {
+            int imm8 = extract32(insn, 0, 8);
             ARCH(5);
-            gen_exception_insn(s, 2, EXCP_BKPT);
+            gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true));
             break;
+        }
 
         case 0xa: /* rev */
             ARCH(6);
@@ -10601,6 +10627,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
         if (cond == 0xf) {
             /* swi */
             gen_set_pc_im(s, s->pc);
+            s->svc_imm = extract32(insn, 0, 8);
             s->is_jmp = DISAS_SWI;
             break;
         }
@@ -10636,11 +10663,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
     }
     return;
 undef32:
-    gen_exception_insn(s, 4, EXCP_UDEF);
+    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
     return;
 illegal_op:
 undef:
-    gen_exception_insn(s, 2, EXCP_UDEF);
+    gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized());
 }
 
 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
@@ -10761,7 +10788,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
         if (dc->pc >= 0xffff0000) {
             /* We always get here via a jump, so know we are not in a
                conditional execution block.  */
-            gen_exception(EXCP_KERNEL_TRAP);
+            gen_exception_internal(EXCP_KERNEL_TRAP);
             dc->is_jmp = DISAS_UPDATE;
             break;
         }
@@ -10769,7 +10796,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
         if (dc->pc >= 0xfffffff0 && IS_M(env)) {
             /* We always get here via a jump, so know we are not in a
                conditional execution block.  */
-            gen_exception(EXCP_EXCEPTION_EXIT);
+            gen_exception_internal(EXCP_EXCEPTION_EXIT);
             dc->is_jmp = DISAS_UPDATE;
             break;
         }
@@ -10778,7 +10805,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
         if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
             QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
                 if (bp->pc == dc->pc) {
-                    gen_exception_insn(dc, 0, EXCP_DEBUG);
+                    gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
                     /* Advance PC so that clearing the breakpoint will
                        invalidate this TB.  */
                     dc->pc += 2;
@@ -10858,9 +10885,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
         if (dc->condjmp) {
             gen_set_condexec(dc);
             if (dc->is_jmp == DISAS_SWI) {
-                gen_exception(EXCP_SWI);
+                gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
             } else {
-                gen_exception(EXCP_DEBUG);
+                gen_exception_internal(EXCP_DEBUG);
             }
             gen_set_label(dc->condlabel);
         }
@@ -10870,11 +10897,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
         }
         gen_set_condexec(dc);
         if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
-            gen_exception(EXCP_SWI);
+            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
         } else {
             /* FIXME: Single stepping a WFI insn will not halt
                the CPU.  */
-            gen_exception(EXCP_DEBUG);
+            gen_exception_internal(EXCP_DEBUG);
         }
     } else {
         /* While branches must always occur at the end of an IT block,
@@ -10903,7 +10930,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
             gen_helper_wfi(cpu_env);
             break;
         case DISAS_SWI:
-            gen_exception(EXCP_SWI);
+            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
             break;
         }
         if (dc->condjmp) {
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 889a031..4d3d363 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -23,6 +23,10 @@ typedef struct DisasContext {
     int vfp_enabled;
     int vec_len;
     int vec_stride;
+    /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
+     * so that top level loop can generate correct syndrome information.
+     */
+    uint32_t svc_imm;
     int aarch64;
     int current_pl;
     GHashTable *cp_regs;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (4 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  3:28   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 07/21] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set Peter Maydell
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Rob Herring <rob.herring@linaro.org>

Set up the required syndrome information when we detect an MMU fault.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
[PMM: split out from exception handling patch, tweaked to bring
 in line with how we create other kinds of syndrome information]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c    | 16 ++++++++++++++++
 target-arm/internals.h | 13 +++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2fa01ae..d547a9d 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3586,6 +3586,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
     target_ulong page_size;
     int prot;
     int ret, is_user;
+    uint32_t syn;
 
     is_user = mmu_idx == MMU_USER_IDX;
     ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,
@@ -3598,14 +3599,29 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
         return 0;
     }
 
+    /* AArch64 syndrome does not have an LPAE bit */
+    syn = ret & ~(1 << 9);
+
+    /* For insn and data aborts we assume there is no instruction syndrome
+     * information; this is always true for exceptions reported to EL1.
+     */
     if (access_type == 2) {
+        syn = syn_insn_abort(0, 0, syn);
         env->exception_index = EXCP_PREFETCH_ABORT;
     } else {
+        syn = syn_data_abort(0, 0, 0, access_type == 1, syn);
         if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) {
             ret |= (1 << 11);
         }
         env->exception_index = EXCP_DATA_ABORT;
     }
+
+    /* Set bit 26 for exceptions with no change in EL */
+    if (arm_current_pl(env)) {
+        syn |= 1 << ARM_EL_EC_SHIFT;
+    }
+
+    env->exception.syndrome = syn;
     env->exception.vaddress = address;
     env->exception.fsr = ret;
     return 1;
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 9bec4e1..93f56a5 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -188,4 +188,17 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
         | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
 }
 
+static inline uint32_t syn_insn_abort(int ea, int s1ptw, int fsc)
+{
+    return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (ea << 9)
+        | (s1ptw << 7) | fsc;
+}
+
+static inline uint32_t syn_data_abort(int ea, int cm, int s1ptw, int wnr,
+                                      int fsc)
+{
+    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (ea << 9)
+        | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
+}
+
 #endif
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 07/21] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (5 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 08/21] target-arm: A64: Add assertion that FP access was checked Peter Maydell
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

For the A64 instruction set, the only FP/Neon disable trap
is the CPACR FPEN bits, which may indicate "enabled", "disabled"
or "disabled for EL0". Add a bit to the AArch64 tb flags indicating
whether FP/Neon access is currently enabled and make the decoder
emit code to raise exceptions on use of FP/Neon insns if it is not.

We use a new flag in DisasContext rather than borrowing the
existing vfp_enabled flag because the A32/T32 decoder is going
to need both.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
I'm aware this is a rather hard to review patch; sorry.
I have done an exhaustive check that we have fp access checks
in all code paths with the aid of the assertions added in the
next patch plus the code-coverage hack patch I posted to the
list earlier.

For the record, this patch is correct for all commits up to:
    target-arm: A64: Implement PMULL instruction
If we add further SIMD instructions before this patch hits
master, it will need additional fp access check hunks...
---
 target-arm/cpu.c           |   7 ++
 target-arm/cpu.h           |   9 ++
 target-arm/internals.h     |   7 ++
 target-arm/translate-a64.c | 243 ++++++++++++++++++++++++++++++++++++++++++++-
 target-arm/translate.h     |   3 +-
 5 files changed, 263 insertions(+), 6 deletions(-)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index bc8eac9..871ed09 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -94,9 +94,16 @@ static void arm_cpu_reset(CPUState *s)
         env->pstate = PSTATE_MODE_EL0t;
         /* Userspace expects access to CTL_EL0 and the cache ops */
         env->cp15.c1_sys |= SCTLR_UCT | SCTLR_UCI;
+        /* and to the FP/Neon instructions */
+        env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 2, 3);
 #else
         env->pstate = PSTATE_MODE_EL1h;
 #endif
+    } else {
+#if defined(CONFIG_USER_ONLY)
+        /* Userspace expects access to cp10 and cp11 for FP/Neon */
+        env->cp15.c1_coproc = deposit64(env->cp15.c1_coproc, 20, 4, 0xf);
+#endif
     }
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 9982e47..a70392f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1105,6 +1105,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
 /* Bit usage when in AArch64 state */
 #define ARM_TBFLAG_AA64_EL_SHIFT    0
 #define ARM_TBFLAG_AA64_EL_MASK     (0x3 << ARM_TBFLAG_AA64_EL_SHIFT)
+#define ARM_TBFLAG_AA64_FPEN_SHIFT  2
+#define ARM_TBFLAG_AA64_FPEN_MASK   (1 << ARM_TBFLAG_AA64_FPEN_SHIFT)
 
 /* some convenience accessor macros */
 #define ARM_TBFLAG_AARCH64_STATE(F) \
@@ -1125,14 +1127,21 @@ static inline int cpu_mmu_index (CPUARMState *env)
     (((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
 #define ARM_TBFLAG_AA64_EL(F) \
     (((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT)
+#define ARM_TBFLAG_AA64_FPEN(F) \
+    (((F) & ARM_TBFLAG_AA64_FPEN_MASK) >> ARM_TBFLAG_AA64_FPEN_SHIFT)
 
 static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
                                         target_ulong *cs_base, int *flags)
 {
+    int fpen = extract32(env->cp15.c1_coproc, 20, 2);
+
     if (is_a64(env)) {
         *pc = env->pc;
         *flags = ARM_TBFLAG_AARCH64_STATE_MASK
             | (arm_current_pl(env) << ARM_TBFLAG_AA64_EL_SHIFT);
+        if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
+            *flags |= ARM_TBFLAG_AA64_FPEN_MASK;
+        }
     } else {
         int privmode;
         *pc = env->regs[15];
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 93f56a5..11a7040 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -188,6 +188,13 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
         | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
 }
 
+static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_thumb)
+{
+    return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT)
+        | (is_thumb ? 0 : ARM_EL_IL)
+        | (cv << 24) | (cond << 20);
+}
+
 static inline uint32_t syn_insn_abort(int ea, int s1ptw, int fsc)
 {
     return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (ea << 9)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index b32068e..527a9e6 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -887,6 +887,23 @@ static void do_vec_ld(DisasContext *s, int destidx, int element,
     tcg_temp_free_i64(tcg_tmp);
 }
 
+/* Check that FP/Neon access is enabled. If it is, return
+ * true. If not, emit code to generate an appropriate exception,
+ * and return false; the caller should not emit any code for
+ * the instruction. Note that this check must happen after all
+ * unallocated-encoding checks (otherwise the syndrome information
+ * for the resulting exception will be incorrect).
+ */
+static inline bool fp_access_check(DisasContext *s)
+{
+    if (s->cpacr_fpen) {
+        return true;
+    }
+
+    gen_exception_insn(s, 4, EXCP_UDEF, syn_fp_access_trap(1, 0xe, false));
+    return false;
+}
+
 /*
  * This utility function is for doing register extension with an
  * optional shift. You will likely want to pass a temporary for the
@@ -1725,6 +1742,9 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
             return;
         }
         size = 2 + opc;
+        if (!fp_access_check(s)) {
+            return;
+        }
     } else {
         if (opc == 3) {
             /* PRFM (literal) : prefetch */
@@ -1834,6 +1854,10 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
         break;
     }
 
+    if (is_vector && !fp_access_check(s)) {
+        return;
+    }
+
     offset <<= size;
 
     if (rn == 31) {
@@ -1927,6 +1951,9 @@ static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
             return;
         }
         is_store = ((opc & 1) == 0);
+        if (!fp_access_check(s)) {
+            return;
+        }
     } else {
         if (size == 3 && opc == 2) {
             /* PRFM - prefetch */
@@ -2047,6 +2074,9 @@ static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
             return;
         }
         is_store = !extract32(opc, 0, 1);
+        if (!fp_access_check(s)) {
+            return;
+        }
     } else {
         if (size == 3 && opc == 2) {
             /* PRFM - prefetch */
@@ -2127,6 +2157,9 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
             return;
         }
         is_store = !extract32(opc, 0, 1);
+        if (!fp_access_check(s)) {
+            return;
+        }
     } else {
         if (size == 3 && opc == 2) {
             /* PRFM - prefetch */
@@ -2269,6 +2302,10 @@ static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (rn == 31) {
         gen_check_sp_alignment(s);
     }
@@ -2395,6 +2432,10 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
         g_assert_not_reached();
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     ebytes = 1 << scale;
 
     if (rn == 31) {
@@ -3872,6 +3913,10 @@ static void disas_fp_compare(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     handle_fp_compare(s, type, rn, rm, opc & 1, opc & 2);
 }
 
@@ -3900,6 +3945,10 @@ static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (cond < 0x0e) { /* not always */
         int label_match = gen_new_label();
         label_continue = gen_new_label();
@@ -3956,6 +4005,10 @@ static void disas_fp_csel(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (cond < 0x0e) { /* not always */
         int label_match = gen_new_label();
         label_continue = gen_new_label();
@@ -4173,6 +4226,10 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         handle_fp_fcvt(s, opcode, rd, rn, dtype, type);
         break;
     }
@@ -4182,9 +4239,17 @@ static void disas_fp_1src(DisasContext *s, uint32_t insn)
         /* 32-to-32 and 64-to-64 ops */
         switch (type) {
         case 0:
+            if (!fp_access_check(s)) {
+                return;
+            }
+
             handle_fp_1src_single(s, opcode, rd, rn);
             break;
         case 1:
+            if (!fp_access_check(s)) {
+                return;
+            }
+
             handle_fp_1src_double(s, opcode, rd, rn);
             break;
         default:
@@ -4324,9 +4389,15 @@ static void disas_fp_2src(DisasContext *s, uint32_t insn)
 
     switch (type) {
     case 0:
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fp_2src_single(s, opcode, rd, rn, rm);
         break;
     case 1:
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fp_2src_double(s, opcode, rd, rn, rm);
         break;
     default:
@@ -4428,9 +4499,15 @@ static void disas_fp_3src(DisasContext *s, uint32_t insn)
 
     switch (type) {
     case 0:
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fp_3src_single(s, o0, o1, rd, rn, rm, ra);
         break;
     case 1:
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fp_3src_double(s, o0, o1, rd, rn, rm, ra);
         break;
     default:
@@ -4457,6 +4534,10 @@ static void disas_fp_imm(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     /* The imm8 encodes the sign bit, enough bits to represent
      * an exponent in the range 01....1xx to 10....0xx,
      * and the most significant 4 bits of the mantissa; see
@@ -4643,6 +4724,10 @@ static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     handle_fpfpcvt(s, rd, rn, opcode, itof, FPROUNDING_ZERO, scale, sf, type);
 }
 
@@ -4742,6 +4827,9 @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
             break;
         }
 
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fmov(s, rd, rn, type, itof);
     } else {
         /* actual FP conversions */
@@ -4752,6 +4840,9 @@ static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
             return;
         }
 
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_fpfpcvt(s, rd, rn, opcode, itof, rmode, 64, sf, type);
     }
 }
@@ -4852,6 +4943,10 @@ static void disas_simd_ext(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     tcg_resh = tcg_temp_new_i64();
     tcg_resl = tcg_temp_new_i64();
 
@@ -4922,6 +5017,10 @@ static void disas_simd_tb(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     /* This does a table lookup: for every byte element in the input
      * we index into a table formed from up to four vector registers,
      * and then the output is the result of the lookups. Our helper
@@ -4992,6 +5091,10 @@ static void disas_simd_zip_trn(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     tcg_resl = tcg_const_i64(0);
     tcg_resh = tcg_const_i64(0);
     tcg_res = tcg_temp_new_i64();
@@ -5125,6 +5228,10 @@ static void disas_simd_across_lanes(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     esize = 8 << size;
     elements = (is_q ? 128 : 64) / esize;
 
@@ -5257,6 +5364,10 @@ static void handle_simd_dupe(DisasContext *s, int is_q, int rd, int rn,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     index = imm5 >> (size + 1);
 
     tmp = tcg_temp_new_i64();
@@ -5291,6 +5402,10 @@ static void handle_simd_dupes(DisasContext *s, int rd, int rn,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     index = imm5 >> (size + 1);
 
     /* This instruction just extracts the specified element and
@@ -5323,6 +5438,11 @@ static void handle_simd_dupg(DisasContext *s, int is_q, int rd, int rn,
         unallocated_encoding(s);
         return;
     }
+
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     for (i = 0; i < elements; i++) {
         write_vec_element(s, cpu_reg(s, rn), rd, i, size);
     }
@@ -5352,6 +5472,11 @@ static void handle_simd_inse(DisasContext *s, int rd, int rn,
         unallocated_encoding(s);
         return;
     }
+
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     dst_index = extract32(imm5, 1+size, 5);
     src_index = extract32(imm4, size, 4);
 
@@ -5384,6 +5509,10 @@ static void handle_simd_insg(DisasContext *s, int rd, int rn, int imm5)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     idx = extract32(imm5, 1 + size, 4 - size);
     write_vec_element(s, cpu_reg(s, rn), rd, idx, size);
 }
@@ -5421,6 +5550,11 @@ static void handle_simd_umov_smov(DisasContext *s, int is_q, int is_signed,
             return;
         }
     }
+
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     element = extract32(imm5, 1+size, 4);
 
     tcg_rd = cpu_reg(s, rd);
@@ -5513,6 +5647,10 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     /* See AdvSIMDExpandImm() in ARM ARM */
     switch (cmode_3_1) {
     case 0: /* Replicate(Zeros(24):imm8, 2) */
@@ -5661,6 +5799,10 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         TCGV_UNUSED_PTR(fpst);
         break;
     case 0xc: /* FMAXNMP */
@@ -5673,6 +5815,10 @@ static void disas_simd_scalar_pairwise(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         size = extract32(size, 0, 1) ? 3 : 2;
         fpst = get_fpstatus_ptr();
         break;
@@ -5875,6 +6021,10 @@ static void handle_scalar_simd_shri(DisasContext *s,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     switch (opcode) {
     case 0x02: /* SSRA / USRA (accumulate) */
         accumulate = true;
@@ -5925,6 +6075,10 @@ static void handle_scalar_simd_shli(DisasContext *s, bool insert,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     tcg_rn = read_fp_dreg(s, rn);
     tcg_rd = insert ? read_fp_dreg(s, rd) : tcg_temp_new_i64();
 
@@ -6003,6 +6157,10 @@ static void disas_simd_scalar_three_reg_diff(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (size == 2) {
         TCGv_i64 tcg_op1 = tcg_temp_new_i64();
         TCGv_i64 tcg_op2 = tcg_temp_new_i64();
@@ -6387,6 +6545,10 @@ static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
             return;
         }
 
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         handle_3same_float(s, extract32(size, 0, 1), 1, fpopcode, rd, rn, rm);
         return;
     }
@@ -6419,6 +6581,10 @@ static void disas_simd_scalar_three_reg_same(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     tcg_rd = tcg_temp_new_i64();
 
     if (size == 3) {
@@ -6569,7 +6735,13 @@ static void handle_2misc_fcmp_zero(DisasContext *s, int opcode,
                                    int size, int rn, int rd)
 {
     bool is_double = (size == 3);
-    TCGv_ptr fpst = get_fpstatus_ptr();
+    TCGv_ptr fpst;
+
+    if (!fp_access_check(s)) {
+        return;
+    }
+
+    fpst = get_fpstatus_ptr();
 
     if (is_double) {
         TCGv_i64 tcg_op = tcg_temp_new_i64();
@@ -6751,6 +6923,10 @@ static void disas_simd_scalar_two_reg_misc(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (size == 3) {
         TCGv_i64 tcg_rn = read_fp_dreg(s, rn);
         TCGv_i64 tcg_rd = tcg_temp_new_i64();
@@ -6793,6 +6969,10 @@ static void handle_vec_simd_shri(DisasContext *s, bool is_q, bool is_u,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     switch (opcode) {
     case 0x02: /* SSRA / USRA (accumulate) */
         accumulate = true;
@@ -6857,6 +7037,10 @@ static void handle_vec_simd_shli(DisasContext *s, bool is_q, bool insert,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     for (i = 0; i < elements; i++) {
         read_vec_element(s, tcg_rn, rn, i, size);
         if (insert) {
@@ -6892,6 +7076,10 @@ static void handle_vec_simd_wshli(DisasContext *s, bool is_q, bool is_u,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     /* For the LL variants the store is larger than the load,
      * so if rd == rn we would overwrite parts of our input.
      * So load everything right now and use shifts in the main loop.
@@ -7333,6 +7521,9 @@ static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_3rd_wide(s, is_q, is_u, size, opcode, rd, rn, rm);
         break;
     case 4: /* ADDHN, ADDHN2, RADDHN, RADDHN2 */
@@ -7342,6 +7533,9 @@ static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
         handle_3rd_narrowing(s, is_q, is_u, size, opcode, rd, rn, rm);
         break;
     case 14: /* PMULL, PMULL2 */
@@ -7354,6 +7548,9 @@ static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
                 unallocated_encoding(s);
                 return;
             }
+            if (!fp_access_check(s)) {
+                return;
+            }
             handle_pmull_64(s, is_q, rd, rn, rm);
             return;
         }
@@ -7379,6 +7576,10 @@ static void disas_simd_three_reg_diff(DisasContext *s, uint32_t insn)
             return;
         }
     is_widening:
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         handle_3rd_widening(s, is_q, is_u, size, opcode, rd, rn, rm);
         break;
     default:
@@ -7397,11 +7598,15 @@ static void disas_simd_3same_logic(DisasContext *s, uint32_t insn)
     int size = extract32(insn, 22, 2);
     bool is_u = extract32(insn, 29, 1);
     bool is_q = extract32(insn, 30, 1);
-    TCGv_i64 tcg_op1 = tcg_temp_new_i64();
-    TCGv_i64 tcg_op2 = tcg_temp_new_i64();
-    TCGv_i64 tcg_res[2];
+    TCGv_i64 tcg_op1, tcg_op2, tcg_res[2];
     int pass;
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
+    tcg_op1 = tcg_temp_new_i64();
+    tcg_op2 = tcg_temp_new_i64();
     tcg_res[0] = tcg_temp_new_i64();
     tcg_res[1] = tcg_temp_new_i64();
 
@@ -7504,6 +7709,10 @@ static void handle_simd_3same_pair(DisasContext *s, int is_q, int u, int opcode,
         TCGV_UNUSED_PTR(fpst);
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     /* These operations work on the concatenated rm:rn, with each pair of
      * adjacent elements being operated on to produce an element in the result.
      */
@@ -7696,6 +7905,10 @@ static void disas_simd_3same_float(DisasContext *s, uint32_t insn)
     case 0x5f: /* FDIV */
     case 0x7a: /* FABD */
     case 0x7c: /* FCMGT */
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         handle_3same_float(s, size, elements, fpopcode, rd, rn, rm);
         return;
     default:
@@ -7750,6 +7963,10 @@ static void disas_simd_3same_int(DisasContext *s, uint32_t insn)
         break;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (size == 3) {
         for (pass = 0; pass < (is_q ? 2 : 1); pass++) {
             TCGv_i64 tcg_op1 = tcg_temp_new_i64();
@@ -8142,6 +8359,10 @@ static void handle_rev(DisasContext *s, int opcode, bool u,
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (size == 0) {
         /* Special case bytes, use bswap op on each group of elements */
         int groups = dsize / (8 << grp_size);
@@ -8237,6 +8458,10 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
             unallocated_encoding(s);
             return;
         }
+        if (!fp_access_check(s)) {
+            return;
+        }
+
         handle_2misc_narrow(s, opcode, u, is_q, size, rn, rd);
         return;
     case 0x2: /* SADDLP, UADDLP */
@@ -8345,6 +8570,10 @@ static void disas_simd_two_reg_misc(DisasContext *s, uint32_t insn)
         return;
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (size == 3) {
         /* All 64-bit element operations can be shared with scalar 2misc */
         int pass;
@@ -8606,6 +8835,10 @@ static void disas_simd_indexed(DisasContext *s, uint32_t insn)
         }
     }
 
+    if (!fp_access_check(s)) {
+        return;
+    }
+
     if (is_fp) {
         fpst = get_fpstatus_ptr();
     } else {
@@ -9104,7 +9337,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (ARM_TBFLAG_AA64_EL(tb->flags) == 0);
 #endif
-    dc->vfp_enabled = 0;
+    dc->cpacr_fpen = ARM_TBFLAG_AA64_FPEN(tb->flags);
     dc->vec_len = 0;
     dc->vec_stride = 0;
     dc->cp_regs = cpu->cp_regs;
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 4d3d363..3e41342 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -20,7 +20,8 @@ typedef struct DisasContext {
 #if !defined(CONFIG_USER_ONLY)
     int user;
 #endif
-    int vfp_enabled;
+    bool cpacr_fpen; /* FP enabled via CPACR.FPEN */
+    bool vfp_enabled; /* FP enabled via FPSCR.EN */
     int vec_len;
     int vec_stride;
     /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 08/21] target-arm: A64: Add assertion that FP access was checked
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (6 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 07/21] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 09/21] target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1 Peter Maydell
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Because unallocated encodings generate different exception syndrome
information from traps due to FP being disabled, we can't do a single
"is fp access disabled" check at a high level in the decode tree.
To help in catching bugs where the access check was forgotten in some
code path, we set this flag when the access check is done, and assert
that it is set at the point where we actually touch the FP regs.

This requires us to pass the DisasContext to the vec_reg_offset
and fp_reg_offset functions.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 74 +++++++++++++++++++++++++++++++---------------
 target-arm/translate.h     |  8 +++++
 2 files changed, 58 insertions(+), 24 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 527a9e6..7054fa1 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -350,11 +350,29 @@ static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
     return v;
 }
 
+/* We should have at some point before trying to access an FP register
+ * done the necessary access check, so assert that (a) we did the check
+ * and (b) we didn't then just plough ahead anyway if it failed.
+ *.Print the instruction pattern in the abort message so we can figure
+ * out what we need to fix if a user encounters this problem in the wild.
+ */
+static inline void assert_fp_access_checked(DisasContext *s)
+{
+#ifdef CONFIG_DEBUG_TCG
+    if (unlikely(!s->fp_access_checked || !s->cpacr_fpen)) {
+        fprintf(stderr, "target-arm: FP access check missing for "
+                "instruction 0x%08x\n", s->insn);
+        abort();
+    }
+#endif
+}
+
 /* Return the offset into CPUARMState of an element of specified
  * size, 'element' places in from the least significant end of
  * the FP/vector register Qn.
  */
-static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
+static inline int vec_reg_offset(DisasContext *s, int regno,
+                                 int element, TCGMemOp size)
 {
     int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
 #ifdef HOST_WORDS_BIGENDIAN
@@ -369,6 +387,7 @@ static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
 #else
     offs += element * (1 << size);
 #endif
+    assert_fp_access_checked(s);
     return offs;
 }
 
@@ -377,18 +396,20 @@ static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
  * Dn, Sn, Hn or Bn).
  * (Note that this is not the same mapping as for A32; see cpu.h)
  */
-static inline int fp_reg_offset(int regno, TCGMemOp size)
+static inline int fp_reg_offset(DisasContext *s, int regno, TCGMemOp size)
 {
     int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
 #ifdef HOST_WORDS_BIGENDIAN
     offs += (8 - (1 << size));
 #endif
+    assert_fp_access_checked(s);
     return offs;
 }
 
 /* Offset of the high half of the 128 bit vector Qn */
-static inline int fp_reg_hi_offset(int regno)
+static inline int fp_reg_hi_offset(DisasContext *s, int regno)
 {
+    assert_fp_access_checked(s);
     return offsetof(CPUARMState, vfp.regs[regno * 2 + 1]);
 }
 
@@ -402,7 +423,7 @@ static TCGv_i64 read_fp_dreg(DisasContext *s, int reg)
 {
     TCGv_i64 v = tcg_temp_new_i64();
 
-    tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
+    tcg_gen_ld_i64(v, cpu_env, fp_reg_offset(s, reg, MO_64));
     return v;
 }
 
@@ -410,7 +431,7 @@ static TCGv_i32 read_fp_sreg(DisasContext *s, int reg)
 {
     TCGv_i32 v = tcg_temp_new_i32();
 
-    tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(reg, MO_32));
+    tcg_gen_ld_i32(v, cpu_env, fp_reg_offset(s, reg, MO_32));
     return v;
 }
 
@@ -418,8 +439,8 @@ static void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v)
 {
     TCGv_i64 tcg_zero = tcg_const_i64(0);
 
-    tcg_gen_st_i64(v, cpu_env, fp_reg_offset(reg, MO_64));
-    tcg_gen_st_i64(tcg_zero, cpu_env, fp_reg_hi_offset(reg));
+    tcg_gen_st_i64(v, cpu_env, fp_reg_offset(s, reg, MO_64));
+    tcg_gen_st_i64(tcg_zero, cpu_env, fp_reg_hi_offset(s, reg));
     tcg_temp_free_i64(tcg_zero);
 }
 
@@ -690,14 +711,14 @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
 {
     /* This writes the bottom N bits of a 128 bit wide vector to memory */
     TCGv_i64 tmp = tcg_temp_new_i64();
-    tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(srcidx, MO_64));
+    tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(s, srcidx, MO_64));
     if (size < 4) {
         tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
     } else {
         TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
         tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
         tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
-        tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(srcidx));
+        tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx));
         tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
         tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
         tcg_temp_free_i64(tcg_hiaddr);
@@ -730,8 +751,8 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
         tcg_temp_free_i64(tcg_hiaddr);
     }
 
-    tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(destidx, MO_64));
-    tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(destidx));
+    tcg_gen_st_i64(tmplo, cpu_env, fp_reg_offset(s, destidx, MO_64));
+    tcg_gen_st_i64(tmphi, cpu_env, fp_reg_hi_offset(s, destidx));
 
     tcg_temp_free_i64(tmplo);
     tcg_temp_free_i64(tmphi);
@@ -753,7 +774,7 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
 static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
                              int element, TCGMemOp memop)
 {
-    int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
+    int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
     switch (memop) {
     case MO_8:
         tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
@@ -785,7 +806,7 @@ static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
 static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
                                  int element, TCGMemOp memop)
 {
-    int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
+    int vect_off = vec_reg_offset(s, srcidx, element, memop & MO_SIZE);
     switch (memop) {
     case MO_8:
         tcg_gen_ld8u_i32(tcg_dest, cpu_env, vect_off);
@@ -812,7 +833,7 @@ static void read_vec_element_i32(DisasContext *s, TCGv_i32 tcg_dest, int srcidx,
 static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
                               int element, TCGMemOp memop)
 {
-    int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
+    int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
     switch (memop) {
     case MO_8:
         tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
@@ -834,7 +855,7 @@ static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
 static void write_vec_element_i32(DisasContext *s, TCGv_i32 tcg_src,
                                   int destidx, int element, TCGMemOp memop)
 {
-    int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
+    int vect_off = vec_reg_offset(s, destidx, element, memop & MO_SIZE);
     switch (memop) {
     case MO_8:
         tcg_gen_st8_i32(tcg_src, cpu_env, vect_off);
@@ -896,6 +917,9 @@ static void do_vec_ld(DisasContext *s, int destidx, int element,
  */
 static inline bool fp_access_check(DisasContext *s)
 {
+    assert(!s->fp_access_checked);
+    s->fp_access_checked = true;
+
     if (s->cpacr_fpen) {
         return true;
     }
@@ -4746,9 +4770,9 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
             /* 32 bit */
             TCGv_i64 tmp = tcg_temp_new_i64();
             tcg_gen_ext32u_i64(tmp, tcg_rn);
-            tcg_gen_st_i64(tmp, cpu_env, fp_reg_offset(rd, MO_64));
+            tcg_gen_st_i64(tmp, cpu_env, fp_reg_offset(s, rd, MO_64));
             tcg_gen_movi_i64(tmp, 0);
-            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
+            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(s, rd));
             tcg_temp_free_i64(tmp);
             break;
         }
@@ -4756,14 +4780,14 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
         {
             /* 64 bit */
             TCGv_i64 tmp = tcg_const_i64(0);
-            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_offset(rd, MO_64));
-            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(rd));
+            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_offset(s, rd, MO_64));
+            tcg_gen_st_i64(tmp, cpu_env, fp_reg_hi_offset(s, rd));
             tcg_temp_free_i64(tmp);
             break;
         }
         case 2:
             /* 64 bit to top half. */
-            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(rd));
+            tcg_gen_st_i64(tcg_rn, cpu_env, fp_reg_hi_offset(s, rd));
             break;
         }
     } else {
@@ -4772,15 +4796,15 @@ static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
         switch (type) {
         case 0:
             /* 32 bit */
-            tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_32));
+            tcg_gen_ld32u_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_32));
             break;
         case 1:
             /* 64 bit */
-            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(rn, MO_64));
+            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_offset(s, rn, MO_64));
             break;
         case 2:
             /* 64 bits from top half */
-            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(rn));
+            tcg_gen_ld_i64(tcg_rd, cpu_env, fp_reg_hi_offset(s, rn));
             break;
         }
     }
@@ -5725,7 +5749,7 @@ static void disas_simd_mod_imm(DisasContext *s, uint32_t insn)
     tcg_rd = new_tmp_a64(s);
 
     for (i = 0; i < 2; i++) {
-        int foffs = i ? fp_reg_hi_offset(rd) : fp_reg_offset(rd, MO_64);
+        int foffs = i ? fp_reg_hi_offset(s, rd) : fp_reg_offset(s, rd, MO_64);
 
         if (i == 1 && !is_q) {
             /* non-quad ops clear high half of vector */
@@ -9270,6 +9294,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
     s->insn = insn;
     s->pc += 4;
 
+    s->fp_access_checked = false;
+
     switch (extract32(insn, 25, 4)) {
     case 0x0: case 0x1: case 0x2: case 0x3: /* UNALLOCATED */
         unallocated_encoding(s);
diff --git a/target-arm/translate.h b/target-arm/translate.h
index 3e41342..a221889 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -32,6 +32,14 @@ typedef struct DisasContext {
     int current_pl;
     GHashTable *cp_regs;
     uint64_t features; /* CPU features bits */
+    /* Because unallocated encodings generate different exception syndrome
+     * information from traps due to FP being disabled, we can't do a single
+     * "is fp access disabled" check at a high level in the decode tree.
+     * To help in catching bugs where the access check was forgotten in some
+     * code path, we set this flag when the access check is done, and assert
+     * that it is set at the point where we actually touch the FP regs.
+     */
+    bool fp_access_checked;
 #define TMP_A64_MAX 16
     int tmp_a64_count;
     TCGv_i64 tmp_a64[TMP_A64_MAX];
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 09/21] target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (7 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 08/21] target-arm: A64: Add assertion that FP access was checked Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support Peter Maydell
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

The current A32/T32 decoder bases its "is VFP/Neon enabled?" check
on the FPSCR.EN bit. This is correct if EL1 is AArch32, but for
an AArch64 EL1 the logic is different: it must act as if FPSCR.EN
is always set. Instead, trapping must happen according to CPACR
bits for cp10/cp11; these cover all of FP/Neon, including the
FPSCR/FPSID/MVFR register accesses which FPSCR.EN does not affect.
Add support for CPACR checks (which are also required for ARMv7,
but were unimplemented because Linux happens not to use them)
and make sure they generate exceptions with the correct syndrome.

We actually return incorrect syndrome information for cases
where FP is disabled but the specific instruction bit pattern
is unallocated: strictly these should be the Uncategorized
exception, not a "SIMD disabled" exception. This should be
mostly harmless, and the structure of the A32/T32 VFP/Neon
decoder makes it painful to put the 'FP disabled?' checks in
the right places.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h       | 10 +++++++++-
 target-arm/translate.c | 19 +++++++++++++++++++
 2 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index a70392f..3a0c38d 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1101,6 +1101,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
 #define ARM_TBFLAG_CONDEXEC_MASK    (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
 #define ARM_TBFLAG_BSWAP_CODE_SHIFT 16
 #define ARM_TBFLAG_BSWAP_CODE_MASK  (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
+#define ARM_TBFLAG_CPACR_FPEN_SHIFT 17
+#define ARM_TBFLAG_CPACR_FPEN_MASK  (1 << ARM_TBFLAG_CPACR_FPEN_SHIFT)
 
 /* Bit usage when in AArch64 state */
 #define ARM_TBFLAG_AA64_EL_SHIFT    0
@@ -1125,6 +1127,8 @@ static inline int cpu_mmu_index (CPUARMState *env)
     (((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
 #define ARM_TBFLAG_BSWAP_CODE(F) \
     (((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
+#define ARM_TBFLAG_CPACR_FPEN(F) \
+    (((F) & ARM_TBFLAG_CPACR_FPEN_MASK) >> ARM_TBFLAG_CPACR_FPEN_SHIFT)
 #define ARM_TBFLAG_AA64_EL(F) \
     (((F) & ARM_TBFLAG_AA64_EL_MASK) >> ARM_TBFLAG_AA64_EL_SHIFT)
 #define ARM_TBFLAG_AA64_FPEN(F) \
@@ -1158,9 +1162,13 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
         if (privmode) {
             *flags |= ARM_TBFLAG_PRIV_MASK;
         }
-        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)) {
+        if (env->vfp.xregs[ARM_VFP_FPEXC] & (1 << 30)
+            || arm_el_is_aa64(env, 1)) {
             *flags |= ARM_TBFLAG_VFPEN_MASK;
         }
+        if (fpen == 3 || (fpen == 1 && arm_current_pl(env) != 0)) {
+            *flags |= ARM_TBFLAG_CPACR_FPEN_MASK;
+        }
     }
 
     *cs_base = 0;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 094be07..d8dc88f 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -2952,6 +2952,12 @@ static int disas_vfp_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
     if (!arm_feature(env, ARM_FEATURE_VFP))
         return 1;
 
+    if (!s->cpacr_fpen) {
+        gen_exception_insn(s, 4, EXCP_UDEF,
+                           syn_fp_access_trap(1, 0xe, s->thumb));
+        return 0;
+    }
+
     if (!s->vfp_enabled) {
         /* VFP disabled.  Only allow fmxr/fmrx to/from some control regs.  */
         if ((insn & 0x0fe00fff) != 0x0ee00a10)
@@ -4229,6 +4235,12 @@ static int disas_neon_ls_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
     TCGv_i32 tmp2;
     TCGv_i64 tmp64;
 
+    if (!s->cpacr_fpen) {
+        gen_exception_insn(s, 4, EXCP_UDEF,
+                           syn_fp_access_trap(1, 0xe, s->thumb));
+        return 0;
+    }
+
     if (!s->vfp_enabled)
       return 1;
     VFP_DREG_D(rd, insn);
@@ -4951,6 +4963,12 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins
     TCGv_i32 tmp, tmp2, tmp3, tmp4, tmp5;
     TCGv_i64 tmp64;
 
+    if (!s->cpacr_fpen) {
+        gen_exception_insn(s, 4, EXCP_UDEF,
+                           syn_fp_access_trap(1, 0xe, s->thumb));
+        return 0;
+    }
+
     if (!s->vfp_enabled)
       return 1;
     q = (insn & (1 << 6)) != 0;
@@ -10717,6 +10735,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (ARM_TBFLAG_PRIV(tb->flags) == 0);
 #endif
+    dc->cpacr_fpen = ARM_TBFLAG_CPACR_FPEN(tb->flags);
     dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
     dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
     dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (8 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 09/21] target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1 Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-20 18:20   ` Peter Maydell
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register Peter Maydell
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Rob Herring <rob.herring@linaro.org>

Add support for v8 page table walks. This supports stage 1 translations
for 4KB, 16KB and 64KB page sizes starting with 0 or 1 level.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
[PMM: fix style nits, fold in 16/64K page support patch, use
 arm_el_is_aa64() to decide whether to do 64 bit page table walk]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c | 103 +++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 74 insertions(+), 29 deletions(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index d547a9d..c18f1a6 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,7 +10,7 @@
 #include <zlib.h> /* For crc32 */
 
 #ifndef CONFIG_USER_ONLY
-static inline int get_phys_addr(CPUARMState *env, uint32_t address,
+static inline int get_phys_addr(CPUARMState *env, target_ulong address,
                                 int access_type, int is_user,
                                 hwaddr *phys_ptr, int *prot,
                                 target_ulong *page_size);
@@ -1065,8 +1065,9 @@ static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
  */
 static inline bool extended_addresses_enabled(CPUARMState *env)
 {
-    return arm_feature(env, ARM_FEATURE_LPAE)
-        && (env->cp15.c2_control & (1U << 31));
+    return arm_feature(env, ARM_FEATURE_V8)
+        || (arm_feature(env, ARM_FEATURE_LPAE)
+        && (env->cp15.c2_control & (1U << 31)));
 }
 
 static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri)
@@ -3294,7 +3295,7 @@ typedef enum {
     permission_fault = 3,
 } MMUFaultType;
 
-static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
+static int get_phys_addr_lpae(CPUARMState *env, target_ulong address,
                               int access_type, int is_user,
                               hwaddr *phys_ptr, int *prot,
                               target_ulong *page_size_ptr)
@@ -3304,26 +3305,46 @@ static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
     MMUFaultType fault_type = translation_fault;
     uint32_t level = 1;
     uint32_t epd;
-    uint32_t tsz;
+    int32_t tsz;
+    uint32_t tg;
     uint64_t ttbr;
     int ttbr_select;
-    int n;
-    hwaddr descaddr;
+    hwaddr descaddr, descmask;
     uint32_t tableattrs;
     target_ulong page_size;
     uint32_t attrs;
+    int32_t granule_sz = 9;
+    int32_t va_size = 32;
+    int32_t tbi = 0;
+
+    if (arm_el_is_aa64(env, 1)) {
+        va_size = 64;
+        if (extract64(address, 55, 1))
+            tbi = extract64(env->cp15.c2_control, 38, 1);
+        else
+            tbi = extract64(env->cp15.c2_control, 37, 1);
+        tbi *= 8;
+    }
 
     /* Determine whether this address is in the region controlled by
      * TTBR0 or TTBR1 (or if it is in neither region and should fault).
      * This is a Non-secure PL0/1 stage 1 translation, so controlled by
      * TTBCR/TTBR0/TTBR1 in accordance with ARM ARM DDI0406C table B-32:
      */
-    uint32_t t0sz = extract32(env->cp15.c2_control, 0, 3);
-    uint32_t t1sz = extract32(env->cp15.c2_control, 16, 3);
-    if (t0sz && !extract32(address, 32 - t0sz, t0sz)) {
+    uint32_t t0sz = extract32(env->cp15.c2_control, 0, 6);
+    if (arm_el_is_aa64(env, 1)) {
+        t0sz = MIN(t0sz, 39);
+        t0sz = MAX(t0sz, 16);
+    }
+    uint32_t t1sz = extract32(env->cp15.c2_control, 16, 6);
+    if (arm_el_is_aa64(env, 1)) {
+        t1sz = MIN(t1sz, 39);
+        t1sz = MAX(t1sz, 16);
+    }
+    if (t0sz && !extract64(address, va_size - t0sz, t0sz - tbi)) {
         /* there is a ttbr0 region and we are in it (high bits all zero) */
         ttbr_select = 0;
-    } else if (t1sz && !extract32(~address, 32 - t1sz, t1sz)) {
+    } else if (t1sz && !extract64(~address, va_size - t1sz, t1sz - tbi)) {
         /* there is a ttbr1 region and we are in it (high bits all one) */
         ttbr_select = 1;
     } else if (!t0sz) {
@@ -3349,10 +3370,26 @@ static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
         ttbr = env->cp15.ttbr0_el1;
         epd = extract32(env->cp15.c2_control, 7, 1);
         tsz = t0sz;
+
+        tg = extract32(env->cp15.c2_control, 14, 2);
+        if (tg == 1) { /* 64KB pages */
+            granule_sz = 13;
+        }
+        if (tg == 2) { /* 16KB pages */
+            granule_sz = 11;
+        }
     } else {
         ttbr = env->cp15.ttbr1_el1;
         epd = extract32(env->cp15.c2_control, 23, 1);
         tsz = t1sz;
+
+        tg = extract32(env->cp15.c2_control, 30, 2);
+        if (tg == 3)  { /* 64KB pages */
+            granule_sz = 13;
+        }
+        if (tg == 1) { /* 16KB pages */
+            granule_sz = 11;
+        }
     }
 
     if (epd) {
@@ -3360,34 +3397,37 @@ static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
         goto do_fault;
     }
 
-    /* If the region is small enough we will skip straight to a 2nd level
-     * lookup. This affects the number of bits of the address used in
-     * combination with the TTBR to find the first descriptor. ('n' here
-     * matches the usage in the ARM ARM sB3.6.6, where bits [39..n] are
-     * from the TTBR, [n-1..3] from the vaddr, and [2..0] always zero).
+    /* The starting level depends on the virtual address size which can be
+     * up to 48-bits and the translation granule size.
      */
-    if (tsz > 1) {
-        level = 2;
-        n = 14 - tsz;
+    if ((va_size - tsz) > (granule_sz * 4 + 3)) {
+        level = 0;
+    } else if ((va_size - tsz) > (granule_sz * 3 + 3)) {
+        level = 1;
     } else {
-        n = 5 - tsz;
+        level = 2;
     }
 
     /* Clear the vaddr bits which aren't part of the within-region address,
      * so that we don't have to special case things when calculating the
      * first descriptor address.
      */
-    address &= (0xffffffffU >> tsz);
+    if (tsz) {
+        address &= (1ULL << (va_size - tsz)) - 1;
+    }
+
+    descmask = (1ULL << (granule_sz + 3)) - 1;
 
     /* Now we can extract the actual base address from the TTBR */
-    descaddr = extract64(ttbr, 0, 40);
-    descaddr &= ~((1ULL << n) - 1);
+    descaddr = extract64(ttbr, 0, 48);
+    descaddr &= ~((1ULL << (va_size - tsz - (granule_sz * (4 - level)))) - 1);
 
     tableattrs = 0;
     for (;;) {
         uint64_t descriptor;
 
-        descaddr |= ((address >> (9 * (4 - level))) & 0xff8);
+        descaddr |= (address >> (granule_sz * (4 - level))) & descmask;
+        descaddr &= ~7ULL;
         descriptor = ldq_phys(cs->as, descaddr);
         if (!(descriptor & 1) ||
             (!(descriptor & 2) && (level == 3))) {
@@ -3410,11 +3450,16 @@ static int get_phys_addr_lpae(CPUARMState *env, uint32_t address,
          * These are basically the same thing, although the number
          * of bits we pull in from the vaddr varies.
          */
-        page_size = (1 << (39 - (9 * level)));
+        page_size = (1 << ((granule_sz * (4 - level)) + 3));
         descaddr |= (address & (page_size - 1));
         /* Extract attributes from the descriptor and merge with table attrs */
-        attrs = extract64(descriptor, 2, 10)
-            | (extract64(descriptor, 52, 12) << 10);
+        if (arm_feature(env, ARM_FEATURE_V8)) {
+            attrs = extract64(descriptor, 2, 10)
+                | (extract64(descriptor, 53, 11) << 10);
+        } else {
+            attrs = extract64(descriptor, 2, 10)
+                | (extract64(descriptor, 52, 12) << 10);
+        }
         attrs |= extract32(tableattrs, 0, 2) << 11; /* XN, PXN */
         attrs |= extract32(tableattrs, 3, 1) << 5; /* APTable[1] => AP[2] */
         /* The sense of AP[1] vs APTable[0] is reversed, as APTable[0] == 1
@@ -3548,7 +3593,7 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
  * @prot: set to the permissions for the page containing phys_ptr
  * @page_size: set to the size of the page containing phys_ptr
  */
-static inline int get_phys_addr(CPUARMState *env, uint32_t address,
+static inline int get_phys_addr(CPUARMState *env, target_ulong address,
                                 int access_type, int is_user,
                                 hwaddr *phys_ptr, int *prot,
                                 target_ulong *page_size)
@@ -3594,7 +3639,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
     if (ret == 0) {
         /* Map a single [sub]page.  */
         phys_addr &= ~(hwaddr)0x3ff;
-        address &= ~(uint32_t)0x3ff;
+        address &= ~(target_ulong)0x3ff;
         tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);
         return 0;
     }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (9 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  5:13   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA Peter Maydell
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Suppress the ID_AA64DFR0_EL1 PMUVer field, even if the CPU specific
value claims that it exists. QEMU doesn't currently implement it,
and not advertising it prevents the guest from trying to use it
and getting UNDEFs on unimplemented registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
This is arguably a hack, but otherwise Linux tries to prod
half a dozen PMU sysregs.
---
 target-arm/helper.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index c18f1a6..e1672aa 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1929,7 +1929,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
             { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
               .access = PL1_R, .type = ARM_CP_CONST,
-              .resetvalue = cpu->id_aa64dfr0 },
+              /* We mask out the PMUVer field, beacuse we don't currently
+               * implement the PMU. Not advertising it prevents the guest
+               * from trying to use it and getting UNDEFs on registers we
+               * don't implement.
+               */
+              .resetvalue = cpu->id_aa64dfr0 & ~0xf00 },
             { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64,
               .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1,
               .access = PL1_R, .type = ARM_CP_CONST,
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (10 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-07 14:51   ` Richard Henderson
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers Peter Maydell
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Implement the DC ZVA instruction, which clears a block of memory.
The fast path obtains a pointer to the underlying RAM via the TCG TLB
data structure so we can do a direct memset(), with fallback to a
simple byte-store loop in the slow path.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 include/exec/softmmu_exec.h |  36 +++++++++++++
 target-arm/cpu-qom.h        |   2 +
 target-arm/cpu.h            |   3 +-
 target-arm/cpu64.c          |   1 +
 target-arm/helper.c         | 122 ++++++++++++++++++++++++++++++++++++++++++--
 target-arm/helper.h         |   1 +
 target-arm/translate-a64.c  |   5 ++
 7 files changed, 164 insertions(+), 6 deletions(-)

diff --git a/include/exec/softmmu_exec.h b/include/exec/softmmu_exec.h
index 6fde154..66a1ba8 100644
--- a/include/exec/softmmu_exec.h
+++ b/include/exec/softmmu_exec.h
@@ -162,3 +162,39 @@
 #define stw(p, v) stw_data(p, v)
 #define stl(p, v) stl_data(p, v)
 #define stq(p, v) stq_data(p, v)
+
+/**
+ * tlb_vaddr_to_host:
+ * @env: CPUArchState
+ * @addr: guest virtual address to look up
+ * @mmu_idx: MMU index to use for lookup
+ *
+ * Look up the specified guest virtual index in the TCG softmmu TLB.
+ * If the TLB contains a host virtual address suitable for direct RAM
+ * access, then return it. Otherwise (TLB miss, TLB entry is for an
+ * I/O access, etc) return NULL.
+ *
+ * This is the equivalent of the initial fast-path code used by
+ * TCG backends for guest load and store accesses.
+ */
+static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
+                                      int mmu_idx)
+{
+    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
+    uintptr_t haddr;
+
+    if ((addr & TARGET_PAGE_MASK)
+        != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        /* TLB entry is for a different page */
+        return NULL;
+    }
+
+    if (tlb_addr & ~TARGET_PAGE_MASK) {
+        /* IO access */
+        return NULL;
+    }
+
+    haddr = addr + env->tlb_table[mmu_idx][index].addend;
+    return (void *)haddr;
+}
diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 00234e1..41caa6c 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -150,6 +150,8 @@ typedef struct ARMCPU {
     uint32_t reset_cbar;
     uint32_t reset_auxcr;
     bool reset_hivecs;
+    /* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
+    uint32_t dcz_blocksize;
 } ARMCPU;
 
 #define TYPE_AARCH64_CPU "aarch64-cpu"
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 3a0c38d..fa826c4 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -755,7 +755,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
 #define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
 #define ARM_CP_CURRENTEL (ARM_CP_SPECIAL | (4 << 8))
-#define ARM_LAST_SPECIAL ARM_CP_CURRENTEL
+#define ARM_CP_DC_ZVA (ARM_CP_SPECIAL | (5 << 8))
+#define ARM_LAST_SPECIAL ARM_CP_DC_ZVA
 /* Used only as a terminator for ARMCPRegInfo lists */
 #define ARM_CP_SENTINEL 0xffff
 /* Mask of only the flag bits in a type field */
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index 8426bf1..fccecc2 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -46,6 +46,7 @@ static void aarch64_any_initfn(Object *obj)
     set_feature(&cpu->env, ARM_FEATURE_V7MP);
     set_feature(&cpu->env, ARM_FEATURE_AARCH64);
     cpu->ctr = 0x80030003; /* 32 byte I and D cacheline size, VIPT icache */
+    cpu->dcz_blocksize = 7; /*  512 bytes */
 }
 #endif
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index e1672aa..45e6910 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -10,6 +10,8 @@
 #include <zlib.h> /* For crc32 */
 
 #ifndef CONFIG_USER_ONLY
+#include "exec/softmmu_exec.h"
+
 static inline int get_phys_addr(CPUARMState *env, target_ulong address,
                                 int access_type, int is_user,
                                 hwaddr *phys_ptr, int *prot,
@@ -1644,6 +1646,29 @@ static void tlbi_aa64_asid_write(CPUARMState *env, const ARMCPRegInfo *ri,
     tlb_flush(env, asid == 0);
 }
 
+static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    /* We don't implement EL2, so the only control on DC ZVA is the
+     * bit in the SCTLR which can prohibit access for EL0.
+     */
+    if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_DZE)) {
+        return CP_ACCESS_TRAP;
+    }
+    return CP_ACCESS_OK;
+}
+
+static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    int dzp_bit = 1 << 4;
+
+    /* DZP indicates whether DC ZVA access is allowed */
+    if (aa64_zva_access(env, NULL) != CP_ACCESS_OK) {
+        dzp_bit = 0;
+    }
+    return cpu->dcz_blocksize | dzp_bit;
+}
+
 static const ARMCPRegInfo v8_cp_reginfo[] = {
     /* Minimal set of EL0-visible registers. This will need to be expanded
      * significantly for system emulation of AArch64 CPUs.
@@ -1663,13 +1688,18 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     { .name = "FPSR", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
       .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
-    /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
-     * For system mode the DZP bit here will need to be computed, not constant.
-     */
     { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
-      .access = PL0_R, .type = ARM_CP_CONST,
-      .resetvalue = 0x10 },
+      .access = PL0_R, .type = ARM_CP_NO_MIGRATE,
+      .readfn = aa64_dczid_read },
+    { .name = "DC_ZVA", .state = ARM_CP_STATE_AA64,
+      .opc0 = 1, .opc1 = 3, .crn = 7, .crm = 4, .opc2 = 1,
+      .access = PL0_W, .type = ARM_CP_DC_ZVA,
+#ifndef CONFIG_USER_ONLY
+      /* Avoid overhead of an access check that always passes in user-mode */
+      .accessfn = aa64_zva_access,
+#endif
+    },
     { .name = "CURRENTEL", .state = ARM_CP_STATE_AA64,
       .opc0 = 3, .opc1 = 0, .opc2 = 2, .crn = 4, .crm = 2,
       .access = PL1_R, .type = ARM_CP_CURRENTEL },
@@ -3820,6 +3850,88 @@ void HELPER(v7m_msr)(CPUARMState *env, uint32_t reg, uint32_t val)
 
 #endif
 
+void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
+{
+    /* Implement DC ZVA, which zeroes a fixed-length block of memory.
+     * Note that we do not implement the (architecturally mandated)
+     * alignment fault for attempts to use this on Device memory
+     * (which matches the usual QEMU behaviour of not implementing either
+     * alignment faults or any memory attribute handling).
+     */
+
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    uint64_t blocklen = 4 << cpu->dcz_blocksize;
+    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
+
+#ifndef CONFIG_USER_ONLY
+    {
+        /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
+         * the block size so we might have to do more than one TLB lookup.
+         * We know that in fact for any v8 CPU the page size is at least 4K
+         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
+         * 1K as an artefact of legacy v5 subpage support being present in the
+         * same QEMU executable.
+         */
+        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
+        void *hostaddr[maxidx];
+        int try, i;
+
+        for (try = 0; try < 2; try++) {
+
+            for (i = 0; i < maxidx; i++) {
+                hostaddr[i] = tlb_vaddr_to_host(env,
+                                                vaddr + TARGET_PAGE_SIZE * i,
+                                                cpu_mmu_index(env));
+                if (!hostaddr[i]) {
+                    break;
+                }
+            }
+            if (i == maxidx) {
+                /* If it's all in the TLB it's fair game for just writing to;
+                 * we know we don't need to update dirty status, etc.
+                 */
+                for (i = 0; i < maxidx - 1; i++) {
+                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
+                }
+                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
+                return;
+            }
+            /* OK, try a store and see if we can populate the tlb. This
+             * might cause an exception if the memory isn't writable,
+             * in which case we will longjmp out of here. We must for
+             * this purpose use the actual register value passed to us
+             * so that we get the fault address right.
+             */
+            cpu_stb_data(env, vaddr_in, 0);
+            /* Now we can populate the other TLB entries, if any */
+            for (i = 0; i < maxidx; i++) {
+                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
+                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
+                    cpu_stb_data(env, va, 0);
+                }
+            }
+        }
+
+        /* Slow path (probably attempt to do this to an I/O device or
+         * similar, or clearing of a block of code we have translations
+         * cached for). Just do a series of byte writes as the architecture
+         * demands. It's not worth trying to use a cpu_physical_memory_map(),
+         * memset(), unmap() sequence here because:
+         *  + we'd need to account for the blocksize being larger than a page
+         *  + the direct-RAM access case is almost always going to be dealt
+         *    with in the fastpath code above, so there's no speed benefit
+         *  + we would have to deal with the map returning NULL because the
+         *    bounce buffer was in use
+         */
+        for (i = 0; i < blocklen; i++) {
+            cpu_stb_data(env, vaddr + i, 0);
+        }
+    }
+#else
+    memset(g2h(vaddr), 0, blocklen);
+#endif
+}
+
 /* Note that signed overflow is undefined in C.  The following routines are
    careful to use unsigned types where modulo arithmetic is required.
    Failure to do so _will_ break on newer gcc.  */
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 2729ea5..4c924e9 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -502,6 +502,7 @@ DEF_HELPER_4(crypto_aesmc, void, env, i32, i32, i32)
 
 DEF_HELPER_FLAGS_3(crc32, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
 DEF_HELPER_FLAGS_3(crc32c, TCG_CALL_NO_RWG_SE, i32, i32, i32, i32)
+DEF_HELPER_2(dc_zva, void, env, i64)
 
 #ifdef TARGET_AARCH64
 #include "helper-a64.h"
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7054fa1..4eaea64 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1331,6 +1331,11 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
         tcg_rt = cpu_reg(s, rt);
         tcg_gen_movi_i64(tcg_rt, s->current_pl << 2);
         return;
+    case ARM_CP_DC_ZVA:
+        /* Writes clear the aligned block of memory which rt points into. */
+        tcg_rt = cpu_reg(s, rt);
+        gen_helper_dc_zva(cpu_env, tcg_rt);
+        return;
     default:
         break;
     }
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (11 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  5:20   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers Peter Maydell
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

The ARM946 model currently uses the c5_data and c5_insn fields in the CPU
state struct to store the contents of its access permission registers.
This is confusing and a good source of bugs because for all the MMU-based
CPUs those fields are fault status and fault address registers, which
behave completely differently; they just happen to use the same cpreg
encoding. Split them out to use their own fields instead.

These registers are only present in PMSAv5 MPU systems (of which the
ARM946 is our only current example); PMSAv6 and PMSAv7 (which we have
no implementations of) handle access permissions differently. We name
the new state fields accordingly.

Note that this change fixes a bug where a data abort or prefetch abort
on the ARM946 would accidentally corrupt the access permission registers
because the interrupt handling code assumed the c5_data and c5_insn
fields were always fault status registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h    |  2 ++
 target-arm/helper.c | 24 ++++++++++++++----------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index fa826c4..ffa4b37 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -179,6 +179,8 @@ typedef struct CPUARMState {
         uint32_t c2_insn; /* MPU instruction cachable bits.  */
         uint32_t c3; /* MMU domain access control register
                         MPU write buffer control.  */
+        uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
+        uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
         uint32_t c5_insn; /* Fault status registers.  */
         uint32_t c5_data;
         uint32_t c6_region[8]; /* MPU base/size registers.  */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 45e6910..cbef0e5 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1183,40 +1183,44 @@ static uint32_t extended_mpu_ap_bits(uint32_t val)
 static void pmsav5_data_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                  uint64_t value)
 {
-    env->cp15.c5_data = extended_mpu_ap_bits(value);
+    env->cp15.pmsav5_data_ap = extended_mpu_ap_bits(value);
 }
 
 static uint64_t pmsav5_data_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
-    return simple_mpu_ap_bits(env->cp15.c5_data);
+    return simple_mpu_ap_bits(env->cp15.pmsav5_data_ap);
 }
 
 static void pmsav5_insn_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
                                  uint64_t value)
 {
-    env->cp15.c5_insn = extended_mpu_ap_bits(value);
+    env->cp15.pmsav5_insn_ap = extended_mpu_ap_bits(value);
 }
 
 static uint64_t pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
 {
-    return simple_mpu_ap_bits(env->cp15.c5_insn);
+    return simple_mpu_ap_bits(env->cp15.pmsav5_insn_ap);
 }
 
 static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
     { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0,
+      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
+      .resetvalue = 0,
       .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, },
     { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0,
+      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap),
+      .resetvalue = 0,
       .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, },
     { .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
+      .resetvalue = 0, },
     { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap),
+      .resetvalue = 0, },
     { .name = "DCACHE_CFG", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW,
       .fieldoffset = offsetof(CPUARMState, cp15.c2_data), .resetvalue = 0, },
@@ -3568,9 +3572,9 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
 	return 2;
 
     if (access_type == 2) {
-	mask = env->cp15.c5_insn;
+        mask = env->cp15.pmsav5_insn_ap;
     } else {
-	mask = env->cp15.c5_data;
+        mask = env->cp15.pmsav5_data_ap;
     }
     mask = (mask >> (n * 4)) & 0xf;
     switch (mask) {
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (12 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  5:30   ` Peter Crosthwaite
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register Peter Maydell
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Rob Herring <rob.herring@linaro.org>

Implement AArch64 views of ESR_EL1 and FAR_EL1, and make the 32 bit
DFSR, DFAR, IFAR share state with them as architecturally specified.
The IFSR doesn't share state with any AArch64 register visible at EL1,
so just rename the state field without widening it to 64 bits.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
[PMM: Minor tweaks; fix some bugs involving inconsistencies between
 use of offsetof() or offsetoflow32() and struct field width]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.c    |  2 +-
 target-arm/cpu.h    |  7 +++----
 target-arm/helper.c | 38 +++++++++++++++++++++++++-------------
 3 files changed, 29 insertions(+), 18 deletions(-)

diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 871ed09..948fd44 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -419,7 +419,7 @@ static void arm1026_initfn(Object *obj)
         ARMCPRegInfo ifar = {
             .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
             .access = PL1_RW,
-            .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
+            .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
             .resetvalue = 0
         };
         define_one_arm_cp_reg(cpu, &ifar);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index ffa4b37..e51add2 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -181,11 +181,10 @@ typedef struct CPUARMState {
                         MPU write buffer control.  */
         uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
         uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
-        uint32_t c5_insn; /* Fault status registers.  */
-        uint32_t c5_data;
+        uint32_t ifsr_el2; /* Fault status registers.  */
+        uint64_t esr_el1;
         uint32_t c6_region[8]; /* MPU base/size registers.  */
-        uint32_t c6_insn; /* Fault address registers.  */
-        uint32_t c6_data;
+        uint64_t far_el1; /* Fault address registers.  */
         uint32_t c7_par;  /* Translation result. */
         uint32_t c7_par_hi;  /* Translation result, high 32 bits */
         uint32_t c9_insn; /* Cache lockdown registers.  */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index cbef0e5..8d96b5c 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -456,7 +456,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
     { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
       .access = PL0_W, .type = ARM_CP_NOP },
     { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
+      .access = PL1_RW,
+      .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
       .resetvalue = 0, },
     /* Watchpoint Fault Address Register : should actually only be present
      * for 1136, 1176, 11MPCore.
@@ -1316,11 +1317,16 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
 
 static const ARMCPRegInfo vmsa_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
+      .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .resetfn = arm_cp_reset_ignore, },
     { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
+      .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, },
+    { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
     { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
       .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
@@ -1338,8 +1344,10 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
       .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
       .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
       .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
-    { .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
-      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data),
+    /* 64-bit FAR; this entry also gives us the AArch32 DFAR */
+    { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
       .resetvalue = 0, },
     REGINFO_SENTINEL
 };
@@ -1379,7 +1387,8 @@ static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
 static const ARMCPRegInfo omap_cp_reginfo[] = {
     { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
       .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
-      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
+      .resetvalue = 0, },
     { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
       .access = PL1_RW, .type = ARM_CP_NOP },
     { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
@@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
         env->exception.fsr = 2;
         /* Fall through to prefetch abort.  */
     case EXCP_PREFETCH_ABORT:
-        env->cp15.c5_insn = env->exception.fsr;
-        env->cp15.c6_insn = env->exception.vaddress;
+        env->cp15.ifsr_el2 = env->exception.fsr;
+        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
+                                      env->exception.vaddress);
         qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
-                      env->cp15.c5_insn, env->cp15.c6_insn);
+                      env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
         new_mode = ARM_CPU_MODE_ABT;
         addr = 0x0c;
         mask = CPSR_A | CPSR_I;
         offset = 4;
         break;
     case EXCP_DATA_ABORT:
-        env->cp15.c5_data = env->exception.fsr;
-        env->cp15.c6_data = env->exception.vaddress;
+        env->cp15.esr_el1 = env->exception.fsr;
+        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
+                                      env->exception.vaddress);
         qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
-                      env->cp15.c5_data, env->cp15.c6_data);
+                      (uint32_t)env->cp15.esr_el1,
+                      (uint32_t)env->exception.vaddress);
         new_mode = ARM_CPU_MODE_ABT;
         addr = 0x10;
         mask = CPSR_A | CPSR_I;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register.
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (13 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers Peter Maydell
@ 2014-03-06 19:32 ` Peter Maydell
  2014-03-17  5:33   ` Peter Crosthwaite
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1 Peter Maydell
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:32 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Add the AArch64 ELR_EL1 register.

Note that this does not live in env->cp15: for KVM migration
compatibility we need to migrate it separately rather than
as part of the system registers, because the KVM-to-userspace
interface puts it in the struct kvm_regs rather than making
them visible via the ONE_REG ioctls.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h     |  2 ++
 target-arm/helper.c  |  4 ++++
 target-arm/kvm64.c   | 15 ++++++++++++++-
 target-arm/machine.c |  7 ++++---
 4 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index e51add2..7ef2c71 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -162,6 +162,8 @@ typedef struct CPUARMState {
     uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
     uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
 
+    uint64_t elr_el1; /* AArch64 ELR_EL1 */
+
     /* System control coprocessor (cp15) */
     struct {
         uint32_t c0_cpuid;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 8d96b5c..812fc73 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1810,6 +1810,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
     { .name = "OSLAR_EL1", .state = ARM_CP_STATE_AA64,
       .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
       .access = PL1_W, .type = ARM_CP_NOP },
+    { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
     REGINFO_SENTINEL
 };
 
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 1b7ca90..ee72748 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -144,9 +144,15 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         return ret;
     }
 
+    reg.id = AARCH64_CORE_REG(elr_el1);
+    reg.addr = (uintptr_t) &env->elr_el1;
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
     /* TODO:
      * SP_EL1
-     * ELR_EL1
      * SPSR[]
      * FP state
      * system registers
@@ -195,6 +201,13 @@ int kvm_arch_get_registers(CPUState *cs)
         return ret;
     }
 
+    reg.id = AARCH64_CORE_REG(elr_el1);
+    reg.addr = (uintptr_t) &env->elr_el1;
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
     /* TODO: other registers */
     return ret;
 }
diff --git a/target-arm/machine.c b/target-arm/machine.c
index fc8825e..01d8f83 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_arm_cpu = {
     .name = "cpu",
-    .version_id = 14,
-    .minimum_version_id = 14,
-    .minimum_version_id_old = 14,
+    .version_id = 15,
+    .minimum_version_id = 15,
+    .minimum_version_id_old = 15,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -243,6 +243,7 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
         VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
+        VMSTATE_UINT64(env.elr_el1, ARMCPU),
         /* The length-check must come before the arrays to avoid
          * incoming data possibly overflowing the array.
          */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (14 preceding siblings ...)
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-17  7:02   ` Peter Crosthwaite
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 17/21] target-arm: Implement AArch64 SPSR_EL1 Peter Maydell
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Implement handling for the AArch64 SP_EL0 system register.
This holds the EL0 stack pointer, and is only accessible when
it's not being used as the stack pointer, ie when we're in EL1
and EL1 is using its own stack pointer. We also provide a
definition of the SP_EL1 register; this isn't guest visible
as a system register for an implementation like QEMU which
doesn't provide EL2 or EL3; however it is useful for ensuring
the underlying state is migrated.

We need to update the state fields in the CPU state whenever
switch stack pointers; this happens when we take an exception
and also when SPSEL is used to change the bit in PSTATE which
indicates which stack pointer EL1 should use.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h       |  2 ++
 target-arm/helper.c    | 34 ++++++++++++++++++++++++++++++++++
 target-arm/internals.h | 25 +++++++++++++++++++++++++
 target-arm/kvm64.c     | 37 ++++++++++++++++++++++++++++++++++---
 target-arm/machine.c   |  7 ++++---
 target-arm/op_helper.c |  2 +-
 6 files changed, 100 insertions(+), 7 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 7ef2c71..338edc3 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -163,6 +163,7 @@ typedef struct CPUARMState {
     uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
 
     uint64_t elr_el1; /* AArch64 ELR_EL1 */
+    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
 
     /* System control coprocessor (cp15) */
     struct {
@@ -431,6 +432,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
  * Only these are valid when in AArch64 mode; in
  * AArch32 mode SPSRs are basically CPSR-format.
  */
+#define PSTATE_SP (1U)
 #define PSTATE_M (0xFU)
 #define PSTATE_nRW (1U << 4)
 #define PSTATE_F (1U << 6)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 812fc73..6ee4135 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1682,6 +1682,27 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
     return cpu->dcz_blocksize | dzp_bit;
 }
 
+static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    if (!env->pstate & PSTATE_SP) {
+        /* Access to SP_EL0 is undefined if it's being used as
+         * the stack pointer.
+         */
+        return CP_ACCESS_TRAP_UNCATEGORIZED;
+    }
+    return CP_ACCESS_OK;
+}
+
+static uint64_t spsel_read(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    return env->pstate & PSTATE_SP;
+}
+
+static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
+{
+    update_spsel(env, val);
+}
+
 static const ARMCPRegInfo v8_cp_reginfo[] = {
     /* Minimal set of EL0-visible registers. This will need to be expanded
      * significantly for system emulation of AArch64 CPUs.
@@ -1814,6 +1835,19 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .type = ARM_CP_NO_MIGRATE,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
+    /* We rely on the access checks not allowing the guest to write to the
+     * state field when SPSel indicates that it's being used as the stack
+     * pointer.
+     */
+    { .name = "SP_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 1, .opc2 = 0,
+      .access = PL1_RW, .accessfn = sp_el0_access,
+      .type = ARM_CP_NO_MIGRATE,
+      .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
+    { .name = "SPSel", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
+      .type = ARM_CP_NO_MIGRATE,
+      .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
     REGINFO_SENTINEL
 };
 
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 11a7040..97a76c2 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -60,6 +60,31 @@ enum arm_fprounding {
 
 int arm_rmode_to_sf(int rmode);
 
+static inline void update_spsel(CPUARMState *env, uint32_t imm)
+{
+    /* Update PSTATE SPSel bit; this requires us to update the
+     * working stack pointer in xregs[31].
+     */
+    if (!((imm ^ env->pstate) & PSTATE_SP)) {
+        return;
+    }
+    env->pstate = deposit32(env->pstate, 0, 1, imm);
+
+    /* EL0 has no access rights to update SPSel, and this code
+     * assumes we are updating SP for EL1 while running as EL1.
+     */
+    assert(arm_current_pl(env) == 1);
+    if (env->pstate & PSTATE_SP) {
+        /* Switch from using SP_EL0 to using SP_ELx */
+        env->sp_el[0] = env->xregs[31];
+        env->xregs[31] = env->sp_el[1];
+    } else {
+        /* Switch from SP_EL0 to SP_ELx */
+        env->sp_el[1] = env->xregs[31];
+        env->xregs[31] = env->sp_el[0];
+    }
+}
+
 /* Valid Syndrome Register EC field values */
 enum arm_exception_class {
     EC_UNCATEGORIZED = 0,
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index ee72748..39c4364 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         }
     }
 
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    if (env->pstate & PSTATE_SP) {
+        env->sp_el[1] = env->xregs[31];
+    } else {
+        env->sp_el[0] = env->xregs[31];
+    }
+
     reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->xregs[31];
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
     if (ret) {
         return ret;
@@ -152,7 +168,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
     }
 
     /* TODO:
-     * SP_EL1
      * SPSR[]
      * FP state
      * system registers
@@ -180,7 +195,14 @@ int kvm_arch_get_registers(CPUState *cs)
     }
 
     reg.id = AARCH64_CORE_REG(regs.sp);
-    reg.addr = (uintptr_t) &env->xregs[31];
+    reg.addr = (uintptr_t) &env->sp_el[0];
+    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+    if (ret) {
+        return ret;
+    }
+
+    reg.id = AARCH64_CORE_REG(sp_el1);
+    reg.addr = (uintptr_t) &env->sp_el[1];
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
     if (ret) {
         return ret;
@@ -194,6 +216,15 @@ int kvm_arch_get_registers(CPUState *cs)
     }
     pstate_write(env, val);
 
+    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
+     * QEMU side we keep the current SP in xregs[31] as well.
+     */
+    if (env->pstate & PSTATE_SP) {
+        env->xregs[31] = env->sp_el[1];
+    } else {
+        env->xregs[31] = env->sp_el[0];
+    }
+
     reg.id = AARCH64_CORE_REG(regs.pc);
     reg.addr = (uintptr_t) &env->pc;
     ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 01d8f83..af49662 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_arm_cpu = {
     .name = "cpu",
-    .version_id = 15,
-    .minimum_version_id = 15,
-    .minimum_version_id_old = 15,
+    .version_id = 16,
+    .minimum_version_id = 16,
+    .minimum_version_id_old = 16,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -244,6 +244,7 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
         VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
         VMSTATE_UINT64(env.elr_el1, ARMCPU),
+        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
         /* The length-check must come before the arrays to avoid
          * incoming data possibly overflowing the array.
          */
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index b1db672..aeb2538 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -349,7 +349,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
 
     switch (op) {
     case 0x05: /* SPSel */
-        env->pstate = deposit32(env->pstate, 0, 1, imm);
+        update_spsel(env, imm);
         break;
     case 0x1e: /* DAIFSet */
         env->daif |= (imm << 6) & PSTATE_DAIF;
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 17/21] target-arm: Implement AArch64 SPSR_EL1
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (15 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1 Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h Peter Maydell
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Implement the AArch64 SPSR_EL1. For compatibility with how KVM
handles SPSRs and with the architectural mapping between AArch32
and AArch64, we put this in the banked_spsr[] array in the slot
that is used for SVC in AArch32. This means we need to extend the
array from uint32_t to uint64_t, which requires some reworking
of the 32 bit KVM save/restore code.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h     |  2 +-
 target-arm/helper.c  |  4 ++++
 target-arm/kvm32.c   | 18 +++++++++++++-----
 target-arm/kvm64.c   | 19 ++++++++++++++++++-
 target-arm/machine.c |  8 ++++----
 5 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 338edc3..5d5f64e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -143,7 +143,7 @@ typedef struct CPUARMState {
     uint32_t spsr;
 
     /* Banked registers.  */
-    uint32_t banked_spsr[6];
+    uint64_t banked_spsr[6];
     uint32_t banked_r13[6];
     uint32_t banked_r14[6];
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 6ee4135..3a976f7 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1835,6 +1835,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
       .type = ARM_CP_NO_MIGRATE,
       .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
       .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
+    { .name = "SPSR_EL1", .state = ARM_CP_STATE_AA64,
+      .type = ARM_CP_NO_MIGRATE,
+      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 0,
+      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, banked_spsr[0]) },
     /* We rely on the access checks not allowing the guest to write to the
      * state field when SPSel indicates that it's being used as the stack
      * pointer.
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index b21f844..a690d99 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -295,6 +295,14 @@ typedef struct Reg {
         offsetof(CPUARMState, vfp.xregs[ARM_VFP_##R])      \
     }
 
+/* Like COREREG, but handle fields which are in a uint64_t in CPUARMState. */
+#define COREREG64(KERNELNAME, QEMUFIELD)                     \
+    {                                                        \
+        KVM_REG_ARM | KVM_REG_SIZE_U32 |                     \
+        KVM_REG_ARM_CORE | KVM_REG_ARM_CORE_REG(KERNELNAME), \
+        offsetoflow32(CPUARMState, QEMUFIELD)                \
+    }
+
 static const Reg regs[] = {
     /* R0_usr .. R14_usr */
     COREREG(usr_regs.uregs[0], regs[0]),
@@ -315,16 +323,16 @@ static const Reg regs[] = {
     /* R13, R14, SPSR for SVC, ABT, UND, IRQ banks */
     COREREG(svc_regs[0], banked_r13[1]),
     COREREG(svc_regs[1], banked_r14[1]),
-    COREREG(svc_regs[2], banked_spsr[1]),
+    COREREG64(svc_regs[2], banked_spsr[1]),
     COREREG(abt_regs[0], banked_r13[2]),
     COREREG(abt_regs[1], banked_r14[2]),
-    COREREG(abt_regs[2], banked_spsr[2]),
+    COREREG64(abt_regs[2], banked_spsr[2]),
     COREREG(und_regs[0], banked_r13[3]),
     COREREG(und_regs[1], banked_r14[3]),
-    COREREG(und_regs[2], banked_spsr[3]),
+    COREREG64(und_regs[2], banked_spsr[3]),
     COREREG(irq_regs[0], banked_r13[4]),
     COREREG(irq_regs[1], banked_r14[4]),
-    COREREG(irq_regs[2], banked_spsr[4]),
+    COREREG64(irq_regs[2], banked_spsr[4]),
     /* R8_fiq .. R14_fiq and SPSR_fiq */
     COREREG(fiq_regs[0], fiq_regs[0]),
     COREREG(fiq_regs[1], fiq_regs[1]),
@@ -333,7 +341,7 @@ static const Reg regs[] = {
     COREREG(fiq_regs[4], fiq_regs[4]),
     COREREG(fiq_regs[5], banked_r13[5]),
     COREREG(fiq_regs[6], banked_r14[5]),
-    COREREG(fiq_regs[7], banked_spsr[5]),
+    COREREG64(fiq_regs[7], banked_spsr[5]),
     /* R15 */
     COREREG(usr_regs.uregs[15], regs[15]),
     /* VFP system registers */
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 39c4364..e115879 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -167,8 +167,16 @@ int kvm_arch_put_registers(CPUState *cs, int level)
         return ret;
     }
 
+    for (i = 0; i < KVM_NR_SPSR; i++) {
+        reg.id = AARCH64_CORE_REG(spsr[i]);
+        reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+        ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
     /* TODO:
-     * SPSR[]
      * FP state
      * system registers
      */
@@ -239,6 +247,15 @@ int kvm_arch_get_registers(CPUState *cs)
         return ret;
     }
 
+    for (i = 0; i < KVM_NR_SPSR; i++) {
+        reg.id = AARCH64_CORE_REG(spsr[i]);
+        reg.addr = (uintptr_t) &env->banked_spsr[i - 1];
+        ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
+        if (ret) {
+            return ret;
+        }
+    }
+
     /* TODO: other registers */
     return ret;
 }
diff --git a/target-arm/machine.c b/target-arm/machine.c
index af49662..3bacc12 100644
--- a/target-arm/machine.c
+++ b/target-arm/machine.c
@@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
 
 const VMStateDescription vmstate_arm_cpu = {
     .name = "cpu",
-    .version_id = 16,
-    .minimum_version_id = 16,
-    .minimum_version_id_old = 16,
+    .version_id = 17,
+    .minimum_version_id = 17,
+    .minimum_version_id_old = 17,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -238,7 +238,7 @@ const VMStateDescription vmstate_arm_cpu = {
             .offset = 0,
         },
         VMSTATE_UINT32(env.spsr, ARMCPU),
-        VMSTATE_UINT32_ARRAY(env.banked_spsr, ARMCPU, 6),
+        VMSTATE_UINT64_ARRAY(env.banked_spsr, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.banked_r13, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
         VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (16 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 17/21] target-arm: Implement AArch64 SPSR_EL1 Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-17  7:04   ` Peter Crosthwaite
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 19/21] target-arm: Implement AArch64 EL1 exception handling Peter Maydell
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Move arm_log_exception() into internals.h so we can use it from
helper-a64.c for the AArch64 exception entry code.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c    | 31 -------------------------------
 target-arm/internals.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 31 deletions(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3a976f7..e461914 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2849,37 +2849,6 @@ static void do_v7m_exception_exit(CPUARMState *env)
        pointer.  */
 }
 
-/* Exception names for debug logging; note that not all of these
- * precisely correspond to architectural exceptions.
- */
-static const char * const excnames[] = {
-    [EXCP_UDEF] = "Undefined Instruction",
-    [EXCP_SWI] = "SVC",
-    [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
-    [EXCP_DATA_ABORT] = "Data Abort",
-    [EXCP_IRQ] = "IRQ",
-    [EXCP_FIQ] = "FIQ",
-    [EXCP_BKPT] = "Breakpoint",
-    [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
-    [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
-    [EXCP_STREX] = "QEMU intercept of STREX",
-};
-
-static inline void arm_log_exception(int idx)
-{
-    if (qemu_loglevel_mask(CPU_LOG_INT)) {
-        const char *exc = NULL;
-
-        if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
-            exc = excnames[idx];
-        }
-        if (!exc) {
-            exc = "unknown";
-        }
-        qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
-    }
-}
-
 void arm_v7m_cpu_do_interrupt(CPUState *cs)
 {
     ARMCPU *cpu = ARM_CPU(cs);
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 97a76c2..e15136b 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -39,6 +39,37 @@ static inline bool excp_is_internal(int excp)
         || excp == EXCP_STREX;
 }
 
+/* Exception names for debug logging; note that not all of these
+ * precisely correspond to architectural exceptions.
+ */
+static const char * const excnames[] = {
+    [EXCP_UDEF] = "Undefined Instruction",
+    [EXCP_SWI] = "SVC",
+    [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
+    [EXCP_DATA_ABORT] = "Data Abort",
+    [EXCP_IRQ] = "IRQ",
+    [EXCP_FIQ] = "FIQ",
+    [EXCP_BKPT] = "Breakpoint",
+    [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
+    [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
+    [EXCP_STREX] = "QEMU intercept of STREX",
+};
+
+static inline void arm_log_exception(int idx)
+{
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
+        const char *exc = NULL;
+
+        if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
+            exc = excnames[idx];
+        }
+        if (!exc) {
+            exc = "unknown";
+        }
+        qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
+    }
+}
+
 /* Scale factor for generic timers, ie number of ns per tick.
  * This gives a 62.5MHz timer.
  */
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 19/21] target-arm: Implement AArch64 EL1 exception handling
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (17 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor Peter Maydell
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Rob Herring <rob.herring@linaro.org>

Implement exception handling for AArch64 EL1. Exceptions from AArch64 or
AArch32 EL0 are supported.

Signed-off-by: Rob Herring <rob.herring@linaro.org>
[PMM: fixed minor style nits; updated to match changes in
 previous patches; added some of the simpler cases of
 illegal-exception-return support]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu-qom.h       |  2 ++
 target-arm/cpu64.c         |  1 +
 target-arm/helper-a64.c    | 75 ++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/helper.h        |  1 +
 target-arm/op_helper.c     | 60 +++++++++++++++++++++++++++++++++++++
 target-arm/translate-a64.c |  3 ++
 6 files changed, 142 insertions(+)

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index 41caa6c..afdee9d 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -202,6 +202,8 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
                             fprintf_function cpu_fprintf, int flags);
 int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
+
+void aarch64_cpu_do_interrupt(CPUState *cs);
 #endif
 
 #endif
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index fccecc2..d4fb1de 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -85,6 +85,7 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
 {
     CPUClass *cc = CPU_CLASS(oc);
 
+    cc->do_interrupt = aarch64_cpu_do_interrupt;
     cc->dump_state = aarch64_cpu_dump_state;
     cc->set_pc = aarch64_cpu_set_pc;
     cc->gdb_read_register = aarch64_cpu_gdb_read_register;
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 80ed029..4f501b4 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -23,6 +23,7 @@
 #include "qemu/host-utils.h"
 #include "sysemu/sysemu.h"
 #include "qemu/bitops.h"
+#include "internals.h"
 
 /* C2.4.7 Multiply and divide */
 /* special cases for 0 and LLONG_MIN are mandated by the standard */
@@ -288,3 +289,77 @@ float64 HELPER(rsqrtsf_f64)(float64 a, float64 b, void *fpstp)
     }
     return float64_muladd(a, b, float64_three, float_muladd_halve_result, fpst);
 }
+
+/* Handle a CPU exception.  */
+void aarch64_cpu_do_interrupt(CPUState *cs)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    target_ulong addr = env->cp15.c12_vbar;
+    int i;
+
+    if (arm_current_pl(env) == 0) {
+        if (env->aarch64) {
+            addr += 0x400;
+        } else {
+            addr += 0x600;
+        }
+    } else if (pstate_read(env) & PSTATE_SP) {
+        addr += 0x200;
+    }
+
+    arm_log_exception(env->exception_index);
+    qemu_log_mask(CPU_LOG_INT, "...from EL%d\n", arm_current_pl(env));
+    if (qemu_loglevel_mask(CPU_LOG_INT)
+        && !excp_is_internal(env->exception_index)) {
+        qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
+                      env->exception.syndrome);
+    }
+
+    env->cp15.esr_el1 = env->exception.syndrome;
+    env->cp15.far_el1 = env->exception.vaddress;
+
+    switch (env->exception_index) {
+    case EXCP_PREFETCH_ABORT:
+    case EXCP_DATA_ABORT:
+        qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
+                      env->cp15.far_el1);
+    case EXCP_BKPT:
+    case EXCP_UDEF:
+    case EXCP_SWI:
+        break;
+    case EXCP_IRQ:
+        addr += 0x80;
+        break;
+    case EXCP_FIQ:
+        addr += 0x100;
+        break;
+    default:
+        cpu_abort(env, "Unhandled exception 0x%x\n", env->exception_index);
+    }
+
+    if (is_a64(env)) {
+        env->banked_spsr[0] = pstate_read(env);
+        env->sp_el[arm_current_pl(env)] = env->xregs[31];
+        env->xregs[31] = env->sp_el[1];
+        env->elr_el1 = env->pc;
+    } else {
+        env->banked_spsr[0] = cpsr_read(env);
+        if (!env->thumb) {
+            env->cp15.esr_el1 |= 1 << 25;
+        }
+        env->elr_el1 = env->regs[15];
+
+        for (i = 0; i < 15; i++) {
+            env->xregs[i] = env->regs[i];
+        }
+
+        env->condexec_bits = 0;
+    }
+
+    pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
+    env->aarch64 = 1;
+
+    env->pc = addr;
+    cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
diff --git a/target-arm/helper.h b/target-arm/helper.h
index 4c924e9..313d4cb 100644
--- a/target-arm/helper.h
+++ b/target-arm/helper.h
@@ -65,6 +65,7 @@ DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
 DEF_HELPER_2(get_cp_reg64, i64, env, ptr)
 
 DEF_HELPER_3(msr_i_pstate, void, env, i32, i32)
+DEF_HELPER_1(exception_return, void, env)
 
 DEF_HELPER_2(get_r13_banked, i32, env, i32)
 DEF_HELPER_3(set_r13_banked, void, env, i32, i32)
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index aeb2538..5581f4f 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -362,6 +362,66 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
     }
 }
 
+void HELPER(exception_return)(CPUARMState *env)
+{
+    uint32_t spsr = env->banked_spsr[0];
+    int new_el, i;
+
+    if (env->pstate & PSTATE_SP) {
+        env->sp_el[1] = env->xregs[31];
+    } else {
+        env->sp_el[0] = env->xregs[31];
+    }
+
+    env->exclusive_addr = -1;
+
+    if (spsr & PSTATE_nRW) {
+        env->aarch64 = 0;
+        new_el = 0;
+        env->uncached_cpsr = 0x10;
+        cpsr_write(env, spsr, ~0);
+        for (i = 0; i < 15; i++) {
+            env->regs[i] = env->xregs[i];
+        }
+
+        env->regs[15] = env->elr_el1 & ~0x1;
+    } else {
+        new_el = extract32(spsr, 2, 2);
+        if (new_el > 1) {
+            /* Return to unimplemented EL */
+            goto illegal_return;
+        }
+        if (extract32(spsr, 1, 1)) {
+            /* Return with reserved M[1] bit set */
+            goto illegal_return;
+        }
+        if (new_el == 0 && (spsr & PSTATE_SP)) {
+            /* Return to EL1 with M[0] bit set */
+            goto illegal_return;
+        }
+        env->aarch64 = 1;
+        pstate_write(env, spsr);
+        env->xregs[31] = env->sp_el[new_el];
+        env->pc = env->elr_el1;
+    }
+
+    return;
+
+illegal_return:
+    /* Illegal return events of various kinds have architecturally
+     * mandated behaviour:
+     * restore NZCV and DAIF from SPSR_ELx
+     * set PSTATE.IL
+     * restore PC from ELR_ELx
+     * no change to exception level, execution state or stack pointer
+     */
+    env->pstate |= PSTATE_IL;
+    env->pc = env->elr_el1;
+    spsr &= PSTATE_NZCV | PSTATE_DAIF;
+    spsr |= pstate_read(env) & ~(PSTATE_NZCV | PSTATE_DAIF);
+    pstate_write(env, spsr);
+}
+
 /* ??? Flag setting arithmetic is awkward because we need to do comparisons.
    The only way to do that in TCG is a conditional branch, which clobbers
    all our temporaries.  For now implement these as helper functions.  */
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 4eaea64..50c5148 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1508,6 +1508,9 @@ static void disas_uncond_b_reg(DisasContext *s, uint32_t insn)
         tcg_gen_movi_i64(cpu_reg(s, 30), s->pc);
         break;
     case 4: /* ERET */
+        gen_helper_exception_return(cpu_env);
+        s->is_jmp = DISAS_JUMP;
+        return;
     case 5: /* DRPS */
         if (rn != 0x1f) {
             unallocated_encoding(s);
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (18 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 19/21] target-arm: Implement AArch64 EL1 exception handling Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-20 19:18   ` Peter Maydell
  2014-03-26  2:34   ` Rob Herring
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57 Peter Maydell
  2014-03-07  4:09 ` [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Xuebing Wang
  21 siblings, 2 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Add Cortex-A57 processor.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu64.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index d4fb1de..cbdf7ed 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -32,6 +32,48 @@ static inline void set_feature(CPUARMState *env, int feature)
     env->features |= 1ULL << feature;
 }
 
+static void aarch64_a57_initfn(Object *obj)
+{
+    ARMCPU *cpu = ARM_CPU(obj);
+
+    set_feature(&cpu->env, ARM_FEATURE_V8);
+    set_feature(&cpu->env, ARM_FEATURE_VFP4);
+    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
+    set_feature(&cpu->env, ARM_FEATURE_NEON);
+    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
+    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
+    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
+    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
+    cpu->midr = 0x411fd070;
+    cpu->reset_fpsid = 0x41034070;
+    cpu->mvfr0 = 0x10110222;
+    cpu->mvfr1 = 0x12111111;
+    cpu->ctr = 0x8444c004;
+    cpu->reset_sctlr = 0x00c50838;
+    cpu->id_pfr0 = 0x00000131;
+    cpu->id_pfr1 = 0x00011011;
+    cpu->id_dfr0 = 0x03010066;
+    cpu->id_afr0 = 0x00000000;
+    cpu->id_mmfr0 = 0x10101105;
+    cpu->id_mmfr1 = 0x40000000;
+    cpu->id_mmfr2 = 0x01260000;
+    cpu->id_mmfr3 = 0x02102211;
+    cpu->id_isar0 = 0x02101110;
+    cpu->id_isar1 = 0x13112111;
+    cpu->id_isar2 = 0x21232042;
+    cpu->id_isar3 = 0x01112131;
+    cpu->id_isar4 = 0x00011142;
+    cpu->id_aa64pfr0 = 0x00002222;
+    cpu->id_aa64dfr0 = 0x10305106;
+    cpu->id_aa64isar0 = 0x00010000;
+    cpu->id_aa64mmfr0 = 0x00001124;
+    cpu->clidr = 0x0a200023;
+    cpu->ccsidr[0] = 0x701fe00a; /* 32KB L1 dcache */
+    cpu->ccsidr[1] = 0x201fe012; /* 48KB L1 icache */
+    cpu->ccsidr[2] = 0x70ffe07a; /* 2048KB L2 cache */
+    cpu->dcz_blocksize = 4; /* 64 bytes */
+}
+
 #ifdef CONFIG_USER_ONLY
 static void aarch64_any_initfn(Object *obj)
 {
@@ -57,6 +99,7 @@ typedef struct ARMCPUInfo {
 } ARMCPUInfo;
 
 static const ARMCPUInfo aarch64_cpus[] = {
+    { .name = "cortex-a57",         .initfn = aarch64_a57_initfn },
 #ifdef CONFIG_USER_ONLY
     { .name = "any",         .initfn = aarch64_any_initfn },
 #endif
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (19 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor Peter Maydell
@ 2014-03-06 19:33 ` Peter Maydell
  2014-03-17  7:12   ` Peter Crosthwaite
  2014-03-07  4:09 ` [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Xuebing Wang
  21 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-06 19:33 UTC (permalink / raw)
  To: qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Support the Cortex-A57 in the virt machine model.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
This should perhaps not be just stealing the a15mpcore_priv
on the basis that it's a GICv2...
---
 hw/arm/virt.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 517f2fe..d985d2e 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -123,6 +123,14 @@ static VirtBoardInfo machines[] = {
         .irqmap = a15irqmap,
     },
     {
+        .cpu_model = "cortex-a57",
+        /* Use the A15 private peripheral model for now: probably wrong! */
+        .qdevname = "a15mpcore_priv",
+        .gic_compatible = "arm,cortex-a15-gic",
+        .memmap = a15memmap,
+        .irqmap = a15irqmap,
+    },
+    {
         .cpu_model = "host",
         /* We use the A15 private peripheral model to get a V2 GIC */
         .qdevname = "a15mpcore_priv",
-- 
1.9.0

^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!)
  2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
                   ` (20 preceding siblings ...)
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57 Peter Maydell
@ 2014-03-07  4:09 ` Xuebing Wang
  2014-03-07  8:47   ` Peter Maydell
  21 siblings, 1 reply; 58+ messages in thread
From: Xuebing Wang @ 2014-03-07  4:09 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Laurent Desnogues, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson


On 03/07/2014 03:32 AM, Peter Maydell wrote:
> This is v4 of the AArch64 system emulation patches, and it's
> an important milestone -- this is enough to boot a Linux kernel.

Does this boot an aarch64 kernel with tcg on x86 host?

-- 
Thanks,
Xuebing Wang

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!)
  2014-03-07  4:09 ` [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Xuebing Wang
@ 2014-03-07  8:47   ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-07  8:47 UTC (permalink / raw)
  To: Xuebing Wang
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Claudio Fontana, QEMU Developers, Alexander Graf,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 7 March 2014 04:09, Xuebing Wang <xbing6@gmail.com> wrote:
>
> On 03/07/2014 03:32 AM, Peter Maydell wrote:
>>
>> This is v4 of the AArch64 system emulation patches, and it's
>> an important milestone -- this is enough to boot a Linux kernel.
>
>
> Does this boot an aarch64 kernel with tcg on x86 host?

Yes, that's what I mean. I also forgot to say you can find
this patchset in this git branch:
 git://git.linaro.org/people/pmaydell/qemu-arm.git a64-system-4

(static branch for people who prefer to review big patchsets
via git, won't update in future)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA Peter Maydell
@ 2014-03-07 14:51   ` Richard Henderson
  2014-03-07 15:11     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Richard Henderson @ 2014-03-07 14:51 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Rob Herring, Peter Crosthwaite, patches, Michael Matz,
	Claudio Fontana, Alexander Graf, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall

On 03/06/2014 11:32 AM, Peter Maydell wrote:
> +/**
> + * tlb_vaddr_to_host:
> + * @env: CPUArchState
> + * @addr: guest virtual address to look up
> + * @mmu_idx: MMU index to use for lookup
> + *
> + * Look up the specified guest virtual index in the TCG softmmu TLB.
> + * If the TLB contains a host virtual address suitable for direct RAM
> + * access, then return it. Otherwise (TLB miss, TLB entry is for an
> + * I/O access, etc) return NULL.
> + *
> + * This is the equivalent of the initial fast-path code used by
> + * TCG backends for guest load and store accesses.
> + */
> +static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
> +                                      int mmu_idx)
> +{
> +    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
> +    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;

Somewhere I think the function name or at least the block comment should
indicate that this lookup is for writing, since we hard-code addr_write here.

> +void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
> +{
> +    /* Implement DC ZVA, which zeroes a fixed-length block of memory.
> +     * Note that we do not implement the (architecturally mandated)
> +     * alignment fault for attempts to use this on Device memory
> +     * (which matches the usual QEMU behaviour of not implementing either
> +     * alignment faults or any memory attribute handling).
> +     */
> +
> +    ARMCPU *cpu = arm_env_get_cpu(env);
> +    uint64_t blocklen = 4 << cpu->dcz_blocksize;
> +    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
> +
> +#ifndef CONFIG_USER_ONLY
> +    {
> +        /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
> +         * the block size so we might have to do more than one TLB lookup.
> +         * We know that in fact for any v8 CPU the page size is at least 4K
> +         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
> +         * 1K as an artefact of legacy v5 subpage support being present in the
> +         * same QEMU executable.
> +         */
> +        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
> +        void *hostaddr[maxidx];

What's the maximum blocksize?  Did you really need dynamic allocation here?

> +        int try, i;
> +
> +        for (try = 0; try < 2; try++) {
> +
> +            for (i = 0; i < maxidx; i++) {
> +                hostaddr[i] = tlb_vaddr_to_host(env,
> +                                                vaddr + TARGET_PAGE_SIZE * i,
> +                                                cpu_mmu_index(env));
> +                if (!hostaddr[i]) {
> +                    break;
> +                }
> +            }
> +            if (i == maxidx) {
> +                /* If it's all in the TLB it's fair game for just writing to;
> +                 * we know we don't need to update dirty status, etc.
> +                 */
> +                for (i = 0; i < maxidx - 1; i++) {
> +                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
> +                }
> +                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
> +                return;
> +            }
> +            /* OK, try a store and see if we can populate the tlb. This
> +             * might cause an exception if the memory isn't writable,
> +             * in which case we will longjmp out of here. We must for
> +             * this purpose use the actual register value passed to us
> +             * so that we get the fault address right.
> +             */
> +            cpu_stb_data(env, vaddr_in, 0);
> +            /* Now we can populate the other TLB entries, if any */
> +            for (i = 0; i < maxidx; i++) {
> +                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
> +                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
> +                    cpu_stb_data(env, va, 0);
> +                }
> +            }

cpu_stb_data doesn't take into account user vs kernel mode accesses.  Maybe
better off using helper_ret_stb_mmu, and passing along GETRA().

As a bonus, you'll have accurate exceptions should the access throw, so you
don't need to force the save of PC before calling the helper.  Which... I don't
see you doing, so perhaps there's a bug here at the moment.



r~

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA
  2014-03-07 14:51   ` Richard Henderson
@ 2014-03-07 15:11     ` Peter Maydell
  2014-03-07 15:25       ` Richard Henderson
  2014-03-07 15:40       ` Richard Henderson
  0 siblings, 2 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-07 15:11 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Claudio Fontana, Alexander Graf, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
	Christoffer Dall

On 7 March 2014 14:51, Richard Henderson <rth@twiddle.net> wrote:
> On 03/06/2014 11:32 AM, Peter Maydell wrote:
>> +/**
>> + * tlb_vaddr_to_host:
>> + * @env: CPUArchState
>> + * @addr: guest virtual address to look up
>> + * @mmu_idx: MMU index to use for lookup
>> + *
>> + * Look up the specified guest virtual index in the TCG softmmu TLB.
>> + * If the TLB contains a host virtual address suitable for direct RAM
>> + * access, then return it. Otherwise (TLB miss, TLB entry is for an
>> + * I/O access, etc) return NULL.
>> + *
>> + * This is the equivalent of the initial fast-path code used by
>> + * TCG backends for guest load and store accesses.
>> + */
>> +static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
>> +                                      int mmu_idx)
>> +{
>> +    int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
>> +    target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
>
> Somewhere I think the function name or at least the block comment should
> indicate that this lookup is for writing, since we hard-code addr_write here.

Doh, yes. I forgot that when I was shifting the code into
a more general function. Is it worth parameterising this for
read vs write lookups?

>> +void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in)
>> +{
>> +    /* Implement DC ZVA, which zeroes a fixed-length block of memory.
>> +     * Note that we do not implement the (architecturally mandated)
>> +     * alignment fault for attempts to use this on Device memory
>> +     * (which matches the usual QEMU behaviour of not implementing either
>> +     * alignment faults or any memory attribute handling).
>> +     */
>> +
>> +    ARMCPU *cpu = arm_env_get_cpu(env);
>> +    uint64_t blocklen = 4 << cpu->dcz_blocksize;
>> +    uint64_t vaddr = vaddr_in & ~(blocklen - 1);
>> +
>> +#ifndef CONFIG_USER_ONLY
>> +    {
>> +        /* Slightly awkwardly, QEMU's TARGET_PAGE_SIZE may be less than
>> +         * the block size so we might have to do more than one TLB lookup.
>> +         * We know that in fact for any v8 CPU the page size is at least 4K
>> +         * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only
>> +         * 1K as an artefact of legacy v5 subpage support being present in the
>> +         * same QEMU executable.
>> +         */
>> +        int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE);
>> +        void *hostaddr[maxidx];
>
> What's the maximum blocksize?  Did you really need dynamic allocation here?

Max blocksize architecturally currently is 2K. Dynamic
allocation seemed cleaner code than hardcoding "this will
always have either 1 or 2 elements", though. (The field
in the "how big is a block?" register would allow more than
2K, since that is encoded as 0b1001 in a 4 bit field.)


>
>> +        int try, i;
>> +
>> +        for (try = 0; try < 2; try++) {
>> +
>> +            for (i = 0; i < maxidx; i++) {
>> +                hostaddr[i] = tlb_vaddr_to_host(env,
>> +                                                vaddr + TARGET_PAGE_SIZE * i,
>> +                                                cpu_mmu_index(env));
>> +                if (!hostaddr[i]) {
>> +                    break;
>> +                }
>> +            }
>> +            if (i == maxidx) {
>> +                /* If it's all in the TLB it's fair game for just writing to;
>> +                 * we know we don't need to update dirty status, etc.
>> +                 */
>> +                for (i = 0; i < maxidx - 1; i++) {
>> +                    memset(hostaddr[i], 0, TARGET_PAGE_SIZE);
>> +                }
>> +                memset(hostaddr[i], 0, blocklen - (i * TARGET_PAGE_SIZE));
>> +                return;
>> +            }
>> +            /* OK, try a store and see if we can populate the tlb. This
>> +             * might cause an exception if the memory isn't writable,
>> +             * in which case we will longjmp out of here. We must for
>> +             * this purpose use the actual register value passed to us
>> +             * so that we get the fault address right.
>> +             */
>> +            cpu_stb_data(env, vaddr_in, 0);
>> +            /* Now we can populate the other TLB entries, if any */
>> +            for (i = 0; i < maxidx; i++) {
>> +                uint64_t va = vaddr + TARGET_PAGE_SIZE * i;
>> +                if (va != (vaddr_in & TARGET_PAGE_MASK)) {
>> +                    cpu_stb_data(env, va, 0);
>> +                }
>> +            }
>
> cpu_stb_data doesn't take into account user vs kernel mode accesses.

...so what does it use for the mmu index?

>  Maybe
> better off using helper_ret_stb_mmu, and passing along GETRA().

OK.

> As a bonus, you'll have accurate exceptions should the access throw, so you
> don't need to force the save of PC before calling the helper.  Which... I don't
> see you doing, so perhaps there's a bug here at the moment.

Mmm. (In system mode we'll save PC as a side effect of having
an accessfn defined for the DC_ZVA reginfo.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA
  2014-03-07 15:11     ` Peter Maydell
@ 2014-03-07 15:25       ` Richard Henderson
  2014-03-07 15:40       ` Richard Henderson
  1 sibling, 0 replies; 58+ messages in thread
From: Richard Henderson @ 2014-03-07 15:25 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Claudio Fontana, Alexander Graf, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
	Christoffer Dall

On 03/07/2014 07:11 AM, Peter Maydell wrote:
>> > cpu_stb_data doesn't take into account user vs kernel mode accesses.
> ...so what does it use for the mmu index?
> 

Oops, read the macro garbage incorrectly.  It does make its way back to
cpu_mmu_index.


r~

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA
  2014-03-07 15:11     ` Peter Maydell
  2014-03-07 15:25       ` Richard Henderson
@ 2014-03-07 15:40       ` Richard Henderson
  1 sibling, 0 replies; 58+ messages in thread
From: Richard Henderson @ 2014-03-07 15:40 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Claudio Fontana, Alexander Graf, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
	Christoffer Dall

On 03/07/2014 07:11 AM, Peter Maydell wrote:
>> > As a bonus, you'll have accurate exceptions should the access throw, so you
>> > don't need to force the save of PC before calling the helper.  Which... I don't
>> > see you doing, so perhaps there's a bug here at the moment.
> Mmm. (In system mode we'll save PC as a side effect of having
> an accessfn defined for the DC_ZVA reginfo.)

Ah, I see it.

I'll note that the GETRA/PC thing can be made to work with any helper.  It's
just a matter of passing down the outermost helper's retaddr to
cpu_restore_state.  C.f. target-alpha's dynamic_excp/arith_excp functions.

So in theory there's no need for the accessfn to require storing the pc first.


r~

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register Peter Maydell
@ 2014-03-17  2:30   ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  2:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement the DAIF system register which is a view of the
> DAIF bits in PSTATE. To avoid needing a readfn, we widen
> the daif field in CPUARMState to uint64_t.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  target-arm/cpu.h    |  2 +-
>  target-arm/helper.c | 20 ++++++++++++++++++++
>  2 files changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 6252ff3..45eb6a2 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -160,7 +160,7 @@ typedef struct CPUARMState {
>      uint32_t GE; /* cpsr[19:16] */
>      uint32_t thumb; /* cpsr[5]. 0 = arm mode, 1 = thumb mode. */
>      uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
> -    uint32_t daif; /* exception masks, in the bits they are in in PSTATE */
> +    uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
>
>      /* System control coprocessor (cp15) */
>      struct {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 3d65bae..f7168c1 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1593,6 +1593,20 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>      vfp_set_fpsr(env, value);
>  }
>
> +static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    if (arm_current_pl(env) == 0 && !(env->cp15.c1_sys & SCTLR_UMA)) {
> +        return CP_ACCESS_TRAP;
> +    }
> +    return CP_ACCESS_OK;
> +}
> +
> +static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                            uint64_t value)
> +{
> +    env->daif = value & PSTATE_DAIF;
> +}
> +
>  static CPAccessResult aa64_cacheop_access(CPUARMState *env,
>                                            const ARMCPRegInfo *ri)
>  {
> @@ -1636,6 +1650,12 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
>      { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>        .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>        .access = PL0_RW, .type = ARM_CP_NZCV },
> +    { .name = "DAIF", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 2,
> +      .type = ARM_CP_NO_MIGRATE,
> +      .access = PL0_RW, .accessfn = aa64_daif_access,
> +      .fieldoffset = offsetof(CPUARMState, daif),
> +      .writefn = aa64_daif_write, .resetfn = arm_cp_reset_ignore },
>      { .name = "FPCR", .state = ARM_CP_STATE_AA64,
>        .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>        .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions Peter Maydell
@ 2014-03-17  2:53   ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  2:53 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> For AArch32 exceptions, the only information provided about
> the cause of an exception is the individual exception type (data
> abort, undef, etc), which we store in env->exception_index. For
> AArch64, the CPU provides much more detail about the cause of
> the exception, which can be found in the syndrome register.
> Create a set of fields in CPUARMState which must be filled in
> whenever an exception is raised, so that exception entry can
> correctly fill in the syndrome register for the guest.
> This includes the information which in AArch32 appears in
> the DFAR and IFAR (fault address registers) and the DFSR
> and IFSR (fault status registers) for data aborts and
> prefetch aborts, since if we end up taking the MMU fault
> to AArch64 rather than AArch32 this will need to end up
> in different system registers.
>
> This patch does a refactoring which moves the setting of the
> AArch32 DFAR/DFSR/IFAR/IFSR from the point where the exception
> is raised to the point where it is taken. (This is no change
> for cores with an MMU, retains the existing clearly incorrect
> behaviour for ARM946 of trashing the MP access permissions
> registers which share the c5_data and c5_insn state fields,
> and has no effect for v7M because we don't implement its
> MPU fault status or address registers.)
>
> As a side effect of the cleanup we fix a bug in the AArch64
> linux-user mode code where we were passing a 64 bit fault
> address through the 32 bit c6_data/c6_insn fields: it now
> goes via the always-64-bit exception.vaddress.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  linux-user/main.c    | 56 ++++++++++++++++++++++------------------------------
>  target-arm/cpu.h     | 15 ++++++++++++++
>  target-arm/helper.c  | 23 ++++++++++++---------
>  target-arm/machine.c |  3 +++
>  4 files changed, 56 insertions(+), 41 deletions(-)
>
> diff --git a/linux-user/main.c b/linux-user/main.c
> index 9192977..a17ee47 100644
> --- a/linux-user/main.c
> +++ b/linux-user/main.c
> @@ -483,17 +483,17 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
>      addr = env->regs[2];
>
>      if (get_user_u64(oldval, env->regs[0])) {
> -        env->cp15.c6_data = env->regs[0];
> +        env->exception.vaddress = env->regs[0];
>          goto segv;
>      };
>
>      if (get_user_u64(newval, env->regs[1])) {
> -        env->cp15.c6_data = env->regs[1];
> +        env->exception.vaddress = env->regs[1];
>          goto segv;
>      };
>
>      if (get_user_u64(val, addr)) {
> -        env->cp15.c6_data = addr;
> +        env->exception.vaddress = addr;
>          goto segv;
>      }
>
> @@ -501,7 +501,7 @@ static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
>          val = newval;
>
>          if (put_user_u64(val, addr)) {
> -            env->cp15.c6_data = addr;
> +            env->exception.vaddress = addr;
>              goto segv;
>          };
>
> @@ -523,7 +523,7 @@ segv:
>      info.si_errno = 0;
>      /* XXX: check env->error_code */
>      info.si_code = TARGET_SEGV_MAPERR;
> -    info._sifields._sigfault._addr = env->cp15.c6_data;
> +    info._sifields._sigfault._addr = env->exception.vaddress;
>      queue_signal(env, info.si_signo, &info);
>
>      end_exclusive();
> @@ -620,14 +620,14 @@ static int do_strex(CPUARMState *env)
>          abort();
>      }
>      if (segv) {
> -        env->cp15.c6_data = addr;
> +        env->exception.vaddress = addr;
>          goto done;
>      }
>      if (size == 3) {
>          uint32_t valhi;
>          segv = get_user_u32(valhi, addr + 4);
>          if (segv) {
> -            env->cp15.c6_data = addr + 4;
> +            env->exception.vaddress = addr + 4;
>              goto done;
>          }
>          val = deposit64(val, 32, 32, valhi);
> @@ -650,14 +650,14 @@ static int do_strex(CPUARMState *env)
>          break;
>      }
>      if (segv) {
> -        env->cp15.c6_data = addr;
> +        env->exception.vaddress = addr;
>          goto done;
>      }
>      if (size == 3) {
>          val = env->regs[(env->exclusive_info >> 12) & 0xf];
>          segv = put_user_u32(val, addr + 4);
>          if (segv) {
> -            env->cp15.c6_data = addr + 4;
> +            env->exception.vaddress = addr + 4;
>              goto done;
>          }
>      }
> @@ -832,12 +832,14 @@ void cpu_loop(CPUARMState *env)
>          case EXCP_INTERRUPT:
>              /* just indicate that signals should be handled asap */
>              break;
> +        case EXCP_STREX:
> +            if (!do_strex(env)) {
> +                break;
> +            }
> +            /* fall through for segv */
>          case EXCP_PREFETCH_ABORT:
> -            addr = env->cp15.c6_insn;
> -            goto do_segv;
>          case EXCP_DATA_ABORT:
> -            addr = env->cp15.c6_data;
> -        do_segv:
> +            addr = env->exception.vaddress;
>              {
>                  info.si_signo = SIGSEGV;
>                  info.si_errno = 0;
> @@ -865,12 +867,6 @@ void cpu_loop(CPUARMState *env)
>              if (do_kernel_trap(env))
>                goto error;
>              break;
> -        case EXCP_STREX:
> -            if (do_strex(env)) {
> -                addr = env->cp15.c6_data;
> -                goto do_segv;
> -            }
> -            break;
>          default:
>          error:
>              fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
> @@ -933,7 +929,7 @@ static int do_strex_a64(CPUARMState *env)
>          abort();
>      }
>      if (segv) {
> -        env->cp15.c6_data = addr;
> +        env->exception.vaddress = addr;
>          goto error;
>      }
>      if (val != env->exclusive_val) {
> @@ -946,7 +942,7 @@ static int do_strex_a64(CPUARMState *env)
>              segv = get_user_u64(val, addr + 8);
>          }
>          if (segv) {
> -            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
> +            env->exception.vaddress = addr + (size == 2 ? 4 : 8);
>              goto error;
>          }
>          if (val != env->exclusive_high) {
> @@ -981,7 +977,7 @@ static int do_strex_a64(CPUARMState *env)
>              segv = put_user_u64(val, addr + 8);
>          }
>          if (segv) {
> -            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
> +            env->exception.vaddress = addr + (size == 2 ? 4 : 8);
>              goto error;
>          }
>      }
> @@ -1037,12 +1033,14 @@ void cpu_loop(CPUARMState *env)
>              info._sifields._sigfault._addr = env->pc;
>              queue_signal(env, info.si_signo, &info);
>              break;
> +        case EXCP_STREX:
> +            if (!do_strex_a64(env)) {
> +                break;
> +            }
> +            /* fall through for segv */
>          case EXCP_PREFETCH_ABORT:
> -            addr = env->cp15.c6_insn;
> -            goto do_segv;
>          case EXCP_DATA_ABORT:
> -            addr = env->cp15.c6_data;
> -        do_segv:
> +            addr = env->exception.vaddress;
>              info.si_signo = SIGSEGV;
>              info.si_errno = 0;
>              /* XXX: check env->error_code */
> @@ -1060,12 +1058,6 @@ void cpu_loop(CPUARMState *env)
>                  queue_signal(env, info.si_signo, &info);
>              }
>              break;
> -        case EXCP_STREX:
> -            if (do_strex_a64(env)) {
> -                addr = env->cp15.c6_data;
> -                goto do_segv;
> -            }
> -            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 45eb6a2..9982e47 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -229,6 +229,21 @@ typedef struct CPUARMState {
>          int pending_exception;
>      } v7m;
>
> +    /* Information associated with an exception about to be taken:
> +     * code which raises an exception must set env->exception_index and
> +     * the relevant parts of this structure; the cpu_do_interrupt function
> +     * will then set the guest-visible registers as part of the exception
> +     * entry process.
> +     */
> +    struct {
> +        uint32_t syndrome; /* AArch64 format syndrome register */
> +        uint32_t fsr; /* AArch32 format fault status register info */
> +        uint64_t vaddress; /* virtual addr associated with exception, if any */
> +        /* If we implement EL2 we will also need to store information
> +         * about the intermediate physical address for stage 2 faults.
> +         */
> +    } exception;
> +
>      /* Thumb-2 EE state.  */
>      uint32_t teecr;
>      uint32_t teehbr;
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index f7168c1..2fa01ae 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2610,12 +2610,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
>  int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
>                                int mmu_idx)
>  {
> +    env->exception.vaddress = address;
>      if (rw == 2) {
>          env->exception_index = EXCP_PREFETCH_ABORT;
> -        env->cp15.c6_insn = address;
>      } else {
>          env->exception_index = EXCP_DATA_ABORT;
> -        env->cp15.c6_data = address;
>      }
>      return 1;
>  }
> @@ -2820,6 +2819,9 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
>          return;
>      case EXCP_PREFETCH_ABORT:
>      case EXCP_DATA_ABORT:
> +        /* TODO: if we implemented the MPU registers, this is where we
> +         * should set the MMFAR, etc from exception.fsr and exception.vaddress.
> +         */
>          armv7m_nvic_set_pending(env->nvic, ARMV7M_EXCP_MEM);
>          return;
>      case EXCP_BKPT:
> @@ -2934,9 +2936,11 @@ void arm_cpu_do_interrupt(CPUState *cs)
>                  return;
>              }
>          }
> -        env->cp15.c5_insn = 2;
> +        env->exception.fsr = 2;
>          /* Fall through to prefetch abort.  */
>      case EXCP_PREFETCH_ABORT:
> +        env->cp15.c5_insn = env->exception.fsr;
> +        env->cp15.c6_insn = env->exception.vaddress;
>          qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
>                        env->cp15.c5_insn, env->cp15.c6_insn);
>          new_mode = ARM_CPU_MODE_ABT;
> @@ -2945,6 +2949,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
>          offset = 4;
>          break;
>      case EXCP_DATA_ABORT:
> +        env->cp15.c5_data = env->exception.fsr;
> +        env->cp15.c6_data = env->exception.vaddress;
>          qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
>                        env->cp15.c5_data, env->cp15.c6_data);
>          new_mode = ARM_CPU_MODE_ABT;
> @@ -3593,16 +3599,15 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
>      }
>
>      if (access_type == 2) {
> -        env->cp15.c5_insn = ret;
> -        env->cp15.c6_insn = address;
>          env->exception_index = EXCP_PREFETCH_ABORT;
>      } else {
> -        env->cp15.c5_data = ret;
> -        if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6))
> -            env->cp15.c5_data |= (1 << 11);
> -        env->cp15.c6_data = address;
> +        if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) {
> +            ret |= (1 << 11);
> +        }
>          env->exception_index = EXCP_DATA_ABORT;
>      }
> +    env->exception.vaddress = address;
> +    env->exception.fsr = ret;
>      return 1;
>  }
>
> diff --git a/target-arm/machine.c b/target-arm/machine.c
> index 8f9e7d4..fc8825e 100644
> --- a/target-arm/machine.c
> +++ b/target-arm/machine.c
> @@ -257,6 +257,9 @@ const VMStateDescription vmstate_arm_cpu = {
>          VMSTATE_UINT64(env.exclusive_val, ARMCPU),
>          VMSTATE_UINT64(env.exclusive_high, ARMCPU),
>          VMSTATE_UINT64(env.features, ARMCPU),
> +        VMSTATE_UINT32(env.exception.syndrome, ARMCPU),
> +        VMSTATE_UINT32(env.exception.fsr, ARMCPU),
> +        VMSTATE_UINT64(env.exception.vaddress, ARMCPU),
>          VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
>          VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
>          VMSTATE_END_OF_LIST()
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps Peter Maydell
@ 2014-03-17  3:05   ` Peter Crosthwaite
  2014-03-17 12:32     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  3:05 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> For exceptions taken to AArch64, if a coprocessor/system register
> access fails due to a trap or enable bit then the syndrome information
> must include details of the failing instruction (crn/crm/opc1/opc2
> fields, etc). Make the decoder construct the syndrome information
> at translate time so it can be passed at runtime to the access-check
> helper function and used as required.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/helper.h        |   2 +-
>  target-arm/internals.h     | 128 +++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/op_helper.c     |   8 +--
>  target-arm/translate-a64.c |   8 ++-
>  target-arm/translate.c     |  45 +++++++++++++++-
>  5 files changed, 184 insertions(+), 7 deletions(-)
>
> diff --git a/target-arm/helper.h b/target-arm/helper.h
> index 276f3a9..7f23cb8 100644
> --- a/target-arm/helper.h
> +++ b/target-arm/helper.h
> @@ -57,7 +57,7 @@ DEF_HELPER_1(cpsr_read, i32, env)
>  DEF_HELPER_3(v7m_msr, void, env, i32, i32)
>  DEF_HELPER_2(v7m_mrs, i32, env, i32)
>
> -DEF_HELPER_2(access_check_cp_reg, void, env, ptr)
> +DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32)
>  DEF_HELPER_3(set_cp_reg, void, env, ptr, i32)
>  DEF_HELPER_2(get_cp_reg, i32, env, ptr)
>  DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64)
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index a38a57f..2c0db20 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -46,4 +46,132 @@ enum arm_fprounding {
>
>  int arm_rmode_to_sf(int rmode);
>
> +/* Valid Syndrome Register EC field values */
> +enum arm_exception_class {
> +    EC_UNCATEGORIZED = 0,
> +    EC_WFX_TRAP = 1,
> +    EC_CP15RTTRAP = 3,
> +    EC_CP15RRTTRAP = 4,
> +    EC_CP14RTTRAP = 5,
> +    EC_CP14DTTRAP = 6,
> +    EC_ADVSIMDFPACCESSTRAP = 7,
> +    EC_FPIDTRAP = 8,
> +    EC_CP14RRTTRAP = 0xc,
> +    EC_ILLEGALSTATE = 0xe,
> +    EC_AA32_SVC = 0x11,
> +    EC_AA32_HVC = 0x12,
> +    EC_AA32_SMC = 0x13,
> +    EC_AA64_SVC = 0x15,
> +    EC_AA64_HVC = 0x16,
> +    EC_AA64_SMC = 0x17,
> +    EC_SYSTEMREGISTERTRAP = 0x18,
> +    EC_INSNABORT = 0x20,
> +    EC_INSNABORT_SAME_EL = 0x21,
> +    EC_PCALIGNMENT = 0x22,
> +    EC_DATAABORT = 0x24,
> +    EC_DATAABORT_SAME_EL = 0x25,
> +    EC_SPALIGNMENT = 0x26,
> +    EC_AA32_FPTRAP = 0x28,
> +    EC_AA64_FPTRAP = 0x2c,
> +    EC_SERROR = 0x2f,
> +    EC_BREAKPOINT = 0x30,
> +    EC_BREAKPOINT_SAME_EL = 0x31,
> +    EC_SOFTWARESTEP = 0x32,
> +    EC_SOFTWARESTEP_SAME_EL = 0x33,
> +    EC_WATCHPOINT = 0x34,
> +    EC_WATCHPOINT_SAME_EL = 0x35,
> +    EC_AA32_BKPT = 0x38,
> +    EC_VECTORCATCH = 0x3a,
> +    EC_AA64_BKPT = 0x3c,
> +};
> +

Can we space out the constants to a consistent tab stop for readability?

> +#define ARM_EL_EC_SHIFT 26
> +#define ARM_EL_IL_SHIFT 25
> +#define ARM_EL_IL (1 << ARM_EL_IL_SHIFT)
> +
> +/* Utility functions for constructing various kinds of syndrome value.
> + * Note that in general we follow the AArch64 syndrome values; in a
> + * few cases the value in HSR for exceptions taken to AArch32 Hyp
> + * mode differs slightly, so if we ever implemented Hyp mode then the
> + * syndrome value would need some massaging on exception entry.
> + * (One example of this is that AArch64 defaults to IL bit set for
> + * exceptions which don't specifically indicate information about the
> + * trapping instruction, whereas AArch32 defaults to IL bit clear.)
> + */
> +static inline uint32_t syn_uncategorized(void)
> +{
> +    return (EC_UNCATEGORIZED << ARM_EL_EC_SHIFT) | ARM_EL_IL;
> +}
> +
> +static inline uint32_t syn_aa64_svc(uint32_t imm16)
> +{
> +    return (EC_AA64_SVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
> +}
> +
> +static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb)
> +{
> +    return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
> +        | (is_thumb ? 0 : ARM_EL_IL);
> +}
> +
> +static inline uint32_t syn_aa64_bkpt(uint32_t imm16)
> +{
> +    return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff);
> +}
> +
> +static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_thumb)
> +{
> +    return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff)
> +        | (is_thumb ? 0 : ARM_EL_IL);
> +}
> +
> +static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2,
> +                                           int crn, int crm, int rt,
> +                                           int isread)
> +{
> +    return (EC_SYSTEMREGISTERTRAP << ARM_EL_EC_SHIFT) | ARM_EL_IL
> +        | (op0 << 20) | (op2 << 17) | (op1 << 14) | (crn << 10) | (rt << 5)
> +        | (crm << 1) | isread;
> +}
> +
> +static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2,
> +                                        int crn, int crm, int rt, int isread,
> +                                        bool is_thumb)
> +{
> +    return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT)
> +        | (is_thumb ? 0 : ARM_EL_IL)
> +        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
> +        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
> +}
> +
> +static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2,
> +                                        int crn, int crm, int rt, int isread,
> +                                        bool is_thumb)
> +{
> +    return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT)
> +        | (is_thumb ? 0 : ARM_EL_IL)
> +        | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14)
> +        | (crn << 10) | (rt << 5) | (crm << 1) | isread;
> +}
> +
> +static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm,
> +                                         int rt, int rt2, int isread,
> +                                         bool is_thumb)
> +{
> +    return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT)
> +        | (is_thumb ? 0 : ARM_EL_IL)
> +        | (cv << 24) | (cond << 20) | (opc1 << 16)
> +        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
> +}
> +
> +static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
> +                                         int rt, int rt2, int isread,
> +                                         bool is_thumb)
> +{
> +    return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT)
> +        | (is_thumb ? 0 : ARM_EL_IL)
> +        | (cv << 24) | (cond << 20) | (opc1 << 16)
> +        | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
> +}
> +
>  #endif
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index 1458cd3..bef2cf6 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -274,17 +274,17 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
>      }
>  }
>
> -void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
> +void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
>  {
>      const ARMCPRegInfo *ri = rip;
>      switch (ri->accessfn(env, ri)) {
>      case CP_ACCESS_OK:
>          return;
>      case CP_ACCESS_TRAP:
> +        env->exception.syndrome = syndrome;

Can TCG just deposit this directly and unconditionally straight to the
env to avoid the extra syndrome arg?

Regards,
Peter

> +        break;
>      case CP_ACCESS_TRAP_UNCATEGORIZED:
> -        /* These cases will eventually need to generate different
> -         * syndrome information.
> -         */
> +        env->exception.syndrome = syn_uncategorized();
>          break;
>      default:
>          g_assert_not_reached();
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 156fda2..a4f9258 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -1239,10 +1239,16 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>           * runtime; this may result in an exception.
>           */
>          TCGv_ptr tmpptr;
> +        TCGv_i32 tcg_syn;
> +        uint32_t syndrome;
> +
>          gen_a64_set_pc_im(s->pc - 4);
>          tmpptr = tcg_const_ptr(ri);
> -        gen_helper_access_check_cp_reg(cpu_env, tmpptr);
> +        syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread);
> +        tcg_syn = tcg_const_i32(syndrome);
> +        gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
>          tcg_temp_free_ptr(tmpptr);
> +        tcg_temp_free_i32(tcg_syn);
>      }
>
>      /* Handle special cases first */
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 4a53313..9a81222 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6843,10 +6843,53 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>               * runtime; this may result in an exception.
>               */
>              TCGv_ptr tmpptr;
> +            TCGv_i32 tcg_syn;
> +            uint32_t syndrome;
> +
> +            /* Note that since we are an implementation which takes an
> +             * exception on a trapped conditional instruction only if the
> +             * instruction passes its condition code check, we can take
> +             * advantage of the clause in the ARM ARM that allows us to set
> +             * the COND field in the instruction to 0xE in all cases.
> +             * We could fish the actual condition out of the insn (ARM)
> +             * or the condexec bits (Thumb) but it isn't necessary.
> +             */
> +            switch (cpnum) {
> +            case 14:
> +                if (is64) {
> +                    syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
> +                                                 isread, s->thumb);
> +                } else {
> +                    syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm,
> +                                                rt, isread, s->thumb);
> +                }
> +                break;
> +            case 15:
> +                if (is64) {
> +                    syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2,
> +                                                 isread, s->thumb);
> +                } else {
> +                    syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm,
> +                                                rt, isread, s->thumb);
> +                }
> +                break;
> +            default:
> +                /* ARMv8 defines that only coprocessors 14 and 15 exist,
> +                 * so this can only happen if this is an ARMv7 or earlier CPU,
> +                 * in which case the syndrome information won't actually be
> +                 * guest visible.
> +                 */
> +                assert(!arm_feature(env, ARM_FEATURE_V8));
> +                syndrome = syn_uncategorized();
> +                break;
> +            }
> +
>              gen_set_pc_im(s, s->pc);
>              tmpptr = tcg_const_ptr(ri);
> -            gen_helper_access_check_cp_reg(cpu_env, tmpptr);
> +            tcg_syn = tcg_const_i32(syndrome);
> +            gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn);
>              tcg_temp_free_ptr(tmpptr);
> +            tcg_temp_free_i32(tcg_syn);
>          }
>
>          /* Handle special cases first */
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information Peter Maydell
@ 2014-03-17  3:19   ` Peter Crosthwaite
  2014-03-17 12:40     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  3:19 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Add new helpers exception_with_syndrome (for generating an exception
> with syndrome information) and exception_uncategorized (for generating
> an exception with "Unknown or Uncategorized Reason", which have a syndrome
> register value of zero), and use them to generate the correct syndrome
> information for exceptions which are raised directly from generated code.
>
> This patch includes moving the A32/T32 gen_exception_insn functions
> further up in the source file; they will be needed for "VFP/Neon disabled"
> exception generation later.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/helper.h        |   3 +-
>  target-arm/internals.h     |  14 ++++++
>  target-arm/op_helper.c     |  19 ++++++++-
>  target-arm/translate-a64.c |  49 +++++++++++++++------
>  target-arm/translate.c     | 103 ++++++++++++++++++++++++++++-----------------
>  target-arm/translate.h     |   4 ++
>  6 files changed, 138 insertions(+), 54 deletions(-)
>
> diff --git a/target-arm/helper.h b/target-arm/helper.h
> index 7f23cb8..2729ea5 100644
> --- a/target-arm/helper.h
> +++ b/target-arm/helper.h
> @@ -48,7 +48,8 @@ DEF_HELPER_FLAGS_2(usad8, TCG_CALL_NO_RWG_SE, i32, i32, i32)
>
>  DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
>                     i32, i32, i32, i32)
> -DEF_HELPER_2(exception, void, env, i32)
> +DEF_HELPER_2(exception_internal, void, env, i32)
> +DEF_HELPER_3(exception_with_syndrome, void, env, i32, i32)
>  DEF_HELPER_1(wfi, void, env)
>
>  DEF_HELPER_3(cpsr_write, void, env, i32, i32)
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index 2c0db20..9bec4e1 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -25,6 +25,20 @@
>  #ifndef TARGET_ARM_INTERNALS_H
>  #define TARGET_ARM_INTERNALS_H
>
> +static inline bool excp_is_internal(int excp)
> +{
> +    /* Return true if this exception number represents a QEMU-internal
> +     * exception that will not be passed to the guest.
> +     */
> +    return excp == EXCP_INTERRUPT
> +        || excp == EXCP_HLT
> +        || excp == EXCP_DEBUG
> +        || excp == EXCP_HALTED
> +        || excp == EXCP_EXCEPTION_EXIT
> +        || excp == EXCP_KERNEL_TRAP
> +        || excp == EXCP_STREX;
> +}
> +
>  /* Scale factor for generic timers, ie number of ns per tick.
>   * This gives a 62.5MHz timer.
>   */
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index bef2cf6..b1db672 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -226,9 +226,26 @@ void HELPER(wfi)(CPUARMState *env)
>      cpu_loop_exit(env);
>  }
>
> -void HELPER(exception)(CPUARMState *env, uint32_t excp)
> +/* Raise an internal-to-QEMU exception. This is limited to only
> + * those EXCP values which are special cases for QEMU to interrupt
> + * execution and not to be used for exceptions which are passed to
> + * the guest (those must all have syndrome information and thus should
> + * use exception_with_syndrome).
> + */
> +void HELPER(exception_internal)(CPUARMState *env, uint32_t excp)
> +{
> +    assert(excp_is_internal(excp));
> +    env->exception_index = excp;
> +    cpu_loop_exit(env);
> +}
> +
> +/* Raise an exception with the specified syndrome register value */
> +void HELPER(exception_with_syndrome)(CPUARMState *env, uint32_t excp,
> +                                     uint32_t syndrome)
>  {
> +    assert(!excp_is_internal(excp));
>      env->exception_index = excp;
> +    env->exception.syndrome = syndrome;
>      cpu_loop_exit(env);
>  }
>
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index a4f9258..b32068e 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -173,18 +173,37 @@ void gen_a64_set_pc_im(uint64_t val)
>      tcg_gen_movi_i64(cpu_pc, val);
>  }
>
> -static void gen_exception(int excp)
> +static void gen_exception_internal(int excp)
>  {
> -    TCGv_i32 tmp = tcg_temp_new_i32();
> -    tcg_gen_movi_i32(tmp, excp);
> -    gen_helper_exception(cpu_env, tmp);
> -    tcg_temp_free_i32(tmp);
> +    TCGv_i32 tcg_excp = tcg_const_i32(excp);
> +
> +    assert(excp_is_internal(excp));
> +    gen_helper_exception_internal(cpu_env, tcg_excp);
> +    tcg_temp_free_i32(tcg_excp);
> +}
> +
> +static void gen_exception(int excp, uint32_t syndrome)
> +{
> +    TCGv_i32 tcg_excp = tcg_const_i32(excp);
> +    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
> +
> +    gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
> +    tcg_temp_free_i32(tcg_syn);
> +    tcg_temp_free_i32(tcg_excp);
> +}
> +
> +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
> +{
> +    gen_a64_set_pc_im(s->pc - offset);
> +    gen_exception_internal(excp);
> +    s->is_jmp = DISAS_EXC;
>  }
>
> -static void gen_exception_insn(DisasContext *s, int offset, int excp)
> +static void gen_exception_insn(DisasContext *s, int offset, int excp,
> +                               uint32_t syndrome)
>  {
>      gen_a64_set_pc_im(s->pc - offset);
> -    gen_exception(excp);
> +    gen_exception(excp, syndrome);
>      s->is_jmp = DISAS_EXC;
>  }
>
> @@ -216,7 +235,7 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
>      } else {
>          gen_a64_set_pc_im(dest);
>          if (s->singlestep_enabled) {
> -            gen_exception(EXCP_DEBUG);
> +            gen_exception_internal(EXCP_DEBUG);
>          }
>          tcg_gen_exit_tb(0);
>          s->is_jmp = DISAS_JUMP;
> @@ -225,7 +244,8 @@ static inline void gen_goto_tb(DisasContext *s, int n, uint64_t dest)
>
>  static void unallocated_encoding(DisasContext *s)
>  {
> -    gen_exception_insn(s, 4, EXCP_UDEF);
> +    /* Unallocated and reserved encodings are uncategorized */
> +    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
>  }
>
>  #define unsupported_encoding(s, insn)                                    \
> @@ -1370,6 +1390,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
>  {
>      int opc = extract32(insn, 21, 3);
>      int op2_ll = extract32(insn, 0, 5);
> +    int imm16 = extract32(insn, 5, 16);
>
>      switch (opc) {
>      case 0:
> @@ -1380,7 +1401,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
>              unallocated_encoding(s);
>              break;
>          }
> -        gen_exception_insn(s, 0, EXCP_SWI);
> +        gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16));
>          break;
>      case 1:
>          if (op2_ll != 0) {
> @@ -1388,7 +1409,7 @@ static void disas_exc(DisasContext *s, uint32_t insn)
>              break;
>          }
>          /* BRK */
> -        gen_exception_insn(s, 0, EXCP_BKPT);
> +        gen_exception_insn(s, 0, EXCP_BKPT, syn_aa64_bkpt(imm16));
>          break;
>      case 2:
>          if (op2_ll != 0) {
> @@ -1537,7 +1558,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
>      tcg_gen_mov_i64(cpu_exclusive_test, addr);
>      tcg_gen_movi_i32(cpu_exclusive_info,
>                       size | is_pair << 2 | (rd << 4) | (rt << 9) | (rt2 << 14));
> -    gen_exception_insn(s, 4, EXCP_STREX);
> +    gen_exception_internal_insn(s, 4, EXCP_STREX);
>  }
>  #else
>  static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> @@ -9108,7 +9129,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
>          if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>              QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
>                  if (bp->pc == dc->pc) {
> -                    gen_exception_insn(dc, 0, EXCP_DEBUG);
> +                    gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
>                      /* Advance PC so that clearing the breakpoint will
>                         invalidate this TB.  */
>                      dc->pc += 2;
> @@ -9171,7 +9192,7 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
>          if (dc->is_jmp != DISAS_JUMP) {
>              gen_a64_set_pc_im(dc->pc);
>          }
> -        gen_exception(EXCP_DEBUG);
> +        gen_exception_internal(EXCP_DEBUG);
>      } else {
>          switch (dc->is_jmp) {
>          case DISAS_NEXT:
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 9a81222..094be07 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -183,12 +183,23 @@ static inline void gen_set_cpsr(TCGv_i32 var, uint32_t mask)
>  /* Set NZCV flags from the high 4 bits of var.  */
>  #define gen_set_nzcv(var) gen_set_cpsr(var, CPSR_NZCV)
>
> -static void gen_exception(int excp)
> +static void gen_exception_internal(int excp)
>  {
> -    TCGv_i32 tmp = tcg_temp_new_i32();
> -    tcg_gen_movi_i32(tmp, excp);
> -    gen_helper_exception(cpu_env, tmp);
> -    tcg_temp_free_i32(tmp);
> +    TCGv_i32 tcg_excp = tcg_const_i32(excp);
> +
> +    assert(excp_is_internal(excp));
> +    gen_helper_exception_internal(cpu_env, tcg_excp);
> +    tcg_temp_free_i32(tcg_excp);
> +}
> +

AFAICT this is identical to gen_exception_internal in translate-a64.c.
Can they be de-static'd and prototyped in internals.h?

> +static void gen_exception(int excp, uint32_t syndrome)
> +{
> +    TCGv_i32 tcg_excp = tcg_const_i32(excp);
> +    TCGv_i32 tcg_syn = tcg_const_i32(syndrome);
> +
> +    gen_helper_exception_with_syndrome(cpu_env, tcg_excp, tcg_syn);
> +    tcg_temp_free_i32(tcg_syn);
> +    tcg_temp_free_i32(tcg_excp);
>  }
>

And here.

Otherwise

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

(I haven't gone line-line checking all arguments against TRM, but the
schema and framework is good).

Regards,
Peter

>  static void gen_smul_dual(TCGv_i32 a, TCGv_i32 b)
> @@ -900,6 +911,33 @@ static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
>      tcg_gen_movi_i32(cpu_R[15], val);
>  }
>
> +static inline void
> +gen_set_condexec (DisasContext *s)
> +{
> +    if (s->condexec_mask) {
> +        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
> +        TCGv_i32 tmp = tcg_temp_new_i32();
> +        tcg_gen_movi_i32(tmp, val);
> +        store_cpu_field(tmp, condexec_bits);
> +    }
> +}
> +
> +static void gen_exception_internal_insn(DisasContext *s, int offset, int excp)
> +{
> +    gen_set_condexec(s);
> +    gen_set_pc_im(s, s->pc - offset);
> +    gen_exception_internal(excp);
> +    s->is_jmp = DISAS_JUMP;
> +}
> +
> +static void gen_exception_insn(DisasContext *s, int offset, int excp, int syn)
> +{
> +    gen_set_condexec(s);
> +    gen_set_pc_im(s, s->pc - offset);
> +    gen_exception(excp, syn);
> +    s->is_jmp = DISAS_JUMP;
> +}
> +
>  /* Force a TB lookup after an instruction that changes the CPU state.  */
>  static inline void gen_lookup_tb(DisasContext *s)
>  {
> @@ -3913,25 +3951,6 @@ static void gen_rfe(DisasContext *s, TCGv_i32 pc, TCGv_i32 cpsr)
>      s->is_jmp = DISAS_UPDATE;
>  }
>
> -static inline void
> -gen_set_condexec (DisasContext *s)
> -{
> -    if (s->condexec_mask) {
> -        uint32_t val = (s->condexec_cond << 4) | (s->condexec_mask >> 1);
> -        TCGv_i32 tmp = tcg_temp_new_i32();
> -        tcg_gen_movi_i32(tmp, val);
> -        store_cpu_field(tmp, condexec_bits);
> -    }
> -}
> -
> -static void gen_exception_insn(DisasContext *s, int offset, int excp)
> -{
> -    gen_set_condexec(s);
> -    gen_set_pc_im(s, s->pc - offset);
> -    gen_exception(excp);
> -    s->is_jmp = DISAS_JUMP;
> -}
> -
>  static void gen_nop_hint(DisasContext *s, int val)
>  {
>      switch (val) {
> @@ -7141,7 +7160,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
>      tcg_gen_extu_i32_i64(cpu_exclusive_test, addr);
>      tcg_gen_movi_i32(cpu_exclusive_info,
>                       size | (rd << 4) | (rt << 8) | (rt2 << 12));
> -    gen_exception_insn(s, 4, EXCP_STREX);
> +    gen_exception_internal_insn(s, 4, EXCP_STREX);
>  }
>  #else
>  static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
> @@ -7651,6 +7670,8 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
>              store_reg(s, rd, tmp);
>              break;
>          case 7:
> +        {
> +            int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << 4);
>              /* SMC instruction (op1 == 3)
>                 and undefined instructions (op1 == 0 || op1 == 2)
>                 will trap */
> @@ -7659,8 +7680,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
>              }
>              /* bkpt */
>              ARCH(5);
> -            gen_exception_insn(s, 4, EXCP_BKPT);
> +            gen_exception_insn(s, 4, EXCP_BKPT, syn_aa32_bkpt(imm16, false));
>              break;
> +        }
>          case 0x8: /* signed multiply */
>          case 0xa:
>          case 0xc:
> @@ -8667,11 +8689,12 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s)
>          case 0xf:
>              /* swi */
>              gen_set_pc_im(s, s->pc);
> +            s->svc_imm = extract32(insn, 0, 24);
>              s->is_jmp = DISAS_SWI;
>              break;
>          default:
>          illegal_op:
> -            gen_exception_insn(s, 4, EXCP_UDEF);
> +            gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
>              break;
>          }
>      }
> @@ -10482,9 +10505,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>              break;
>
>          case 0xe: /* bkpt */
> +        {
> +            int imm8 = extract32(insn, 0, 8);
>              ARCH(5);
> -            gen_exception_insn(s, 2, EXCP_BKPT);
> +            gen_exception_insn(s, 2, EXCP_BKPT, syn_aa32_bkpt(imm8, true));
>              break;
> +        }
>
>          case 0xa: /* rev */
>              ARCH(6);
> @@ -10601,6 +10627,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>          if (cond == 0xf) {
>              /* swi */
>              gen_set_pc_im(s, s->pc);
> +            s->svc_imm = extract32(insn, 0, 8);
>              s->is_jmp = DISAS_SWI;
>              break;
>          }
> @@ -10636,11 +10663,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
>      }
>      return;
>  undef32:
> -    gen_exception_insn(s, 4, EXCP_UDEF);
> +    gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized());
>      return;
>  illegal_op:
>  undef:
> -    gen_exception_insn(s, 2, EXCP_UDEF);
> +    gen_exception_insn(s, 2, EXCP_UDEF, syn_uncategorized());
>  }
>
>  /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
> @@ -10761,7 +10788,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>          if (dc->pc >= 0xffff0000) {
>              /* We always get here via a jump, so know we are not in a
>                 conditional execution block.  */
> -            gen_exception(EXCP_KERNEL_TRAP);
> +            gen_exception_internal(EXCP_KERNEL_TRAP);
>              dc->is_jmp = DISAS_UPDATE;
>              break;
>          }
> @@ -10769,7 +10796,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>          if (dc->pc >= 0xfffffff0 && IS_M(env)) {
>              /* We always get here via a jump, so know we are not in a
>                 conditional execution block.  */
> -            gen_exception(EXCP_EXCEPTION_EXIT);
> +            gen_exception_internal(EXCP_EXCEPTION_EXIT);
>              dc->is_jmp = DISAS_UPDATE;
>              break;
>          }
> @@ -10778,7 +10805,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>          if (unlikely(!QTAILQ_EMPTY(&env->breakpoints))) {
>              QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
>                  if (bp->pc == dc->pc) {
> -                    gen_exception_insn(dc, 0, EXCP_DEBUG);
> +                    gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
>                      /* Advance PC so that clearing the breakpoint will
>                         invalidate this TB.  */
>                      dc->pc += 2;
> @@ -10858,9 +10885,9 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>          if (dc->condjmp) {
>              gen_set_condexec(dc);
>              if (dc->is_jmp == DISAS_SWI) {
> -                gen_exception(EXCP_SWI);
> +                gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
>              } else {
> -                gen_exception(EXCP_DEBUG);
> +                gen_exception_internal(EXCP_DEBUG);
>              }
>              gen_set_label(dc->condlabel);
>          }
> @@ -10870,11 +10897,11 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>          }
>          gen_set_condexec(dc);
>          if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
> -            gen_exception(EXCP_SWI);
> +            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
>          } else {
>              /* FIXME: Single stepping a WFI insn will not halt
>                 the CPU.  */
> -            gen_exception(EXCP_DEBUG);
> +            gen_exception_internal(EXCP_DEBUG);
>          }
>      } else {
>          /* While branches must always occur at the end of an IT block,
> @@ -10903,7 +10930,7 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
>              gen_helper_wfi(cpu_env);
>              break;
>          case DISAS_SWI:
> -            gen_exception(EXCP_SWI);
> +            gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb));
>              break;
>          }
>          if (dc->condjmp) {
> diff --git a/target-arm/translate.h b/target-arm/translate.h
> index 889a031..4d3d363 100644
> --- a/target-arm/translate.h
> +++ b/target-arm/translate.h
> @@ -23,6 +23,10 @@ typedef struct DisasContext {
>      int vfp_enabled;
>      int vec_len;
>      int vec_stride;
> +    /* Immediate value in AArch32 SVC insn; must be set if is_jmp == DISAS_SWI
> +     * so that top level loop can generate correct syndrome information.
> +     */
> +    uint32_t svc_imm;
>      int aarch64;
>      int current_pl;
>      GHashTable *cp_regs;
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults Peter Maydell
@ 2014-03-17  3:28   ` Peter Crosthwaite
  2014-03-17 12:41     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  3:28 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Rob Herring <rob.herring@linaro.org>
>
> Set up the required syndrome information when we detect an MMU fault.
>
> Signed-off-by: Rob Herring <rob.herring@linaro.org>
> [PMM: split out from exception handling patch, tweaked to bring
>  in line with how we create other kinds of syndrome information]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/helper.c    | 16 ++++++++++++++++
>  target-arm/internals.h | 13 +++++++++++++
>  2 files changed, 29 insertions(+)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 2fa01ae..d547a9d 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -3586,6 +3586,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
>      target_ulong page_size;
>      int prot;
>      int ret, is_user;
> +    uint32_t syn;
>
>      is_user = mmu_idx == MMU_USER_IDX;
>      ret = get_phys_addr(env, address, access_type, is_user, &phys_addr, &prot,
> @@ -3598,14 +3599,29 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
>          return 0;
>      }
>
> +    /* AArch64 syndrome does not have an LPAE bit */
> +    syn = ret & ~(1 << 9);
> +
> +    /* For insn and data aborts we assume there is no instruction syndrome
> +     * information; this is always true for exceptions reported to EL1.
> +     */
>      if (access_type == 2) {
> +        syn = syn_insn_abort(0, 0, syn);
>          env->exception_index = EXCP_PREFETCH_ABORT;
>      } else {
> +        syn = syn_data_abort(0, 0, 0, access_type == 1, syn);
>          if (access_type == 1 && arm_feature(env, ARM_FEATURE_V6)) {
>              ret |= (1 << 11);
>          }
>          env->exception_index = EXCP_DATA_ABORT;
>      }
> +
> +    /* Set bit 26 for exceptions with no change in EL */
> +    if (arm_current_pl(env)) {
> +        syn |= 1 << ARM_EL_EC_SHIFT;
> +    }
> +

Perhaps in internals.h:

#define ARM_EL_EC_SAME_LEVEL (1 << ARM_EL_EC_SHIFT)

Then this becomes:

syn |= ARM_EL_EC_SAME_LEVEL

Then in internals.h you can be more self documenting with:

EC_BREAKPOINT_SAME_EL = EC_BREAKPOINT | ARM_EL_EC_SAME_LEVEL

Regards,
Peter

> +    env->exception.syndrome = syn;
>      env->exception.vaddress = address;
>      env->exception.fsr = ret;
>      return 1;
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index 9bec4e1..93f56a5 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -188,4 +188,17 @@ static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm,
>          | (rt2 << 10) | (rt << 5) | (crm << 1) | isread;
>  }
>
> +static inline uint32_t syn_insn_abort(int ea, int s1ptw, int fsc)
> +{
> +    return (EC_INSNABORT << ARM_EL_EC_SHIFT) | (ea << 9)
> +        | (s1ptw << 7) | fsc;
> +}
> +
> +static inline uint32_t syn_data_abort(int ea, int cm, int s1ptw, int wnr,
> +                                      int fsc)
> +{
> +    return (EC_DATAABORT << ARM_EL_EC_SHIFT) | (ea << 9)
> +        | (cm << 8) | (s1ptw << 7) | (wnr << 6) | fsc;
> +}
> +
>  #endif
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register Peter Maydell
@ 2014-03-17  5:13   ` Peter Crosthwaite
  2014-03-17 12:58     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  5:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Suppress the ID_AA64DFR0_EL1 PMUVer field, even if the CPU specific
> value claims that it exists. QEMU doesn't currently implement it,
> and not advertising it prevents the guest from trying to use it
> and getting UNDEFs on unimplemented registers.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
> This is arguably a hack, but otherwise Linux tries to prod
> half a dozen PMU sysregs.

Not really. I think sane self-identification trumps dummy feature
advertising. Although there is a consistency argument to be made, as
to whether you should also wipe-out any other features advertised by
this register and friends (e.g. should TraceVer be set?).

Regards,
Peter

> ---
>  target-arm/helper.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index c18f1a6..e1672aa 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1929,7 +1929,12 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>              { .name = "ID_AA64DFR0_EL1", .state = ARM_CP_STATE_AA64,
>                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 0,
>                .access = PL1_R, .type = ARM_CP_CONST,
> -              .resetvalue = cpu->id_aa64dfr0 },
> +              /* We mask out the PMUVer field, beacuse we don't currently
> +               * implement the PMU. Not advertising it prevents the guest
> +               * from trying to use it and getting UNDEFs on registers we
> +               * don't implement.
> +               */
> +              .resetvalue = cpu->id_aa64dfr0 & ~0xf00 },
>              { .name = "ID_AA64DFR1_EL1", .state = ARM_CP_STATE_AA64,
>                .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 5, .opc2 = 1,
>                .access = PL1_R, .type = ARM_CP_CONST,
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers Peter Maydell
@ 2014-03-17  5:20   ` Peter Crosthwaite
  2014-03-17 13:03     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  5:20 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> The ARM946 model currently uses the c5_data and c5_insn fields in the CPU
> state struct to store the contents of its access permission registers.
> This is confusing and a good source of bugs because for all the MMU-based
> CPUs those fields are fault status and fault address registers, which
> behave completely differently; they just happen to use the same cpreg
> encoding. Split them out to use their own fields instead.
>
> These registers are only present in PMSAv5 MPU systems (of which the
> ARM946 is our only current example); PMSAv6 and PMSAv7 (which we have
> no implementations of) handle access permissions differently. We name
> the new state fields accordingly.
>
> Note that this change fixes a bug where a data abort or prefetch abort
> on the ARM946 would accidentally corrupt the access permission registers
> because the interrupt handling code assumed the c5_data and c5_insn
> fields were always fault status registers.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  target-arm/cpu.h    |  2 ++
>  target-arm/helper.c | 24 ++++++++++++++----------
>  2 files changed, 16 insertions(+), 10 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index fa826c4..ffa4b37 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -179,6 +179,8 @@ typedef struct CPUARMState {
>          uint32_t c2_insn; /* MPU instruction cachable bits.  */
>          uint32_t c3; /* MMU domain access control register
>                          MPU write buffer control.  */
> +        uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
> +        uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
>          uint32_t c5_insn; /* Fault status registers.  */
>          uint32_t c5_data;
>          uint32_t c6_region[8]; /* MPU base/size registers.  */
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 45e6910..cbef0e5 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1183,40 +1183,44 @@ static uint32_t extended_mpu_ap_bits(uint32_t val)
>  static void pmsav5_data_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
>                                   uint64_t value)
>  {
> -    env->cp15.c5_data = extended_mpu_ap_bits(value);
> +    env->cp15.pmsav5_data_ap = extended_mpu_ap_bits(value);
>  }
>
>  static uint64_t pmsav5_data_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
> -    return simple_mpu_ap_bits(env->cp15.c5_data);
> +    return simple_mpu_ap_bits(env->cp15.pmsav5_data_ap);
>  }
>
>  static void pmsav5_insn_ap_write(CPUARMState *env, const ARMCPRegInfo *ri,
>                                   uint64_t value)
>  {
> -    env->cp15.c5_insn = extended_mpu_ap_bits(value);
> +    env->cp15.pmsav5_insn_ap = extended_mpu_ap_bits(value);
>  }
>
>  static uint64_t pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri)
>  {
> -    return simple_mpu_ap_bits(env->cp15.c5_insn);
> +    return simple_mpu_ap_bits(env->cp15.pmsav5_insn_ap);
>  }
>
>  static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
>      { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0,
> +      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
> +      .resetvalue = 0,

I know its just motion of existing code, but what's the policy on zero
resets? Can we leave them out for brevity? Checkpatch complains when a
global is explictly 0 initialized, so it seems sane that the same rule
applies to individual fields (just checkpatch probably has hard time
figuring this one out).

Regards,
Peter

>        .readfn = pmsav5_data_ap_read, .writefn = pmsav5_data_ap_write, },
>      { .name = "INSN_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
>        .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0,
> +      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap),
> +      .resetvalue = 0,
>        .readfn = pmsav5_insn_ap_read, .writefn = pmsav5_insn_ap_write, },
>      { .name = "DATA_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 2,
>        .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
> +      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
> +      .resetvalue = 0, },
>      { .name = "INSN_EXT_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 3,
>        .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
> +      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_insn_ap),
> +      .resetvalue = 0, },
>      { .name = "DCACHE_CFG", .cp = 15, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW,
>        .fieldoffset = offsetof(CPUARMState, cp15.c2_data), .resetvalue = 0, },
> @@ -3568,9 +3572,9 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address,
>         return 2;
>
>      if (access_type == 2) {
> -       mask = env->cp15.c5_insn;
> +        mask = env->cp15.pmsav5_insn_ap;
>      } else {
> -       mask = env->cp15.c5_data;
> +        mask = env->cp15.pmsav5_data_ap;
>      }
>      mask = (mask >> (n * 4)) & 0xf;
>      switch (mask) {
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers Peter Maydell
@ 2014-03-17  5:30   ` Peter Crosthwaite
  2014-03-17 13:06     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  5:30 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Rob Herring <rob.herring@linaro.org>
>
> Implement AArch64 views of ESR_EL1 and FAR_EL1, and make the 32 bit
> DFSR, DFAR, IFAR share state with them as architecturally specified.
> The IFSR doesn't share state with any AArch64 register visible at EL1,
> so just rename the state field without widening it to 64 bits.
>
> Signed-off-by: Rob Herring <rob.herring@linaro.org>
> [PMM: Minor tweaks; fix some bugs involving inconsistencies between
>  use of offsetof() or offsetoflow32() and struct field width]
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu.c    |  2 +-
>  target-arm/cpu.h    |  7 +++----
>  target-arm/helper.c | 38 +++++++++++++++++++++++++-------------
>  3 files changed, 29 insertions(+), 18 deletions(-)
>
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index 871ed09..948fd44 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -419,7 +419,7 @@ static void arm1026_initfn(Object *obj)
>          ARMCPRegInfo ifar = {
>              .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
>              .access = PL1_RW,
> -            .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
> +            .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
>              .resetvalue = 0
>          };
>          define_one_arm_cp_reg(cpu, &ifar);
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index ffa4b37..e51add2 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -181,11 +181,10 @@ typedef struct CPUARMState {
>                          MPU write buffer control.  */
>          uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
>          uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
> -        uint32_t c5_insn; /* Fault status registers.  */
> -        uint32_t c5_data;
> +        uint32_t ifsr_el2; /* Fault status registers.  */
> +        uint64_t esr_el1;
>          uint32_t c6_region[8]; /* MPU base/size registers.  */
> -        uint32_t c6_insn; /* Fault address registers.  */
> -        uint32_t c6_data;
> +        uint64_t far_el1; /* Fault address registers.  */
>          uint32_t c7_par;  /* Translation result. */
>          uint32_t c7_par_hi;  /* Translation result, high 32 bits */
>          uint32_t c9_insn; /* Cache lockdown registers.  */
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index cbef0e5..8d96b5c 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -456,7 +456,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
>      { .name = "DMB", .cp = 15, .crn = 7, .crm = 10, .opc1 = 0, .opc2 = 5,
>        .access = PL0_W, .type = ARM_CP_NOP },
>      { .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
> -      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_insn),
> +      .access = PL1_RW,
> +      .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
>        .resetvalue = 0, },
>      /* Watchpoint Fault Address Register : should actually only be present
>       * for 1136, 1176, 11MPCore.
> @@ -1316,11 +1317,16 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri,
>
>  static const ARMCPRegInfo vmsa_cp_reginfo[] = {
>      { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
> -      .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
> +      .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
> +      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> +      .resetfn = arm_cp_reset_ignore, },
>      { .name = "IFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 1,
>        .access = PL1_RW,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_insn), .resetvalue = 0, },
> +      .fieldoffset = offsetof(CPUARMState, cp15.ifsr_el2), .resetvalue = 0, },
> +    { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0,
> +      .access = PL1_RW,
> +      .fieldoffset = offsetof(CPUARMState, cp15.esr_el1), .resetvalue = 0, },
>      { .name = "TTBR0_EL1", .state = ARM_CP_STATE_BOTH,
>        .opc0 = 3, .crn = 2, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.ttbr0_el1),
> @@ -1338,8 +1344,10 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
>        .access = PL1_RW, .type = ARM_CP_NO_MIGRATE, .writefn = vmsa_ttbcr_write,
>        .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write,
>        .fieldoffset = offsetoflow32(CPUARMState, cp15.c2_control) },
> -    { .name = "DFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> -      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.c6_data),
> +    /* 64-bit FAR; this entry also gives us the AArch32 DFAR */
> +    { .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
> +      .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
> +      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
>        .resetvalue = 0, },
>      REGINFO_SENTINEL
>  };
> @@ -1379,7 +1387,8 @@ static void omap_cachemaint_write(CPUARMState *env, const ARMCPRegInfo *ri,
>  static const ARMCPRegInfo omap_cp_reginfo[] = {
>      { .name = "DFSR", .cp = 15, .crn = 5, .crm = CP_ANY,
>        .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_RW, .type = ARM_CP_OVERRIDE,
> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0, },
> +      .fieldoffset = offsetoflow32(CPUARMState, cp15.esr_el1),
> +      .resetvalue = 0, },
>      { .name = "", .cp = 15, .crn = 15, .crm = 0, .opc1 = 0, .opc2 = 0,
>        .access = PL1_RW, .type = ARM_CP_NOP },
>      { .name = "TICONFIG", .cp = 15, .crn = 15, .crm = 1, .opc1 = 0, .opc2 = 0,
> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>          env->exception.fsr = 2;
>          /* Fall through to prefetch abort.  */
>      case EXCP_PREFETCH_ABORT:
> -        env->cp15.c5_insn = env->exception.fsr;
> -        env->cp15.c6_insn = env->exception.vaddress;
> +        env->cp15.ifsr_el2 = env->exception.fsr;
> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
> +                                      env->exception.vaddress);

Is it better to just grab the CPRegInfo and pass it to raw_write() to
do the deposit dirty work?

Regards,
Peter

>          qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
> -                      env->cp15.c5_insn, env->cp15.c6_insn);
> +                      env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
>          new_mode = ARM_CPU_MODE_ABT;
>          addr = 0x0c;
>          mask = CPSR_A | CPSR_I;
>          offset = 4;
>          break;
>      case EXCP_DATA_ABORT:
> -        env->cp15.c5_data = env->exception.fsr;
> -        env->cp15.c6_data = env->exception.vaddress;
> +        env->cp15.esr_el1 = env->exception.fsr;
> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
> +                                      env->exception.vaddress);
>          qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
> -                      env->cp15.c5_data, env->cp15.c6_data);
> +                      (uint32_t)env->cp15.esr_el1,
> +                      (uint32_t)env->exception.vaddress);
>          new_mode = ARM_CPU_MODE_ABT;
>          addr = 0x10;
>          mask = CPSR_A | CPSR_I;
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register.
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register Peter Maydell
@ 2014-03-17  5:33   ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  5:33 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Add the AArch64 ELR_EL1 register.
>
> Note that this does not live in env->cp15: for KVM migration
> compatibility we need to migrate it separately rather than
> as part of the system registers, because the KVM-to-userspace
> interface puts it in the struct kvm_regs rather than making
> them visible via the ONE_REG ioctls.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

(Although my working knowledge of KVM is very limited).

Regards,
Peter

> ---
>  target-arm/cpu.h     |  2 ++
>  target-arm/helper.c  |  4 ++++
>  target-arm/kvm64.c   | 15 ++++++++++++++-
>  target-arm/machine.c |  7 ++++---
>  4 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index e51add2..7ef2c71 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -162,6 +162,8 @@ typedef struct CPUARMState {
>      uint32_t condexec_bits; /* IT bits.  cpsr[15:10,26:25].  */
>      uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
>
> +    uint64_t elr_el1; /* AArch64 ELR_EL1 */
> +
>      /* System control coprocessor (cp15) */
>      struct {
>          uint32_t c0_cpuid;
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 8d96b5c..812fc73 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1810,6 +1810,10 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
>      { .name = "OSLAR_EL1", .state = ARM_CP_STATE_AA64,
>        .opc0 = 2, .opc1 = 0, .crn = 1, .crm = 0, .opc2 = 4,
>        .access = PL1_W, .type = ARM_CP_NOP },
> +    { .name = "ELR_EL1", .state = ARM_CP_STATE_AA64,
> +      .type = ARM_CP_NO_MIGRATE,
> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
> +      .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
>      REGINFO_SENTINEL
>  };
>
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> index 1b7ca90..ee72748 100644
> --- a/target-arm/kvm64.c
> +++ b/target-arm/kvm64.c
> @@ -144,9 +144,15 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>          return ret;
>      }
>
> +    reg.id = AARCH64_CORE_REG(elr_el1);
> +    reg.addr = (uintptr_t) &env->elr_el1;
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
>      /* TODO:
>       * SP_EL1
> -     * ELR_EL1
>       * SPSR[]
>       * FP state
>       * system registers
> @@ -195,6 +201,13 @@ int kvm_arch_get_registers(CPUState *cs)
>          return ret;
>      }
>
> +    reg.id = AARCH64_CORE_REG(elr_el1);
> +    reg.addr = (uintptr_t) &env->elr_el1;
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
>      /* TODO: other registers */
>      return ret;
>  }
> diff --git a/target-arm/machine.c b/target-arm/machine.c
> index fc8825e..01d8f83 100644
> --- a/target-arm/machine.c
> +++ b/target-arm/machine.c
> @@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
>
>  const VMStateDescription vmstate_arm_cpu = {
>      .name = "cpu",
> -    .version_id = 14,
> -    .minimum_version_id = 14,
> -    .minimum_version_id_old = 14,
> +    .version_id = 15,
> +    .minimum_version_id = 15,
> +    .minimum_version_id_old = 15,
>      .pre_save = cpu_pre_save,
>      .post_load = cpu_post_load,
>      .fields = (VMStateField[]) {
> @@ -243,6 +243,7 @@ const VMStateDescription vmstate_arm_cpu = {
>          VMSTATE_UINT32_ARRAY(env.banked_r14, ARMCPU, 6),
>          VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
>          VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
> +        VMSTATE_UINT64(env.elr_el1, ARMCPU),
>          /* The length-check must come before the arrays to avoid
>           * incoming data possibly overflowing the array.
>           */
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1 Peter Maydell
@ 2014-03-17  7:02   ` Peter Crosthwaite
  2014-03-17  7:31     ` Peter Crosthwaite
  2014-03-20 17:12     ` Peter Maydell
  0 siblings, 2 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  7:02 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement handling for the AArch64 SP_EL0 system register.
> This holds the EL0 stack pointer, and is only accessible when
> it's not being used as the stack pointer, ie when we're in EL1
> and EL1 is using its own stack pointer. We also provide a
> definition of the SP_EL1 register; this isn't guest visible
> as a system register for an implementation like QEMU which
> doesn't provide EL2 or EL3; however it is useful for ensuring
> the underlying state is migrated.
>
> We need to update the state fields in the CPU state whenever

"whenever we".

> switch stack pointers; this happens when we take an exception
> and also when SPSEL is used to change the bit in PSTATE which
> indicates which stack pointer EL1 should use.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu.h       |  2 ++
>  target-arm/helper.c    | 34 ++++++++++++++++++++++++++++++++++
>  target-arm/internals.h | 25 +++++++++++++++++++++++++
>  target-arm/kvm64.c     | 37 ++++++++++++++++++++++++++++++++++---
>  target-arm/machine.c   |  7 ++++---
>  target-arm/op_helper.c |  2 +-
>  6 files changed, 100 insertions(+), 7 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 7ef2c71..338edc3 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -163,6 +163,7 @@ typedef struct CPUARMState {
>      uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
>
>      uint64_t elr_el1; /* AArch64 ELR_EL1 */
> +    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
>

Should the macro AARCH64_MAX_EL_LEVELS exist for this?

>      /* System control coprocessor (cp15) */
>      struct {
> @@ -431,6 +432,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
>   * Only these are valid when in AArch64 mode; in
>   * AArch32 mode SPSRs are basically CPSR-format.
>   */
> +#define PSTATE_SP (1U)
>  #define PSTATE_M (0xFU)
>  #define PSTATE_nRW (1U << 4)
>  #define PSTATE_F (1U << 6)
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 812fc73..6ee4135 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1682,6 +1682,27 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
>      return cpu->dcz_blocksize | dzp_bit;
>  }
>
> +static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    if (!env->pstate & PSTATE_SP) {
> +        /* Access to SP_EL0 is undefined if it's being used as
> +         * the stack pointer.
> +         */
> +        return CP_ACCESS_TRAP_UNCATEGORIZED;
> +    }
> +    return CP_ACCESS_OK;
> +}
> +
> +static uint64_t spsel_read(CPUARMState *env, const ARMCPRegInfo *ri)
> +{
> +    return env->pstate & PSTATE_SP;
> +}
> +
> +static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
> +{
> +    update_spsel(env, val);
> +}
> +
>  static const ARMCPRegInfo v8_cp_reginfo[] = {
>      /* Minimal set of EL0-visible registers. This will need to be expanded
>       * significantly for system emulation of AArch64 CPUs.
> @@ -1814,6 +1835,19 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
>        .type = ARM_CP_NO_MIGRATE,
>        .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
>        .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
> +    /* We rely on the access checks not allowing the guest to write to the
> +     * state field when SPSel indicates that it's being used as the stack
> +     * pointer.
> +     */
> +    { .name = "SP_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 1, .opc2 = 0,
> +      .access = PL1_RW, .accessfn = sp_el0_access,
> +      .type = ARM_CP_NO_MIGRATE,
> +      .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
> +    { .name = "SPSel", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
> +      .type = ARM_CP_NO_MIGRATE,
> +      .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
>      REGINFO_SENTINEL
>  };
>
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index 11a7040..97a76c2 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -60,6 +60,31 @@ enum arm_fprounding {
>
>  int arm_rmode_to_sf(int rmode);
>
> +static inline void update_spsel(CPUARMState *env, uint32_t imm)
> +{
> +    /* Update PSTATE SPSel bit; this requires us to update the
> +     * working stack pointer in xregs[31].
> +     */
> +    if (!((imm ^ env->pstate) & PSTATE_SP)) {
> +        return;
> +    }
> +    env->pstate = deposit32(env->pstate, 0, 1, imm);
> +
> +    /* EL0 has no access rights to update SPSel, and this code
> +     * assumes we are updating SP for EL1 while running as EL1.
> +     */
> +    assert(arm_current_pl(env) == 1);
> +    if (env->pstate & PSTATE_SP) {
> +        /* Switch from using SP_EL0 to using SP_ELx */
> +        env->sp_el[0] = env->xregs[31];

Does this break on repeated writes to spsel bit of the same value? E.g.

Lets say I have the sequence (with spsel = 0 initially):

spsel = 1; /* Via MSR SPSel, <Xt> ; */
/* do some stuff that changes current SP */
spsel = 1; /* again */

The first write will sync sp_el[0] fine. But the second one will take
the new version xregs[31] and save to sp_el[0] again. A subsequent
return to use of sp_el[0] expecting the original saved value would
then break.

Can probably be solved by doing to save offs before ->pstate update
(based on the old value) and the loads after.

> +        env->xregs[31] = env->sp_el[1];
> +    } else {
> +        /* Switch from SP_EL0 to SP_ELx */
> +        env->sp_el[1] = env->xregs[31];
> +        env->xregs[31] = env->sp_el[0];
> +    }
> +}
> +
>  /* Valid Syndrome Register EC field values */
>  enum arm_exception_class {
>      EC_UNCATEGORIZED = 0,
> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
> index ee72748..39c4364 100644
> --- a/target-arm/kvm64.c
> +++ b/target-arm/kvm64.c
> @@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>          }
>      }
>
> +    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
> +     * QEMU side we keep the current SP in xregs[31] as well.
> +     */
> +    if (env->pstate & PSTATE_SP) {
> +        env->sp_el[1] = env->xregs[31];
> +    } else {
> +        env->sp_el[0] = env->xregs[31];
> +    }
> +
>      reg.id = AARCH64_CORE_REG(regs.sp);
> -    reg.addr = (uintptr_t) &env->xregs[31];
> +    reg.addr = (uintptr_t) &env->sp_el[0];
> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(sp_el1);
> +    reg.addr = (uintptr_t) &env->sp_el[1];
>      ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
>      if (ret) {
>          return ret;
> @@ -152,7 +168,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>      }
>
>      /* TODO:
> -     * SP_EL1
>       * SPSR[]
>       * FP state
>       * system registers
> @@ -180,7 +195,14 @@ int kvm_arch_get_registers(CPUState *cs)
>      }
>
>      reg.id = AARCH64_CORE_REG(regs.sp);
> -    reg.addr = (uintptr_t) &env->xregs[31];
> +    reg.addr = (uintptr_t) &env->sp_el[0];
> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> +    if (ret) {
> +        return ret;
> +    }
> +
> +    reg.id = AARCH64_CORE_REG(sp_el1);
> +    reg.addr = (uintptr_t) &env->sp_el[1];
>      ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
>      if (ret) {
>          return ret;
> @@ -194,6 +216,15 @@ int kvm_arch_get_registers(CPUState *cs)
>      }
>      pstate_write(env, val);
>
> +    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
> +     * QEMU side we keep the current SP in xregs[31] as well.
> +     */
> +    if (env->pstate & PSTATE_SP) {
> +        env->xregs[31] = env->sp_el[1];
> +    } else {
> +        env->xregs[31] = env->sp_el[0];
> +    }
> +
>      reg.id = AARCH64_CORE_REG(regs.pc);
>      reg.addr = (uintptr_t) &env->pc;
>      ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
> diff --git a/target-arm/machine.c b/target-arm/machine.c
> index 01d8f83..af49662 100644
> --- a/target-arm/machine.c
> +++ b/target-arm/machine.c
> @@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
>
>  const VMStateDescription vmstate_arm_cpu = {
>      .name = "cpu",
> -    .version_id = 15,
> -    .minimum_version_id = 15,
> -    .minimum_version_id_old = 15,
> +    .version_id = 16,
> +    .minimum_version_id = 16,
> +    .minimum_version_id_old = 16,

So in the past, I have squashed unrelated patches together to minimise
VMSD versions bumps. Whats more important - these versions numbers of
git patch separation?

Regards,
Peter

>      .pre_save = cpu_pre_save,
>      .post_load = cpu_post_load,
>      .fields = (VMStateField[]) {
> @@ -244,6 +244,7 @@ const VMStateDescription vmstate_arm_cpu = {
>          VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
>          VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
>          VMSTATE_UINT64(env.elr_el1, ARMCPU),
> +        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
>          /* The length-check must come before the arrays to avoid
>           * incoming data possibly overflowing the array.
>           */
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index b1db672..aeb2538 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -349,7 +349,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
>
>      switch (op) {
>      case 0x05: /* SPSel */
> -        env->pstate = deposit32(env->pstate, 0, 1, imm);
> +        update_spsel(env, imm);
>          break;
>      case 0x1e: /* DAIFSet */
>          env->daif |= (imm << 6) & PSTATE_DAIF;
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h Peter Maydell
@ 2014-03-17  7:04   ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  7:04 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Move arm_log_exception() into internals.h so we can use it from
> helper-a64.c for the AArch64 exception entry code.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  target-arm/helper.c    | 31 -------------------------------
>  target-arm/internals.h | 31 +++++++++++++++++++++++++++++++
>  2 files changed, 31 insertions(+), 31 deletions(-)
>
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 3a976f7..e461914 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -2849,37 +2849,6 @@ static void do_v7m_exception_exit(CPUARMState *env)
>         pointer.  */
>  }
>
> -/* Exception names for debug logging; note that not all of these
> - * precisely correspond to architectural exceptions.
> - */
> -static const char * const excnames[] = {
> -    [EXCP_UDEF] = "Undefined Instruction",
> -    [EXCP_SWI] = "SVC",
> -    [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
> -    [EXCP_DATA_ABORT] = "Data Abort",
> -    [EXCP_IRQ] = "IRQ",
> -    [EXCP_FIQ] = "FIQ",
> -    [EXCP_BKPT] = "Breakpoint",
> -    [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
> -    [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
> -    [EXCP_STREX] = "QEMU intercept of STREX",
> -};
> -
> -static inline void arm_log_exception(int idx)
> -{
> -    if (qemu_loglevel_mask(CPU_LOG_INT)) {
> -        const char *exc = NULL;
> -
> -        if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
> -            exc = excnames[idx];
> -        }
> -        if (!exc) {
> -            exc = "unknown";
> -        }
> -        qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
> -    }
> -}
> -
>  void arm_v7m_cpu_do_interrupt(CPUState *cs)
>  {
>      ARMCPU *cpu = ARM_CPU(cs);
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> index 97a76c2..e15136b 100644
> --- a/target-arm/internals.h
> +++ b/target-arm/internals.h
> @@ -39,6 +39,37 @@ static inline bool excp_is_internal(int excp)
>          || excp == EXCP_STREX;
>  }
>
> +/* Exception names for debug logging; note that not all of these
> + * precisely correspond to architectural exceptions.
> + */
> +static const char * const excnames[] = {
> +    [EXCP_UDEF] = "Undefined Instruction",
> +    [EXCP_SWI] = "SVC",
> +    [EXCP_PREFETCH_ABORT] = "Prefetch Abort",
> +    [EXCP_DATA_ABORT] = "Data Abort",
> +    [EXCP_IRQ] = "IRQ",
> +    [EXCP_FIQ] = "FIQ",
> +    [EXCP_BKPT] = "Breakpoint",
> +    [EXCP_EXCEPTION_EXIT] = "QEMU v7M exception exit",
> +    [EXCP_KERNEL_TRAP] = "QEMU intercept of kernel commpage",
> +    [EXCP_STREX] = "QEMU intercept of STREX",
> +};
> +
> +static inline void arm_log_exception(int idx)
> +{
> +    if (qemu_loglevel_mask(CPU_LOG_INT)) {
> +        const char *exc = NULL;
> +
> +        if (idx >= 0 && idx < ARRAY_SIZE(excnames)) {
> +            exc = excnames[idx];
> +        }
> +        if (!exc) {
> +            exc = "unknown";
> +        }
> +        qemu_log_mask(CPU_LOG_INT, "Taking exception %d [%s]\n", idx, exc);
> +    }
> +}
> +
>  /* Scale factor for generic timers, ie number of ns per tick.
>   * This gives a 62.5MHz timer.
>   */
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57 Peter Maydell
@ 2014-03-17  7:12   ` Peter Crosthwaite
  2014-04-10 15:02     ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  7:12 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Support the Cortex-A57 in the virt machine model.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> This should perhaps not be just stealing the a15mpcore_priv
> on the basis that it's a GICv2...

Wont this mean you gets lots of extraneous hardware? Although, with a
pure virtual machine I guess you can do whatever you really want.

> ---
>  hw/arm/virt.c | 8 ++++++++
>  1 file changed, 8 insertions(+)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 517f2fe..d985d2e 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -123,6 +123,14 @@ static VirtBoardInfo machines[] = {
>          .irqmap = a15irqmap,
>      },
>      {
> +        .cpu_model = "cortex-a57",
> +        /* Use the A15 private peripheral model for now: probably wrong! */
> +        .qdevname = "a15mpcore_priv",

Can you just change this to gics qdev name? The qdev propnames of gic
and mpcore ("num-cpu" and "num-irq") should just match. Then perhaps a
little callback to set gicv2 version property.

Regards,
Peter

> +        .gic_compatible = "arm,cortex-a15-gic",
> +        .memmap = a15memmap,
> +        .irqmap = a15irqmap,
> +    },
> +    {
>          .cpu_model = "host",
>          /* We use the A15 private peripheral model to get a V2 GIC */
>          .qdevname = "a15mpcore_priv",
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h Peter Maydell
@ 2014-03-17  7:13   ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  7:13 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Currently cpu.h defines a mixture of functions and types needed by
> the rest of QEMU and those needed only by files within target-arm/.
> Split the latter out into a new header so they aren't needlessly
> exposed further than required.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

> ---
>  target-arm/cpu.c           |  1 +
>  target-arm/cpu.h           | 20 -------------------
>  target-arm/helper.c        |  1 +
>  target-arm/internals.h     | 49 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/kvm32.c         |  1 +
>  target-arm/op_helper.c     |  1 +
>  target-arm/translate-a64.c |  1 +
>  target-arm/translate.c     |  1 +
>  8 files changed, 55 insertions(+), 20 deletions(-)
>  create mode 100644 target-arm/internals.h
>
> diff --git a/target-arm/cpu.c b/target-arm/cpu.c
> index 1ce8a9b..bc8eac9 100644
> --- a/target-arm/cpu.c
> +++ b/target-arm/cpu.c
> @@ -19,6 +19,7 @@
>   */
>
>  #include "cpu.h"
> +#include "internals.h"
>  #include "qemu-common.h"
>  #include "hw/qdev-properties.h"
>  #include "qapi/qmp/qerror.h"
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 49fef3f..6252ff3 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -111,11 +111,6 @@ typedef struct ARMGenericTimer {
>  #define GTIMER_VIRT 1
>  #define NUM_GTIMERS 2
>
> -/* Scale factor for generic timers, ie number of ns per tick.
> - * This gives a 62.5MHz timer.
> - */
> -#define GTIMER_SCALE 16
> -
>  typedef struct CPUARMState {
>      /* Regs for current mode.  */
>      uint32_t regs[16];
> @@ -318,11 +313,7 @@ typedef struct CPUARMState {
>  #include "cpu-qom.h"
>
>  ARMCPU *cpu_arm_init(const char *cpu_model);
> -void arm_translate_init(void);
> -void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
>  int cpu_arm_exec(CPUARMState *s);
> -int bank_number(int mode);
> -void switch_mode(CPUARMState *, int);
>  uint32_t do_arm_semihosting(CPUARMState *env);
>
>  static inline bool is_a64(CPUARMState *env)
> @@ -545,17 +536,6 @@ static inline void vfp_set_fpcr(CPUARMState *env, uint32_t val)
>      vfp_set_fpscr(env, new_fpscr);
>  }
>
> -enum arm_fprounding {
> -    FPROUNDING_TIEEVEN,
> -    FPROUNDING_POSINF,
> -    FPROUNDING_NEGINF,
> -    FPROUNDING_ZERO,
> -    FPROUNDING_TIEAWAY,
> -    FPROUNDING_ODD
> -};
> -
> -int arm_rmode_to_sf(int rmode);
> -
>  enum arm_cpu_mode {
>    ARM_CPU_MODE_USR = 0x10,
>    ARM_CPU_MODE_FIQ = 0x11,
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index d44e603..3d65bae 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1,4 +1,5 @@
>  #include "cpu.h"
> +#include "internals.h"
>  #include "exec/gdbstub.h"
>  #include "helper.h"
>  #include "qemu/host-utils.h"
> diff --git a/target-arm/internals.h b/target-arm/internals.h
> new file mode 100644
> index 0000000..a38a57f
> --- /dev/null
> +++ b/target-arm/internals.h
> @@ -0,0 +1,49 @@
> +/*
> + * QEMU ARM CPU -- internal functions and types
> + *
> + * Copyright (c) 2014 Linaro Ltd
> + *
> + * 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 (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, see
> + * <http://www.gnu.org/licenses/gpl-2.0.html>
> + *
> + * This header defines functions, types, etc which need to be shared
> + * between different source files within target-arm/ but which are
> + * private to it and not required by the rest of QEMU.
> + */
> +
> +#ifndef TARGET_ARM_INTERNALS_H
> +#define TARGET_ARM_INTERNALS_H
> +
> +/* Scale factor for generic timers, ie number of ns per tick.
> + * This gives a 62.5MHz timer.
> + */
> +#define GTIMER_SCALE 16
> +
> +int bank_number(int mode);
> +void switch_mode(CPUARMState *, int);
> +void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
> +void arm_translate_init(void);
> +
> +enum arm_fprounding {
> +    FPROUNDING_TIEEVEN,
> +    FPROUNDING_POSINF,
> +    FPROUNDING_NEGINF,
> +    FPROUNDING_ZERO,
> +    FPROUNDING_TIEAWAY,
> +    FPROUNDING_ODD
> +};
> +
> +int arm_rmode_to_sf(int rmode);
> +
> +#endif
> diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
> index a4fde07..b21f844 100644
> --- a/target-arm/kvm32.c
> +++ b/target-arm/kvm32.c
> @@ -21,6 +21,7 @@
>  #include "sysemu/kvm.h"
>  #include "kvm_arm.h"
>  #include "cpu.h"
> +#include "internals.h"
>  #include "hw/arm/arm.h"
>
>  static inline void set_feature(uint64_t *features, int feature)
> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
> index 7d06d2f..1458cd3 100644
> --- a/target-arm/op_helper.c
> +++ b/target-arm/op_helper.c
> @@ -18,6 +18,7 @@
>   */
>  #include "cpu.h"
>  #include "helper.h"
> +#include "internals.h"
>
>  #define SIGNBIT (uint32_t)0x80000000
>  #define SIGNBIT64 ((uint64_t)1 << 63)
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index f89b0a5..156fda2 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -26,6 +26,7 @@
>  #include "tcg-op.h"
>  #include "qemu/log.h"
>  #include "translate.h"
> +#include "internals.h"
>  #include "qemu/host-utils.h"
>
>  #include "exec/gen-icount.h"
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 9612da7..4a53313 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -25,6 +25,7 @@
>  #include <inttypes.h>
>
>  #include "cpu.h"
> +#include "internals.h"
>  #include "disas/disas.h"
>  #include "tcg-op.h"
>  #include "qemu/log.h"
> --
> 1.9.0
>
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1
  2014-03-17  7:02   ` Peter Crosthwaite
@ 2014-03-17  7:31     ` Peter Crosthwaite
  2014-03-20 17:12     ` Peter Maydell
  1 sibling, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17  7:31 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On Mon, Mar 17, 2014 at 5:02 PM, Peter Crosthwaite
<peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Implement handling for the AArch64 SP_EL0 system register.
>> This holds the EL0 stack pointer, and is only accessible when
>> it's not being used as the stack pointer, ie when we're in EL1
>> and EL1 is using its own stack pointer. We also provide a
>> definition of the SP_EL1 register; this isn't guest visible
>> as a system register for an implementation like QEMU which
>> doesn't provide EL2 or EL3; however it is useful for ensuring
>> the underlying state is migrated.
>>
>> We need to update the state fields in the CPU state whenever
>
> "whenever we".
>
>> switch stack pointers; this happens when we take an exception
>> and also when SPSEL is used to change the bit in PSTATE which
>> indicates which stack pointer EL1 should use.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  target-arm/cpu.h       |  2 ++
>>  target-arm/helper.c    | 34 ++++++++++++++++++++++++++++++++++
>>  target-arm/internals.h | 25 +++++++++++++++++++++++++
>>  target-arm/kvm64.c     | 37 ++++++++++++++++++++++++++++++++++---
>>  target-arm/machine.c   |  7 ++++---
>>  target-arm/op_helper.c |  2 +-
>>  6 files changed, 100 insertions(+), 7 deletions(-)
>>
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index 7ef2c71..338edc3 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -163,6 +163,7 @@ typedef struct CPUARMState {
>>      uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
>>
>>      uint64_t elr_el1; /* AArch64 ELR_EL1 */
>> +    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
>>
>
> Should the macro AARCH64_MAX_EL_LEVELS exist for this?
>
>>      /* System control coprocessor (cp15) */
>>      struct {
>> @@ -431,6 +432,7 @@ int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
>>   * Only these are valid when in AArch64 mode; in
>>   * AArch32 mode SPSRs are basically CPSR-format.
>>   */
>> +#define PSTATE_SP (1U)
>>  #define PSTATE_M (0xFU)
>>  #define PSTATE_nRW (1U << 4)
>>  #define PSTATE_F (1U << 6)
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index 812fc73..6ee4135 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -1682,6 +1682,27 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
>>      return cpu->dcz_blocksize | dzp_bit;
>>  }
>>
>> +static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
>> +{
>> +    if (!env->pstate & PSTATE_SP) {
>> +        /* Access to SP_EL0 is undefined if it's being used as
>> +         * the stack pointer.
>> +         */
>> +        return CP_ACCESS_TRAP_UNCATEGORIZED;
>> +    }
>> +    return CP_ACCESS_OK;
>> +}
>> +
>> +static uint64_t spsel_read(CPUARMState *env, const ARMCPRegInfo *ri)
>> +{
>> +    return env->pstate & PSTATE_SP;
>> +}
>> +
>> +static void spsel_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t val)
>> +{
>> +    update_spsel(env, val);
>> +}
>> +
>>  static const ARMCPRegInfo v8_cp_reginfo[] = {
>>      /* Minimal set of EL0-visible registers. This will need to be expanded
>>       * significantly for system emulation of AArch64 CPUs.
>> @@ -1814,6 +1835,19 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
>>        .type = ARM_CP_NO_MIGRATE,
>>        .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 0, .opc2 = 1,
>>        .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, elr_el1) },
>> +    /* We rely on the access checks not allowing the guest to write to the
>> +     * state field when SPSel indicates that it's being used as the stack
>> +     * pointer.
>> +     */
>> +    { .name = "SP_EL0", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 1, .opc2 = 0,
>> +      .access = PL1_RW, .accessfn = sp_el0_access,
>> +      .type = ARM_CP_NO_MIGRATE,
>> +      .fieldoffset = offsetof(CPUARMState, sp_el[0]) },
>> +    { .name = "SPSel", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
>> +      .type = ARM_CP_NO_MIGRATE,
>> +      .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
>>      REGINFO_SENTINEL
>>  };
>>
>> diff --git a/target-arm/internals.h b/target-arm/internals.h
>> index 11a7040..97a76c2 100644
>> --- a/target-arm/internals.h
>> +++ b/target-arm/internals.h
>> @@ -60,6 +60,31 @@ enum arm_fprounding {
>>
>>  int arm_rmode_to_sf(int rmode);
>>
>> +static inline void update_spsel(CPUARMState *env, uint32_t imm)
>> +{
>> +    /* Update PSTATE SPSel bit; this requires us to update the
>> +     * working stack pointer in xregs[31].
>> +     */
>> +    if (!((imm ^ env->pstate) & PSTATE_SP)) {
>> +        return;
>> +    }

Ergh, my bad. Missed your short return path here.

>> +    env->pstate = deposit32(env->pstate, 0, 1, imm);
>> +
>> +    /* EL0 has no access rights to update SPSel, and this code
>> +     * assumes we are updating SP for EL1 while running as EL1.
>> +     */
>> +    assert(arm_current_pl(env) == 1);
>> +    if (env->pstate & PSTATE_SP) {
>> +        /* Switch from using SP_EL0 to using SP_ELx */
>> +        env->sp_el[0] = env->xregs[31];
>
> Does this break on repeated writes to spsel bit of the same value? E.g.
>
> Lets say I have the sequence (with spsel = 0 initially):
>
> spsel = 1; /* Via MSR SPSel, <Xt> ; */
> /* do some stuff that changes current SP */
> spsel = 1; /* again */
>
> The first write will sync sp_el[0] fine. But the second one will take
> the new version xregs[31] and save to sp_el[0] again. A subsequent
> return to use of sp_el[0] expecting the original saved value would
> then break.
>
> Can probably be solved by doing to save offs before ->pstate update
> (based on the old value) and the loads after.
>

Sorry for the noise.

Regards,
Peter

>> +        env->xregs[31] = env->sp_el[1];
>> +    } else {
>> +        /* Switch from SP_EL0 to SP_ELx */
>> +        env->sp_el[1] = env->xregs[31];
>> +        env->xregs[31] = env->sp_el[0];
>> +    }
>> +}
>> +
>>  /* Valid Syndrome Register EC field values */
>>  enum arm_exception_class {
>>      EC_UNCATEGORIZED = 0,
>> diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
>> index ee72748..39c4364 100644
>> --- a/target-arm/kvm64.c
>> +++ b/target-arm/kvm64.c
>> @@ -121,8 +121,24 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>>          }
>>      }
>>
>> +    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
>> +     * QEMU side we keep the current SP in xregs[31] as well.
>> +     */
>> +    if (env->pstate & PSTATE_SP) {
>> +        env->sp_el[1] = env->xregs[31];
>> +    } else {
>> +        env->sp_el[0] = env->xregs[31];
>> +    }
>> +
>>      reg.id = AARCH64_CORE_REG(regs.sp);
>> -    reg.addr = (uintptr_t) &env->xregs[31];
>> +    reg.addr = (uintptr_t) &env->sp_el[0];
>> +    ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
>> +    if (ret) {
>> +        return ret;
>> +    }
>> +
>> +    reg.id = AARCH64_CORE_REG(sp_el1);
>> +    reg.addr = (uintptr_t) &env->sp_el[1];
>>      ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
>>      if (ret) {
>>          return ret;
>> @@ -152,7 +168,6 @@ int kvm_arch_put_registers(CPUState *cs, int level)
>>      }
>>
>>      /* TODO:
>> -     * SP_EL1
>>       * SPSR[]
>>       * FP state
>>       * system registers
>> @@ -180,7 +195,14 @@ int kvm_arch_get_registers(CPUState *cs)
>>      }
>>
>>      reg.id = AARCH64_CORE_REG(regs.sp);
>> -    reg.addr = (uintptr_t) &env->xregs[31];
>> +    reg.addr = (uintptr_t) &env->sp_el[0];
>> +    ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
>> +    if (ret) {
>> +        return ret;
>> +    }
>> +
>> +    reg.id = AARCH64_CORE_REG(sp_el1);
>> +    reg.addr = (uintptr_t) &env->sp_el[1];
>>      ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
>>      if (ret) {
>>          return ret;
>> @@ -194,6 +216,15 @@ int kvm_arch_get_registers(CPUState *cs)
>>      }
>>      pstate_write(env, val);
>>
>> +    /* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
>> +     * QEMU side we keep the current SP in xregs[31] as well.
>> +     */
>> +    if (env->pstate & PSTATE_SP) {
>> +        env->xregs[31] = env->sp_el[1];
>> +    } else {
>> +        env->xregs[31] = env->sp_el[0];
>> +    }
>> +
>>      reg.id = AARCH64_CORE_REG(regs.pc);
>>      reg.addr = (uintptr_t) &env->pc;
>>      ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
>> diff --git a/target-arm/machine.c b/target-arm/machine.c
>> index 01d8f83..af49662 100644
>> --- a/target-arm/machine.c
>> +++ b/target-arm/machine.c
>> @@ -222,9 +222,9 @@ static int cpu_post_load(void *opaque, int version_id)
>>
>>  const VMStateDescription vmstate_arm_cpu = {
>>      .name = "cpu",
>> -    .version_id = 15,
>> -    .minimum_version_id = 15,
>> -    .minimum_version_id_old = 15,
>> +    .version_id = 16,
>> +    .minimum_version_id = 16,
>> +    .minimum_version_id_old = 16,
>
> So in the past, I have squashed unrelated patches together to minimise
> VMSD versions bumps. Whats more important - these versions numbers of
> git patch separation?
>
> Regards,
> Peter
>
>>      .pre_save = cpu_pre_save,
>>      .post_load = cpu_post_load,
>>      .fields = (VMStateField[]) {
>> @@ -244,6 +244,7 @@ const VMStateDescription vmstate_arm_cpu = {
>>          VMSTATE_UINT32_ARRAY(env.usr_regs, ARMCPU, 5),
>>          VMSTATE_UINT32_ARRAY(env.fiq_regs, ARMCPU, 5),
>>          VMSTATE_UINT64(env.elr_el1, ARMCPU),
>> +        VMSTATE_UINT64_ARRAY(env.sp_el, ARMCPU, 2),
>>          /* The length-check must come before the arrays to avoid
>>           * incoming data possibly overflowing the array.
>>           */
>> diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
>> index b1db672..aeb2538 100644
>> --- a/target-arm/op_helper.c
>> +++ b/target-arm/op_helper.c
>> @@ -349,7 +349,7 @@ void HELPER(msr_i_pstate)(CPUARMState *env, uint32_t op, uint32_t imm)
>>
>>      switch (op) {
>>      case 0x05: /* SPSel */
>> -        env->pstate = deposit32(env->pstate, 0, 1, imm);
>> +        update_spsel(env, imm);
>>          break;
>>      case 0x1e: /* DAIFSet */
>>          env->daif |= (imm << 6) & PSTATE_DAIF;
>> --
>> 1.9.0
>>
>>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps
  2014-03-17  3:05   ` Peter Crosthwaite
@ 2014-03-17 12:32     ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 12:32 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 03:05, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> For exceptions taken to AArch64, if a coprocessor/system register
>> access fails due to a trap or enable bit then the syndrome information
>> must include details of the failing instruction (crn/crm/opc1/opc2
>> fields, etc). Make the decoder construct the syndrome information
>> at translate time so it can be passed at runtime to the access-check
>> helper function and used as required.

> Can we space out the constants to a consistent tab stop for readability?

Sure.

>> -void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip)
>> +void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome)
>>  {
>>      const ARMCPRegInfo *ri = rip;
>>      switch (ri->accessfn(env, ri)) {
>>      case CP_ACCESS_OK:
>>          return;
>>      case CP_ACCESS_TRAP:
>> +        env->exception.syndrome = syndrome;
>
> Can TCG just deposit this directly and unconditionally straight to the
> env to avoid the extra syndrome arg?

Hmm. I think in theory that would be possible, but it seems
to me that it would be pretty confusing if exception.syndrome
could be set for anything other than "we're going to take an
exception and this is it". Passing the syndrome as a function
argument (probably in a register) seems better than always
doing a store to memory, as well. Or am I missing something that
would make it slower?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information
  2014-03-17  3:19   ` Peter Crosthwaite
@ 2014-03-17 12:40     ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 12:40 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 03:19, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> -static void gen_exception(int excp)
>> +static void gen_exception_internal(int excp)
>>  {
>> -    TCGv_i32 tmp = tcg_temp_new_i32();
>> -    tcg_gen_movi_i32(tmp, excp);
>> -    gen_helper_exception(cpu_env, tmp);
>> -    tcg_temp_free_i32(tmp);
>> +    TCGv_i32 tcg_excp = tcg_const_i32(excp);
>> +
>> +    assert(excp_is_internal(excp));
>> +    gen_helper_exception_internal(cpu_env, tcg_excp);
>> +    tcg_temp_free_i32(tcg_excp);
>> +}
>> +
>
> AFAICT this is identical to gen_exception_internal in translate-a64.c.
> Can they be de-static'd and prototyped in internals.h?

This is true, but it would break the current situation we
have where translate.c and translate-a64.c are entirely
independent and you never have to worry about breaking
one if you make changes to the other, which is why I didn't
do it. Maybe that's not very important, but it didn't seem
worth going against for the sake of a couple of helpers just
a few lines long. (If we do make them common then translate.h
would be the right place for the prototypes.)

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults
  2014-03-17  3:28   ` Peter Crosthwaite
@ 2014-03-17 12:41     ` Peter Maydell
  2014-03-17 12:50       ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 12:41 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 03:28, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> From: Rob Herring <rob.herring@linaro.org>

>> +    /* Set bit 26 for exceptions with no change in EL */
>> +    if (arm_current_pl(env)) {
>> +        syn |= 1 << ARM_EL_EC_SHIFT;
>> +    }
>> +
>
> Perhaps in internals.h:
>
> #define ARM_EL_EC_SAME_LEVEL (1 << ARM_EL_EC_SHIFT)
>
> Then this becomes:
>
> syn |= ARM_EL_EC_SAME_LEVEL
>
> Then in internals.h you can be more self documenting with:
>
> EC_BREAKPOINT_SAME_EL = EC_BREAKPOINT | ARM_EL_EC_SAME_LEVEL

Yeah, seems reasonable.

-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults
  2014-03-17 12:41     ` Peter Maydell
@ 2014-03-17 12:50       ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 12:50 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 12:41, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 17 March 2014 03:28, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> From: Rob Herring <rob.herring@linaro.org>
>
>>> +    /* Set bit 26 for exceptions with no change in EL */
>>> +    if (arm_current_pl(env)) {
>>> +        syn |= 1 << ARM_EL_EC_SHIFT;
>>> +    }
>>> +
>>
>> Perhaps in internals.h:
>>
>> #define ARM_EL_EC_SAME_LEVEL (1 << ARM_EL_EC_SHIFT)
>>
>> Then this becomes:
>>
>> syn |= ARM_EL_EC_SAME_LEVEL
>>
>> Then in internals.h you can be more self documenting with:
>>
>> EC_BREAKPOINT_SAME_EL = EC_BREAKPOINT | ARM_EL_EC_SAME_LEVEL
>
> Yeah, seems reasonable.

On the other hand you can't define EC_BREAKPOINT_SAME_EL
like that, because the EC_ enum values aren't shifted.

Perhaps it would be better to have the syn_* functions for
the EC values which have SAME_EL versions (currently just
insn abort and data abort, since we don't implement any
of the hardware debug exceptions) have an extra parameter
bool same_el, and have the syn_ function OR in the extra bit.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register
  2014-03-17  5:13   ` Peter Crosthwaite
@ 2014-03-17 12:58     ` Peter Maydell
  2014-03-17 13:11       ` Peter Crosthwaite
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 12:58 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 05:13, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Suppress the ID_AA64DFR0_EL1 PMUVer field, even if the CPU specific
>> value claims that it exists. QEMU doesn't currently implement it,
>> and not advertising it prevents the guest from trying to use it
>> and getting UNDEFs on unimplemented registers.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
> Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>
>> ---
>> This is arguably a hack, but otherwise Linux tries to prod
>> half a dozen PMU sysregs.
>
> Not really. I think sane self-identification trumps dummy feature
> advertising. Although there is a consistency argument to be made, as
> to whether you should also wipe-out any other features advertised by
> this register and friends (e.g. should TraceVer be set?).

The lack of consistency is what makes it a hack :-) Generally
QEMU takes the approach of "report what the h/w reports even
if we don't implement it all"; "report what we provide even
if that's not the same values as h/w" would be a different
approach, but if we wanted that we'd need to do it consistently.
Still I think pragmatism wins out here.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers
  2014-03-17  5:20   ` Peter Crosthwaite
@ 2014-03-17 13:03     ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 13:03 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 05:20, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>  static const ARMCPRegInfo pmsav5_cp_reginfo[] = {
>>      { .name = "DATA_AP", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0,
>>        .access = PL1_RW, .type = ARM_CP_NO_MIGRATE,
>> -      .fieldoffset = offsetof(CPUARMState, cp15.c5_data), .resetvalue = 0,
>> +      .fieldoffset = offsetof(CPUARMState, cp15.pmsav5_data_ap),
>> +      .resetvalue = 0,
>
> I know its just motion of existing code, but what's the policy on zero
> resets? Can we leave them out for brevity? Checkpatch complains when a
> global is explictly 0 initialized, so it seems sane that the same rule
> applies to individual fields (just checkpatch probably has hard time
> figuring this one out).

The semantics allow you to leave out .resetvalue if it is 0; I think
generally when I've written reginfo definitions I've tended to put
in the .resetvalue as an indication of "I know this reginfo needs
a reset value and it is zero" as opposed to "I didn't think about
reset when I wrote this".

We definitely don't want checkpatch to warn about explicit zero
initializers in structs like this, otherwise we wouldn't be
able to say ".crm = 0, .opc1 = 0, .opc2 = 0", which would be
less comprehensible than writing them out explicitly I think.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers
  2014-03-17  5:30   ` Peter Crosthwaite
@ 2014-03-17 13:06     ` Peter Maydell
  2014-03-17 13:17       ` Peter Crosthwaite
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-03-17 13:06 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 05:30, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>>          env->exception.fsr = 2;
>>          /* Fall through to prefetch abort.  */
>>      case EXCP_PREFETCH_ABORT:
>> -        env->cp15.c5_insn = env->exception.fsr;
>> -        env->cp15.c6_insn = env->exception.vaddress;
>> +        env->cp15.ifsr_el2 = env->exception.fsr;
>> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
>> +                                      env->exception.vaddress);
>
> Is it better to just grab the CPRegInfo and pass it to raw_write() to
> do the deposit dirty work?

You'd have to do a hash-table lookup and it would be an odd
case compared to the other registers we update here, so I think
just directly depositing to the state field is simpler.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register
  2014-03-17 12:58     ` Peter Maydell
@ 2014-03-17 13:11       ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17 13:11 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	qemu-devel@nongnu.org Developers, Alexander Graf, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
	Christoffer Dall, Richard Henderson

On Mon, Mar 17, 2014 at 10:58 PM, Peter Maydell
<peter.maydell@linaro.org> wrote:
> On 17 March 2014 05:13, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> Suppress the ID_AA64DFR0_EL1 PMUVer field, even if the CPU specific
>>> value claims that it exists. QEMU doesn't currently implement it,
>>> and not advertising it prevents the guest from trying to use it
>>> and getting UNDEFs on unimplemented registers.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>
>> Reviewed-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>>
>>> ---
>>> This is arguably a hack, but otherwise Linux tries to prod
>>> half a dozen PMU sysregs.
>>
>> Not really. I think sane self-identification trumps dummy feature
>> advertising. Although there is a consistency argument to be made, as
>> to whether you should also wipe-out any other features advertised by
>> this register and friends (e.g. should TraceVer be set?).
>
> The lack of consistency is what makes it a hack :-) Generally
> QEMU takes the approach of "report what the h/w reports even
> if we don't implement it all"; "report what we provide even
> if that's not the same values as h/w" would be a different
> approach, but if we wanted that we'd need to do it consistently.

I think there is an argument to decide it case by case ..

> Still I think pragmatism wins out here.
>

In cases where QEMU can validly nop the feature in question (like
caches etc.) then faking up to match real HW is cool. But if a guest
can take a feature advertisment then if() on it to bang on
non-existant hardware causing bus errors or exceptions then I think we
should remove the advertisements even if it is a deviation from real
hw register state. Supporting a good guest that has self identificaton
correct seems more worthwhile than support a guest that somehow
requires a feature advertisment without actually using the feature.

Regards,
Peter

> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers
  2014-03-17 13:06     ` Peter Maydell
@ 2014-03-17 13:17       ` Peter Crosthwaite
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Crosthwaite @ 2014-03-17 13:17 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	qemu-devel@nongnu.org Developers, Alexander Graf, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
	Christoffer Dall, Richard Henderson

On Mon, Mar 17, 2014 at 11:06 PM, Peter Maydell
<peter.maydell@linaro.org> wrote:
> On 17 March 2014 05:30, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Fri, Mar 7, 2014 at 5:32 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> @@ -2979,20 +2988,23 @@ void arm_cpu_do_interrupt(CPUState *cs)
>>>          env->exception.fsr = 2;
>>>          /* Fall through to prefetch abort.  */
>>>      case EXCP_PREFETCH_ABORT:
>>> -        env->cp15.c5_insn = env->exception.fsr;
>>> -        env->cp15.c6_insn = env->exception.vaddress;
>>> +        env->cp15.ifsr_el2 = env->exception.fsr;
>>> +        env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
>>> +                                      env->exception.vaddress);
>>
>> Is it better to just grab the CPRegInfo and pass it to raw_write() to
>> do the deposit dirty work?
>
> You'd have to do a hash-table lookup and it would be an odd
> case compared to the other registers we update here, so I think
> just directly depositing to the state field is simpler.
>

OK fair enough. I was thinking just pass the & of static const
CPRegInfo (if its even visible here) rather than doing a lookup. But
then I spose you have a preformatted CPRegInfo that may or may not be
correct.

FWIW I know you dislike unions, but it would solve this one. In
general its verbose and cumbersome, but I think its applicable to the
ones where you have wierd register sharing policys (like the somewhat
numerically unrealted IFAR and DFAR being high and low words of FAR).

Regards,
Peter

> thanks
> -- PMM
>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1
  2014-03-17  7:02   ` Peter Crosthwaite
  2014-03-17  7:31     ` Peter Crosthwaite
@ 2014-03-20 17:12     ` Peter Maydell
  1 sibling, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-20 17:12 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 07:02, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Implement handling for the AArch64 SP_EL0 system register.
>> This holds the EL0 stack pointer, and is only accessible when
>> it's not being used as the stack pointer, ie when we're in EL1
>> and EL1 is using its own stack pointer. We also provide a
>> definition of the SP_EL1 register; this isn't guest visible
>> as a system register for an implementation like QEMU which
>> doesn't provide EL2 or EL3; however it is useful for ensuring
>> the underlying state is migrated.
>>
>> We need to update the state fields in the CPU state whenever
>
> "whenever we".

Fixed, thanks.

>> switch stack pointers; this happens when we take an exception
>> and also when SPSEL is used to change the bit in PSTATE which
>> indicates which stack pointer EL1 should use.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>>  target-arm/cpu.h       |  2 ++
>>  target-arm/helper.c    | 34 ++++++++++++++++++++++++++++++++++
>>  target-arm/internals.h | 25 +++++++++++++++++++++++++
>>  target-arm/kvm64.c     | 37 ++++++++++++++++++++++++++++++++++---
>>  target-arm/machine.c   |  7 ++++---
>>  target-arm/op_helper.c |  2 +-
>>  6 files changed, 100 insertions(+), 7 deletions(-)
>>
>> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
>> index 7ef2c71..338edc3 100644
>> --- a/target-arm/cpu.h
>> +++ b/target-arm/cpu.h
>> @@ -163,6 +163,7 @@ typedef struct CPUARMState {
>>      uint64_t daif; /* exception masks, in the bits they are in in PSTATE */
>>
>>      uint64_t elr_el1; /* AArch64 ELR_EL1 */
>> +    uint64_t sp_el[2]; /* AArch64 banked stack pointers */
>>
>
> Should the macro AARCH64_MAX_EL_LEVELS exist for this?

I'm not really convinced, because the set of things that
would need to change to make the maximum EL not 1 would
be so huge that one array size more or less is not really
very relevant. This seems to me like the kind of thing that
will shake itself out when somebody gets round to adding
EL2 or EL3 emulation support.

>>  const VMStateDescription vmstate_arm_cpu = {
>>      .name = "cpu",
>> -    .version_id = 15,
>> -    .minimum_version_id = 15,
>> -    .minimum_version_id_old = 15,
>> +    .version_id = 16,
>> +    .minimum_version_id = 16,
>> +    .minimum_version_id_old = 16,
>
> So in the past, I have squashed unrelated patches together to minimise
> VMSD versions bumps. Whats more important - these versions numbers of
> git patch separation?

We have an entire 32 bit integer to work with for the ID
numbers, so there's no reason to make patches harder to
review by squashing together things that would be clearer
handled separately.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support
  2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support Peter Maydell
@ 2014-03-20 18:20   ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-20 18:20 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Laurent Desnogues, Dirk Mueller, Will Newton, kvmarm,
	Richard Henderson

On 6 March 2014 19:32, Peter Maydell <peter.maydell@linaro.org> wrote:
> @@ -1065,8 +1065,9 @@ static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>   */
>  static inline bool extended_addresses_enabled(CPUARMState *env)
>  {
> -    return arm_feature(env, ARM_FEATURE_LPAE)
> -        && (env->cp15.c2_control & (1U << 31));
> +    return arm_feature(env, ARM_FEATURE_V8)
> +        || (arm_feature(env, ARM_FEATURE_LPAE)
> +        && (env->cp15.c2_control & (1U << 31)));
>  }

Just noticed a minor nit here -- rather than checking
for ARM_FEATURE_V8 we should be using arm_el_is_aa64(env, 1)
(as the translation code itself does). At the moment the
two give the same answer, but if/when we ever support
running a 32 bit kernel on an ARMv8 CPU they'll be
different, so better to get the check right to start with.

I'll fix this for the next round of these patches
(and also update the now out of date comment).

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor Peter Maydell
@ 2014-03-20 19:18   ` Peter Maydell
  2014-03-26  2:34   ` Rob Herring
  1 sibling, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-03-20 19:18 UTC (permalink / raw)
  To: QEMU Developers
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	Claudio Fontana, Alexander Graf, Laurent Desnogues, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On 6 March 2014 19:33, Peter Maydell <peter.maydell@linaro.org> wrote:
> Add Cortex-A57 processor.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

> +static void aarch64_a57_initfn(Object *obj)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +
> +    set_feature(&cpu->env, ARM_FEATURE_V8);
> +    set_feature(&cpu->env, ARM_FEATURE_VFP4);
> +    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
> +    set_feature(&cpu->env, ARM_FEATURE_NEON);
> +    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);

This last one should be removed, since Thumb2EE is
not present in ARMv8.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor
  2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor Peter Maydell
  2014-03-20 19:18   ` Peter Maydell
@ 2014-03-26  2:34   ` Rob Herring
  1 sibling, 0 replies; 58+ messages in thread
From: Rob Herring @ 2014-03-26  2:34 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Peter Crosthwaite, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, QEMU Developers, Will Newton, Dirk Mueller,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Thu, Mar 6, 2014 at 1:33 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Add Cortex-A57 processor.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu64.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 43 insertions(+)
>
> diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
> index d4fb1de..cbdf7ed 100644
> --- a/target-arm/cpu64.c
> +++ b/target-arm/cpu64.c
> @@ -32,6 +32,48 @@ static inline void set_feature(CPUARMState *env, int feature)
>      env->features |= 1ULL << feature;
>  }
>
> +static void aarch64_a57_initfn(Object *obj)
> +{
> +    ARMCPU *cpu = ARM_CPU(obj);
> +
> +    set_feature(&cpu->env, ARM_FEATURE_V8);
> +    set_feature(&cpu->env, ARM_FEATURE_VFP4);
> +    set_feature(&cpu->env, ARM_FEATURE_VFP_FP16);
> +    set_feature(&cpu->env, ARM_FEATURE_NEON);
> +    set_feature(&cpu->env, ARM_FEATURE_THUMB2EE);
> +    set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
> +    set_feature(&cpu->env, ARM_FEATURE_AARCH64);
> +    cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57;
> +    cpu->midr = 0x411fd070;
> +    cpu->reset_fpsid = 0x41034070;
> +    cpu->mvfr0 = 0x10110222;
> +    cpu->mvfr1 = 0x12111111;
> +    cpu->ctr = 0x8444c004;
> +    cpu->reset_sctlr = 0x00c50838;
> +    cpu->id_pfr0 = 0x00000131;
> +    cpu->id_pfr1 = 0x00011011;
> +    cpu->id_dfr0 = 0x03010066;
> +    cpu->id_afr0 = 0x00000000;
> +    cpu->id_mmfr0 = 0x10101105;
> +    cpu->id_mmfr1 = 0x40000000;
> +    cpu->id_mmfr2 = 0x01260000;
> +    cpu->id_mmfr3 = 0x02102211;
> +    cpu->id_isar0 = 0x02101110;
> +    cpu->id_isar1 = 0x13112111;
> +    cpu->id_isar2 = 0x21232042;
> +    cpu->id_isar3 = 0x01112131;
> +    cpu->id_isar4 = 0x00011142;

Need to add id_isar5 here. 0x00010001 is the correct value with no
crypto extensions.

Rob

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57
  2014-03-17  7:12   ` Peter Crosthwaite
@ 2014-04-10 15:02     ` Peter Maydell
  2014-04-10 19:41       ` Rob Herring
  0 siblings, 1 reply; 58+ messages in thread
From: Peter Maydell @ 2014-04-10 15:02 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Rob Herring, Patch Tracking, Michael Matz, Claudio Fontana,
	Alexander Graf, qemu-devel@nongnu.org Developers,
	Laurent Desnogues, Dirk Mueller, Will Newton, Alex Bennée,
	kvmarm, Christoffer Dall, Richard Henderson

On 17 March 2014 07:12, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> Support the Cortex-A57 in the virt machine model.
>>
>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>> ---
>> This should perhaps not be just stealing the a15mpcore_priv
>> on the basis that it's a GICv2...
>
> Wont this mean you gets lots of extraneous hardware? Although, with a
> pure virtual machine I guess you can do whatever you really want.

No, a15mpcore_priv only has a GIC in it.

>> ---
>>  hw/arm/virt.c | 8 ++++++++
>>  1 file changed, 8 insertions(+)
>>
>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>> index 517f2fe..d985d2e 100644
>> --- a/hw/arm/virt.c
>> +++ b/hw/arm/virt.c
>> @@ -123,6 +123,14 @@ static VirtBoardInfo machines[] = {
>>          .irqmap = a15irqmap,
>>      },
>>      {
>> +        .cpu_model = "cortex-a57",
>> +        /* Use the A15 private peripheral model for now: probably wrong! */
>> +        .qdevname = "a15mpcore_priv",
>
> Can you just change this to gics qdev name? The qdev propnames of gic
> and mpcore ("num-cpu" and "num-irq") should just match. Then perhaps a
> little callback to set gicv2 version property.

That would miss the other thing a15mpcore_priv does for us,
which is to wire up the generic timer outputs from the CPU
objects to the appropriate GIC inputs. (Also the gpio_in
lines on a15mpcore_priv and the gic itself are not the
same: a15mpcore_priv only exposise the SPIs.)

We could in theory write an a57mpcore_priv which was a
carbon copy of a15mpcore_priv, but that seems a bit pointless.
I think it's probably actually reasonable to use a15mpcore_priv
here, with an appropriate comment:

    /* Our A57 has an A15-style GICv2, so we can use a15mpcore_priv */

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57
  2014-04-10 15:02     ` Peter Maydell
@ 2014-04-10 19:41       ` Rob Herring
  2014-04-10 21:16         ` Peter Maydell
  0 siblings, 1 reply; 58+ messages in thread
From: Rob Herring @ 2014-04-10 19:41 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	qemu-devel@nongnu.org Developers, Will Newton, Dirk Mueller,
	Laurent Desnogues, kvmarm, Richard Henderson

On Thu, Apr 10, 2014 at 10:02 AM, Peter Maydell
<peter.maydell@linaro.org> wrote:
> On 17 March 2014 07:12, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Fri, Mar 7, 2014 at 5:33 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> Support the Cortex-A57 in the virt machine model.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>> This should perhaps not be just stealing the a15mpcore_priv
>>> on the basis that it's a GICv2...
>>
>> Wont this mean you gets lots of extraneous hardware? Although, with a
>> pure virtual machine I guess you can do whatever you really want.
>
> No, a15mpcore_priv only has a GIC in it.
>
>>> ---
>>>  hw/arm/virt.c | 8 ++++++++
>>>  1 file changed, 8 insertions(+)
>>>
>>> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
>>> index 517f2fe..d985d2e 100644
>>> --- a/hw/arm/virt.c
>>> +++ b/hw/arm/virt.c
>>> @@ -123,6 +123,14 @@ static VirtBoardInfo machines[] = {
>>>          .irqmap = a15irqmap,
>>>      },
>>>      {
>>> +        .cpu_model = "cortex-a57",
>>> +        /* Use the A15 private peripheral model for now: probably wrong! */
>>> +        .qdevname = "a15mpcore_priv",
>>
>> Can you just change this to gics qdev name? The qdev propnames of gic
>> and mpcore ("num-cpu" and "num-irq") should just match. Then perhaps a
>> little callback to set gicv2 version property.
>
> That would miss the other thing a15mpcore_priv does for us,
> which is to wire up the generic timer outputs from the CPU
> objects to the appropriate GIC inputs. (Also the gpio_in
> lines on a15mpcore_priv and the gic itself are not the
> same: a15mpcore_priv only exposise the SPIs.)
>
> We could in theory write an a57mpcore_priv which was a
> carbon copy of a15mpcore_priv, but that seems a bit pointless.
> I think it's probably actually reasonable to use a15mpcore_priv
> here, with an appropriate comment:
>
>     /* Our A57 has an A15-style GICv2, so we can use a15mpcore_priv */

I think there are 3 possibilities of what actual h/w may look like. i
agree this is the correct thing to do for one case (and is the only
one qemu is able to support today). The others are:

A57 + SBSA compliant GICv2(M)
A57 + GICv3

The SBSA change is making each register bank within the GIC 64K spaced
instead of 4K spaced to support 64KB pages in OSs and hypervisors.
This is a simple address swizzling trick defined in the SBSA doc.
(Since it's documented it must not be a cute embedded nonsense hack.
:)) Then the M portion is for PCI MSI support which is optional.

Rob

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57
  2014-04-10 19:41       ` Rob Herring
@ 2014-04-10 21:16         ` Peter Maydell
  0 siblings, 0 replies; 58+ messages in thread
From: Peter Maydell @ 2014-04-10 21:16 UTC (permalink / raw)
  To: Rob Herring
  Cc: Rob Herring, Peter Crosthwaite, Patch Tracking, Michael Matz,
	qemu-devel@nongnu.org Developers, Will Newton, Dirk Mueller,
	Laurent Desnogues, kvmarm, Richard Henderson

On 10 April 2014 20:41, Rob Herring <robherring2@gmail.com> wrote:
> On Thu, Apr 10, 2014 at 10:02 AM, Peter Maydell
> <peter.maydell@linaro.org> wrote:
>> We could in theory write an a57mpcore_priv which was a
>> carbon copy of a15mpcore_priv, but that seems a bit pointless.
>> I think it's probably actually reasonable to use a15mpcore_priv
>> here, with an appropriate comment:
>>
>>     /* Our A57 has an A15-style GICv2, so we can use a15mpcore_priv */
>
> I think there are 3 possibilities of what actual h/w may look like. i
> agree this is the correct thing to do for one case (and is the only
> one qemu is able to support today). The others are:
>
> A57 + SBSA compliant GICv2(M)
> A57 + GICv3
>
> The SBSA change is making each register bank within the GIC 64K spaced
> instead of 4K spaced to support 64KB pages in OSs and hypervisors.

That part is pretty easy to do in QEMU -- we'd just need a suitable
container object that mapped the GIC regions in different locations.
It might be worth doing that now rather than putting this in and
then changing it later.

> This is a simple address swizzling trick defined in the SBSA doc.
> (Since it's documented it must not be a cute embedded nonsense hack.
> :)) Then the M portion is for PCI MSI support which is optional.

I haven't looked too closely at the GICv2M spec but it probably
is not too hard (certainly in comparison to the v3 GIC ;-))

thanks
-- PMM

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2014-04-10 21:17 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-06 19:32 [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 01/21] target-arm: Split out private-to-target functions into internals.h Peter Maydell
2014-03-17  7:13   ` Peter Crosthwaite
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 02/21] target-arm: Implement AArch64 DAIF system register Peter Maydell
2014-03-17  2:30   ` Peter Crosthwaite
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 03/21] target-arm: Define exception record for AArch64 exceptions Peter Maydell
2014-03-17  2:53   ` Peter Crosthwaite
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 04/21] target-arm: Provide correct syndrome information for cpreg access traps Peter Maydell
2014-03-17  3:05   ` Peter Crosthwaite
2014-03-17 12:32     ` Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 05/21] target-arm: Add support for generating exceptions with syndrome information Peter Maydell
2014-03-17  3:19   ` Peter Crosthwaite
2014-03-17 12:40     ` Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 06/21] target-arm: Provide syndrome information for MMU faults Peter Maydell
2014-03-17  3:28   ` Peter Crosthwaite
2014-03-17 12:41     ` Peter Maydell
2014-03-17 12:50       ` Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 07/21] target-arm: A64: Correctly fault FP/Neon if CPACR.FPEN set Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 08/21] target-arm: A64: Add assertion that FP access was checked Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 09/21] target-arm: Fix VFP enables for AArch32 EL0 under AArch64 EL1 Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 10/21] target-arm: Add v8 mmu translation support Peter Maydell
2014-03-20 18:20   ` Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 11/21] target-arm: Don't mention PMU in debug feature register Peter Maydell
2014-03-17  5:13   ` Peter Crosthwaite
2014-03-17 12:58     ` Peter Maydell
2014-03-17 13:11       ` Peter Crosthwaite
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 12/21] target-arm: A64: Implement DC ZVA Peter Maydell
2014-03-07 14:51   ` Richard Henderson
2014-03-07 15:11     ` Peter Maydell
2014-03-07 15:25       ` Richard Henderson
2014-03-07 15:40       ` Richard Henderson
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 13/21] target-arm: Use dedicated CPU state fields for ARM946 access bit registers Peter Maydell
2014-03-17  5:20   ` Peter Crosthwaite
2014-03-17 13:03     ` Peter Maydell
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 14/21] target-arm: Implement AArch64 views of fault status and data registers Peter Maydell
2014-03-17  5:30   ` Peter Crosthwaite
2014-03-17 13:06     ` Peter Maydell
2014-03-17 13:17       ` Peter Crosthwaite
2014-03-06 19:32 ` [Qemu-devel] [PATCH v4 15/21] target-arm: Add AArch64 ELR_EL1 register Peter Maydell
2014-03-17  5:33   ` Peter Crosthwaite
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 16/21] target-arm: Implement SP_EL0, SP_EL1 Peter Maydell
2014-03-17  7:02   ` Peter Crosthwaite
2014-03-17  7:31     ` Peter Crosthwaite
2014-03-20 17:12     ` Peter Maydell
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 17/21] target-arm: Implement AArch64 SPSR_EL1 Peter Maydell
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 18/21] target-arm: Move arm_log_exception() into internals.h Peter Maydell
2014-03-17  7:04   ` Peter Crosthwaite
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 19/21] target-arm: Implement AArch64 EL1 exception handling Peter Maydell
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 20/21] target-arm: Add Cortex-A57 processor Peter Maydell
2014-03-20 19:18   ` Peter Maydell
2014-03-26  2:34   ` Rob Herring
2014-03-06 19:33 ` [Qemu-devel] [PATCH v4 21/21] hw/arm/virt: Add support for Cortex-A57 Peter Maydell
2014-03-17  7:12   ` Peter Crosthwaite
2014-04-10 15:02     ` Peter Maydell
2014-04-10 19:41       ` Rob Herring
2014-04-10 21:16         ` Peter Maydell
2014-03-07  4:09 ` [Qemu-devel] [PATCH v4 00/21] AArch64 system emulation (boots a kernel!) Xuebing Wang
2014-03-07  8:47   ` Peter Maydell

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.