All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd
@ 2013-12-22 22:49 Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair Peter Maydell
                   ` (24 more replies)
  0 siblings, 25 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Hi; this is the second version of a64-third-fourth-set, which
implements support for more or less all A64 instructions except
 * FP [we support simple FP register load/store and
   transfer to/from the general purpose registers]
 * Neon
 * system instructions (either ones only available to system
   mode or which only make sense for system mode like LDRT)
(There may also be one or two obscure gaps like the CRC32 instruction.)

Changes v1->v2:
 * finally got the ld/st pair decode correct
 * cleaned up the other ld/st decode to use extract32 rather than bitops
 * special case the simple-multiply in 3-src data ops
 * move set_pc in mrs/msr down to the end-of-loop handling
 * fix use of tcg temp over bblk end and possible gcc warning in cond-compare
 * use new qemu ld ops in ldst excl
 * revised version of sysregs support:
   + new .state field to specify whether register is AA64, AA32 or both
   + support shared register definitions between both states
   + new patch pulling the inner loop body of the 'define a reginfo'
     function out into its own function, for clarity
   + move the AA64 TLS register definitions to be together with the AA32
     ones rather than in a completely different part of the file
 * added a couple of minor bugfixes to aarch64 linux-user support found
   in testing (the clone bugfix in particular is necessary for fork())
 * added a patch to add the aarch64 targets to the travis test matrix

(That looks like a long list but it's mostly minor stuff apart from
the adjustments to sysregs support.)

This patchset sits on top of upstream master (yay); git tree
available at:
 git://git.linaro.org/people/peter.maydell/qemu-arm.git a64-third-fourth-set
web UI:
 https://git.linaro.org/people/peter.maydell/qemu-arm.git/shortlog/refs/heads/a64-third-fourth-set

(My plan for the next patchset is basically "softfloat
fixes and all of FP"; we have working and tested code
that basically just needs a touch more cleanup.)

thanks
-- PMM

Alex Bennée (6):
  target-arm: A64: add support for ld/st unsigned imm
  target-arm: A64: add support for ld/st with reg offset
  target-arm: A64: add support for ld/st with index
  target-arm: A64: add support for add, addi, sub, subi
  target-arm: A64: add support for move wide instructions
  .travis.yml: Add aarch64-* targets

Alexander Graf (3):
  target-arm: A64: add support for 3 src data proc insns
  target-arm: A64: implement SVC, BRK
  target-arm: aarch64: add support for ld lit

Claudio Fontana (3):
  target-arm: A64: add support for add/sub with carry
  target-arm: A64: add support for conditional compare insns
  linux-user: AArch64: define TARGET_CLONE_BACKWARDS

Michael Matz (1):
  target-arm: A64: support for ld/st/cl exclusive

Peter Maydell (11):
  target-arm: A64: add support for ld/st pair
  target-arm: A64: Add decoder skeleton for FP instructions
  target-arm: A64: implement FMOV
  target-arm: Pull "add one cpreg to hashtable" into its own function
  target-arm: Update generic cpreg code for AArch64
  target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder
  target-arm: A64: Implement MRS/MSR/SYS/SYSL
  target-arm: A64: Implement minimal set of EL0-visible sysregs
  target-arm: Widen thread-local register state fields to 64 bits
  target-arm: Widen exclusive-access support struct fields to 64 bits
  default-configs: Add config for aarch64-linux-user

Will Newton (1):
  linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext

 .travis.yml                            |    1 +
 default-configs/aarch64-linux-user.mak |    3 +
 linux-user/aarch64/syscall.h           |    1 +
 linux-user/aarch64/target_cpu.h        |    5 +-
 linux-user/arm/target_cpu.h            |    2 +-
 linux-user/main.c                      |  154 ++-
 linux-user/signal.c                    |   10 +-
 target-arm/cpu.h                       |  109 +-
 target-arm/helper.c                    |  284 ++++-
 target-arm/kvm-consts.h                |   37 +
 target-arm/machine.c                   |   12 +-
 target-arm/translate-a64.c             | 1949 ++++++++++++++++++++++++++++++--
 target-arm/translate.c                 |   72 +-
 target-arm/translate.h                 |    2 +
 14 files changed, 2439 insertions(+), 202 deletions(-)
 create mode 100644 default-configs/aarch64-linux-user.mak

-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-23 19:49   ` Richard Henderson
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 02/25] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
                   ` (23 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

This patch support the basic load and store pair instructions and
includes the generic helper functions:

  * do_gpr_st()
  * do_fp_st()
  * do_gpr_ld()
  * do_fp_ld()
  * read_cpu_reg_sp()
  * gen_check_sp_alignment()

The last function gen_check_sp_alignment() is a NULL op currently but
put in place to make it easy to add SP alignment checking later.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 279 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 277 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0a76130..0c3b994 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -99,6 +99,15 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
     cpu_fprintf(f, "\n");
 }
 
+static int get_mem_index(DisasContext *s)
+{
+#ifdef CONFIG_USER_ONLY
+    return 1;
+#else
+    return s->user;
+#endif
+}
+
 void gen_a64_set_pc_im(uint64_t val)
 {
     tcg_gen_movi_i64(cpu_pc, val);
@@ -250,6 +259,17 @@ static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
     return v;
 }
 
+static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
+{
+    TCGv_i64 v = new_tmp_a64(s);
+    if (sf) {
+        tcg_gen_mov_i64(v, cpu_X[reg]);
+    } else {
+        tcg_gen_ext32u_i64(v, cpu_X[reg]);
+    }
+    return v;
+}
+
 /* Set ZF and NF based on a 64 bit result. This is alas fiddlier
  * than the 32 bit equivalent.
  */
@@ -278,6 +298,126 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
 }
 
 /*
+ * Load/Store generators
+ */
+
+/*
+ * Store from GPR register to memory
+ */
+static void do_gpr_st(DisasContext *s, TCGv_i64 source,
+                      TCGv_i64 tcg_addr, int size)
+{
+    g_assert(size <= 3);
+    tcg_gen_qemu_st_i64(source, tcg_addr, get_mem_index(s), MO_TE + size);
+}
+
+/*
+ * Load from memory to GPR register
+ */
+static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
+                      int size, bool is_signed, bool extend)
+{
+    TCGMemOp memop = MO_TE + size;
+
+    g_assert(size <= 3);
+
+    if (is_signed) {
+        memop += MO_SIGN;
+    }
+
+    tcg_gen_qemu_ld_i64(dest, tcg_addr, get_mem_index(s), memop);
+
+    if (extend && is_signed) {
+        g_assert(size < 3);
+        tcg_gen_ext32u_i64(dest, dest);
+    }
+}
+
+/*
+ * Store from FP register to memory
+ */
+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 */
+    int freg_offs = offsetof(CPUARMState, vfp.regs[srcidx * 2]);
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    if (size < 4) {
+        switch (size) {
+        case 0:
+            tcg_gen_ld8u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 1:
+            tcg_gen_ld16u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 2:
+            tcg_gen_ld32u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 3:
+            tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
+            break;
+        }
+        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_ld_i64(tmp, cpu_env, freg_offs);
+        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, freg_offs + sizeof(float64));
+        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);
+    }
+
+    tcg_temp_free_i64(tmp);
+}
+
+/*
+ * Load from memory to FP register
+ */
+static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
+{
+    /* This always zero-extends and writes to a full 128 bit wide vector */
+    int freg_offs = offsetof(CPUARMState, vfp.regs[destidx * 2]);
+    TCGv_i64 tmplo = tcg_temp_new_i64();
+    TCGv_i64 tmphi;
+
+    if (size < 4) {
+        TCGMemOp memop = MO_TE + size;
+        tmphi = tcg_const_i64(0);
+        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
+    } else {
+        TCGv_i64 tcg_hiaddr;
+        tmphi = tcg_temp_new_i64();
+        tcg_hiaddr = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
+        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
+        tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
+        tcg_temp_free_i64(tcg_hiaddr);
+    }
+
+    tcg_gen_st_i64(tmplo, cpu_env, freg_offs);
+    tcg_gen_st_i64(tmphi, cpu_env, freg_offs + sizeof(float64));
+
+    tcg_temp_free_i64(tmplo);
+    tcg_temp_free_i64(tmphi);
+}
+
+static inline void gen_check_sp_alignment(DisasContext *s)
+{
+    /* The AArch64 architecture mandates that (if enabled via PSTATE
+     * or SCTLR bits) there is a check that SP is 16-aligned on every
+     * SP-relative load or store (with an exception generated if it is not).
+     * In line with general QEMU practice regarding misaligned accesses,
+     * we omit these checks for the sake of guest program performance.
+     * This function is provided as a hook so we can more easily add these
+     * checks in future (possibly as a "favour catching guest program bugs
+     * over speed" user selectable option).
+     */
+}
+
+/*
  * the instruction disassembly implemented here matches
  * the instruction encoding classifications in chapter 3 (C3)
  * of the ARM Architecture Reference Manual (DDI0487A_a)
@@ -620,10 +760,145 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
     unsupported_encoding(s, insn);
 }
 
-/* Load/store pair (all forms) */
+/*
+ * C5.6.80 LDNP (Load Pair - non-temporal hint)
+ * C5.6.81 LDP (Load Pair - non vector)
+ * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
+ * C5.6.176 STNP (Store Pair - non-temporal hint)
+ * C5.6.177 STP (Store Pair - non vector)
+ * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
+ * C6.3.165 LDP (Load Pair of SIMD&FP)
+ * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
+ * C6.3.284 STP (Store Pair of SIMD&FP)
+ *
+ *  31 30 29   27  26  25 24   23  22 21   15 14   10 9    5 4    0
+ * +-----+-------+---+---+-------+---+-----------------------------+
+ * | opc | 1 0 1 | V | 0 | index | L |  imm7 |  Rt2  |  Rn  | Rt   |
+ * +-----+-------+---+---+-------+---+-------+-------+------+------+
+ *
+ * opc: LDP/STP/LDNP/STNP        00 -> 32 bit, 10 -> 64 bit
+ *      LDPSW                    01
+ *      LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
+ *   V: 0 -> GPR, 1 -> Vector
+ * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
+ *      10 -> signed offset, 11 -> pre-index
+ *   L: 0 -> Store 1 -> Load
+ *
+ * Rt, Rt2 = GPR or SIMD registers to be stored
+ * Rn = general purpose register containing address
+ * imm7 = signed offset (multiple of 4 or 8 depending on size)
+ */
 static void disas_ldst_pair(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int rt2 = extract32(insn, 10, 5);
+    int64_t offset = sextract32(insn, 15, 7);
+    int index = extract32(insn, 23, 2);
+    bool is_vector = extract32(insn, 26, 1);
+    bool is_load = extract32(insn, 22, 1);
+    int opc = extract32(insn, 30, 2);
+
+    bool is_signed = false;
+    bool postindex = false;
+    bool wback = false;
+
+    TCGv_i64 tcg_addr; /* calculated address */
+    int size;
+
+    if (opc == 3) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (is_vector) {
+        size = 2 + opc;
+    } else {
+        size = 2 + extract32(opc, 1, 1);
+        is_signed = extract32(opc, 0, 1);
+        if (!is_load && is_signed) {
+            unallocated_encoding(s);
+            return;
+        }
+    }
+
+    switch (index) {
+    case 1: /* post-index */
+        postindex = true;
+        wback = true;
+        break;
+    case 0:
+        /* signed offset with "non-temporal" hint. Since we don't emulate
+         * caches we don't care about hints to the cache system about
+         * data access patterns, and handle this identically to plain
+         * signed offset.
+         */
+        if (is_signed) {
+            /* There is no non-temporal-hint version of LDPSW */
+            unallocated_encoding(s);
+            return;
+        }
+        postindex = false;
+        break;
+    case 2: /* signed offset, rn not updated */
+        postindex = false;
+        break;
+    case 3: /* pre-index */
+        postindex = false;
+        wback = true;
+        break;
+    }
+
+    offset <<= size;
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    if (!postindex) {
+        tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+    }
+
+    if (is_vector) {
+        if (is_load) {
+            do_fp_ld(s, rt, tcg_addr, size);
+        } else {
+            do_fp_st(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_load) {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
+        } else {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        }
+    }
+    tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
+    if (is_vector) {
+        if (is_load) {
+            do_fp_ld(s, rt2, tcg_addr, size);
+        } else {
+            do_fp_st(s, rt2, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
+        if (is_load) {
+            do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
+        } else {
+            do_gpr_st(s, tcg_rt2, tcg_addr, size);
+        }
+    }
+
+    if (wback) {
+        if (postindex) {
+            tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
+        } else {
+            tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
+        }
+        tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
+    }
 }
 
 /* Load/store register (all forms) */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 02/25] target-arm: A64: add support for ld/st unsigned imm
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 03/25] target-arm: A64: add support for ld/st with reg offset Peter Maydell
                   ` (22 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This adds support for the forms of ld/st with a 12 bit
unsigned immediate offset.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 89 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0c3b994..0edcee1 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -901,10 +901,97 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
     }
 }
 
+/*
+ * C3.3.13 Load/store (unsigned immediate)
+ *
+ * 31 30 29   27  26 25 24 23 22 21        10 9     5
+ * +----+-------+---+-----+-----+------------+-------+------+
+ * |size| 1 1 1 | V | 0 1 | opc |   imm12    |  Rn   |  Rt  |
+ * +----+-------+---+-----+-----+------------+-------+------+
+ *
+ * For non-vector:
+ *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
+ *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ * For vector:
+ *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
+ *   opc<0>: 0 -> store, 1 -> load
+ * Rn: base address register (inc SP)
+ * Rt: target register
+ */
+static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    unsigned int imm12 = extract32(insn, 10, 12);
+    bool is_vector = extract32(insn, 26, 1);
+    int size = extract32(insn, 30, 2);
+    int opc = extract32(insn, 22, 2);
+    unsigned int offset;
+
+    TCGv_i64 tcg_addr;
+
+    bool is_store;
+    bool is_signed = false;
+    bool is_extended = false;
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = !extract32(opc, 0, 1);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = extract32(opc, 1, 1);
+        is_extended = (size < 3) && extract32(opc, 0, 1);
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+    offset = imm12 << size;
+    tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+}
+
 /* Load/store register (all forms) */
 static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    switch (extract32(insn, 24, 2)) {
+    case 0:
+        unsupported_encoding(s, insn);
+        break;
+    case 1:
+        disas_ldst_reg_unsigned_imm(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* AdvSIMD load/store multiple structures */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 03/25] target-arm: A64: add support for ld/st with reg offset
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 02/25] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 04/25] target-arm: A64: add support for ld/st with index Peter Maydell
                   ` (21 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This adds support for the load/store forms using a register offset.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 144 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0edcee1..67efcf9 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -404,6 +404,54 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
     tcg_temp_free_i64(tmphi);
 }
 
+/*
+ * This utility function is for doing register extension with an
+ * optional shift. You will likely want to pass a temporary for the
+ * destination register. See DecodeRegExtend() in the ARM ARM.
+ */
+static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
+                              int option, unsigned int shift)
+{
+    int extsize = extract32(option, 0, 2);
+    bool is_signed = extract32(option, 2, 1);
+
+    if (is_signed) {
+        switch (extsize) {
+        case 0:
+            tcg_gen_ext8s_i64(tcg_out, tcg_in);
+            break;
+        case 1:
+            tcg_gen_ext16s_i64(tcg_out, tcg_in);
+            break;
+        case 2:
+            tcg_gen_ext32s_i64(tcg_out, tcg_in);
+            break;
+        case 3:
+            tcg_gen_mov_i64(tcg_out, tcg_in);
+            break;
+        }
+    } else {
+        switch (extsize) {
+        case 0:
+            tcg_gen_ext8u_i64(tcg_out, tcg_in);
+            break;
+        case 1:
+            tcg_gen_ext16u_i64(tcg_out, tcg_in);
+            break;
+        case 2:
+            tcg_gen_ext32u_i64(tcg_out, tcg_in);
+            break;
+        case 3:
+            tcg_gen_mov_i64(tcg_out, tcg_in);
+            break;
+        }
+    }
+
+    if (shift) {
+        tcg_gen_shli_i64(tcg_out, tcg_out, shift);
+    }
+}
+
 static inline void gen_check_sp_alignment(DisasContext *s)
 {
     /* The AArch64 architecture mandates that (if enabled via PSTATE
@@ -902,6 +950,96 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
 }
 
 /*
+ * C3.3.10 Load/store (register offset)
+ *
+ * 31 30 29   27  26 25 24 23 22 21  20  16 15 13 12 11 10 9  5 4  0
+ * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
+ * |size| 1 1 1 | V | 0 0 | opc | 1 |  Rm  | opt | S| 1 0 | Rn | Rt |
+ * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
+ *
+ * For non-vector:
+ *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
+ *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ * For vector:
+ *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
+ *   opc<0>: 0 -> store, 1 -> load
+ * V: 1 -> vector/simd
+ * opt: extend encoding (see DecodeRegExtend)
+ * S: if S=1 then scale (essentially index by sizeof(size))
+ * Rt: register to transfer into/out of
+ * Rn: address register or SP for base
+ * Rm: offset register or ZR for offset
+ */
+static void disas_ldst_reg_roffset(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int shift = extract32(insn, 12, 1);
+    int rm = extract32(insn, 16, 5);
+    int opc = extract32(insn, 22, 2);
+    int opt = extract32(insn, 13, 3);
+    int size = extract32(insn, 30, 2);
+    bool is_signed = false;
+    bool is_store = false;
+    bool is_extended = false;
+    bool is_vector = extract32(insn, 26, 1);
+
+    TCGv_i64 tcg_rm;
+    TCGv_i64 tcg_addr;
+
+    if (extract32(opt, 1, 1) == 0) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = !extract32(opc, 0, 1);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = extract32(opc, 1, 1);
+        is_extended = (size < 3) && extract32(opc, 0, 1);
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    tcg_rm = read_cpu_reg(s, rm, 1);
+    ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
+
+    tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+}
+
+/*
  * C3.3.13 Load/store (unsigned immediate)
  *
  * 31 30 29   27  26 25 24 23 22 21        10 9     5
@@ -983,7 +1121,11 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
     switch (extract32(insn, 24, 2)) {
     case 0:
-        unsupported_encoding(s, insn);
+        if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
+            disas_ldst_reg_roffset(s, insn);
+        } else {
+            unsupported_encoding(s, insn);
+        }
         break;
     case 1:
         disas_ldst_reg_unsigned_imm(s, insn);
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 04/25] target-arm: A64: add support for ld/st with index
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (2 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 03/25] target-arm: A64: add support for ld/st with reg offset Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 05/25] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
                   ` (20 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This adds support for the pre/post-index ld/st forms with immediate
offsets as well as the un-scaled immediate form (which are all
variations on the same 9-bit immediate instruction form).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 124 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 67efcf9..a2cc9f0 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -950,6 +950,110 @@ static void disas_ldst_pair(DisasContext *s, uint32_t insn)
 }
 
 /*
+ * C3.3.8 Load/store (immediate post-indexed)
+ * C3.3.9 Load/store (immediate pre-indexed)
+ * C3.3.12 Load/store (unscaled immediate)
+ *
+ * 31 30 29   27  26 25 24 23 22 21  20    12 11 10 9    5 4    0
+ * +----+-------+---+-----+-----+---+--------+-----+------+------+
+ * |size| 1 1 1 | V | 0 0 | opc | 0 |  imm9  | idx |  Rn  |  Rt  |
+ * +----+-------+---+-----+-----+---+--------+-----+------+------+
+ *
+ * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
+ * V = 0 -> non-vector
+ * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
+ * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ */
+static void disas_ldst_reg_imm9(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm9 = sextract32(insn, 12, 9);
+    int opc = extract32(insn, 22, 2);
+    int size = extract32(insn, 30, 2);
+    int idx = extract32(insn, 10, 2);
+    bool is_signed = false;
+    bool is_store = false;
+    bool is_extended = false;
+    bool is_vector = extract32(insn, 26, 1);
+    bool post_index;
+    bool writeback;
+
+    TCGv_i64 tcg_addr;
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = ((opc & 1) == 0);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = opc & (1<<1);
+        is_extended = (size < 3) && (opc & 1);
+    }
+
+    switch (idx) {
+    case 0:
+        post_index = false;
+        writeback = false;
+        break;
+    case 1:
+        post_index = true;
+        writeback = true;
+        break;
+    case 3:
+        post_index = false;
+        writeback = true;
+        break;
+    case 2:
+        g_assert(false);
+        break;
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    if (!post_index) {
+        tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
+    }
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+
+    if (writeback) {
+        TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
+        if (post_index) {
+            tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
+        }
+        tcg_gen_mov_i64(tcg_rn, tcg_addr);
+    }
+}
+
+/*
  * C3.3.10 Load/store (register offset)
  *
  * 31 30 29   27  26 25 24 23 22 21  20  16 15 13 12 11 10 9  5 4  0
@@ -1116,6 +1220,25 @@ static void disas_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
     }
 }
 
+/* Load/store register (immediate forms) */
+static void disas_ldst_reg_imm(DisasContext *s, uint32_t insn)
+{
+    switch (extract32(insn, 10, 2)) {
+    case 0: case 1: case 3:
+        /* Load/store register (unscaled immediate) */
+        /* Load/store immediate pre/post-indexed */
+        disas_ldst_reg_imm9(s, insn);
+        break;
+    case 2:
+        /* Load/store register unprivileged */
+        unsupported_encoding(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
+}
+
 /* Load/store register (all forms) */
 static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
@@ -1124,7 +1247,7 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
         if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
             disas_ldst_reg_roffset(s, insn);
         } else {
-            unsupported_encoding(s, insn);
+            disas_ldst_reg_imm(s, insn);
         }
         break;
     case 1:
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 05/25] target-arm: A64: add support for add, addi, sub, subi
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (3 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 04/25] target-arm: A64: add support for ld/st with index Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 06/25] target-arm: A64: add support for move wide instructions Peter Maydell
                   ` (19 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

Implement the non-carry forms of addition and subtraction
(immediate, extended register and shifted register).
This includes the code to calculate NZCV if the instruction
calls for setting the flags.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 292 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 286 insertions(+), 6 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index a2cc9f0..c0057a2 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -297,6 +297,102 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
     tcg_gen_movi_i32(cpu_VF, 0);
 }
 
+/* dest = T0 + T1; compute C, N, V and Z flags */
+static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    if (sf) {
+        TCGv_i64 result, flag, tmp;
+        result = tcg_temp_new_i64();
+        flag = tcg_temp_new_i64();
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_movi_i64(tmp, 0);
+        tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
+
+        tcg_gen_trunc_i64_i32(cpu_CF, flag);
+
+        gen_set_NZ64(result);
+
+        tcg_gen_xor_i64(flag, result, t0);
+        tcg_gen_xor_i64(tmp, t0, t1);
+        tcg_gen_andc_i64(flag, flag, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_gen_shri_i64(flag, flag, 32);
+        tcg_gen_trunc_i64_i32(cpu_VF, flag);
+
+        tcg_gen_mov_i64(dest, result);
+        tcg_temp_free_i64(result);
+        tcg_temp_free_i64(flag);
+    } else {
+        /* 32 bit arithmetic */
+        TCGv_i32 t0_32 = tcg_temp_new_i32();
+        TCGv_i32 t1_32 = tcg_temp_new_i32();
+        TCGv_i32 tmp = tcg_temp_new_i32();
+
+        tcg_gen_movi_i32(tmp, 0);
+        tcg_gen_trunc_i64_i32(t0_32, t0);
+        tcg_gen_trunc_i64_i32(t1_32, t1);
+        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
+        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
+        tcg_gen_xor_i32(tmp, t0_32, t1_32);
+        tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
+        tcg_gen_extu_i32_i64(dest, cpu_NF);
+
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(t0_32);
+        tcg_temp_free_i32(t1_32);
+    }
+}
+
+/* dest = T0 - T1; compute C, N, V and Z flags */
+static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    if (sf) {
+        /* 64 bit arithmetic */
+        TCGv_i64 result, flag, tmp;
+
+        result = tcg_temp_new_i64();
+        flag = tcg_temp_new_i64();
+        tcg_gen_sub_i64(result, t0, t1);
+
+        gen_set_NZ64(result);
+
+        tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
+        tcg_gen_trunc_i64_i32(cpu_CF, flag);
+
+        tcg_gen_xor_i64(flag, result, t0);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_xor_i64(tmp, t0, t1);
+        tcg_gen_and_i64(flag, flag, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_gen_shri_i64(flag, flag, 32);
+        tcg_gen_trunc_i64_i32(cpu_VF, flag);
+        tcg_gen_mov_i64(dest, result);
+        tcg_temp_free_i64(flag);
+        tcg_temp_free_i64(result);
+    } else {
+        /* 32 bit arithmetic */
+        TCGv_i32 t0_32 = tcg_temp_new_i32();
+        TCGv_i32 t1_32 = tcg_temp_new_i32();
+        TCGv_i32 tmp;
+
+        tcg_gen_trunc_i64_i32(t0_32, t0);
+        tcg_gen_trunc_i64_i32(t1_32, t1);
+        tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
+        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+        tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
+        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
+        tmp = tcg_temp_new_i32();
+        tcg_gen_xor_i32(tmp, t0_32, t1_32);
+        tcg_temp_free_i32(t0_32);
+        tcg_temp_free_i32(t1_32);
+        tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
+        tcg_temp_free_i32(tmp);
+        tcg_gen_extu_i32_i64(dest, cpu_NF);
+    }
+}
+
 /*
  * Load/Store generators
  */
@@ -1328,10 +1424,68 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
     tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
 }
 
-/* Add/subtract (immediate) */
+/*
+ * C3.4.1 Add/subtract (immediate)
+ *
+ *  31 30 29 28       24 23 22 21         10 9   5 4   0
+ * +--+--+--+-----------+-----+-------------+-----+-----+
+ * |sf|op| S| 1 0 0 0 1 |shift|    imm12    |  Rn | Rd  |
+ * +--+--+--+-----------+-----+-------------+-----+-----+
+ *
+ *    sf: 0 -> 32bit, 1 -> 64bit
+ *    op: 0 -> add  , 1 -> sub
+ *     S: 1 -> set flags
+ * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12
+ */
 static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    uint64_t imm = extract32(insn, 10, 12);
+    int shift = extract32(insn, 22, 2);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool is_64bit = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
+    TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
+    TCGv_i64 tcg_result;
+
+    switch (shift) {
+    case 0x0:
+        break;
+    case 0x1:
+        imm <<= 12;
+        break;
+    default:
+        unallocated_encoding(s);
+        return;
+    }
+
+    tcg_result = tcg_temp_new_i64();
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_subi_i64(tcg_result, tcg_rn, imm);
+        } else {
+            tcg_gen_addi_i64(tcg_result, tcg_rn, imm);
+        }
+    } else {
+        TCGv_i64 tcg_imm = tcg_const_i64(imm);
+        if (sub_op) {
+            gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
+        } else {
+            gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
+        }
+        tcg_temp_free_i64(tcg_imm);
+    }
+
+    if (is_64bit) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
 /* The input should be a value in the bottom e bits (with higher
@@ -1789,16 +1943,142 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Add/subtract (extended register) */
+/*
+ * C3.5.1 Add/subtract (extended register)
+ *
+ *  31|30|29|28       24|23 22|21|20   16|15  13|12  10|9  5|4  0|
+ * +--+--+--+-----------+-----+--+-------+------+------+----+----+
+ * |sf|op| S| 0 1 0 1 1 | opt | 1|  Rm   |option| imm3 | Rn | Rd |
+ * +--+--+--+-----------+-----+--+-------+------+------+----+----+
+ *
+ *  sf: 0 -> 32bit, 1 -> 64bit
+ *  op: 0 -> add  , 1 -> sub
+ *   S: 1 -> set flags
+ * opt: 00
+ * option: extension type (see DecodeRegExtend)
+ * imm3: optional shift to Rm
+ *
+ * Rd = Rn + LSL(extend(Rm), amount)
+ */
 static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm3 = extract32(insn, 10, 3);
+    int option = extract32(insn, 13, 3);
+    int rm = extract32(insn, 16, 5);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool sf = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rm, tcg_rn; /* temps */
+    TCGv_i64 tcg_rd;
+    TCGv_i64 tcg_result;
+
+    if (imm3 > 4) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    /* non-flag setting ops may use SP */
+    if (!setflags) {
+        tcg_rn = read_cpu_reg_sp(s, rn, sf);
+        tcg_rd = cpu_reg_sp(s, rd);
+    } else {
+        tcg_rn = read_cpu_reg(s, rn, sf);
+        tcg_rd = cpu_reg(s, rd);
+    }
+
+    tcg_rm = read_cpu_reg(s, rm, sf);
+    ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
+
+    tcg_result = tcg_temp_new_i64();
+
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
+        }
+    } else {
+        if (sub_op) {
+            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        } else {
+            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        }
+    }
+
+    if (sf) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
-/* Add/subtract (shifted register) */
+/*
+ * C3.5.2 Add/subtract (shifted register)
+ *
+ *  31 30 29 28       24 23 22 21 20   16 15     10 9    5 4    0
+ * +--+--+--+-----------+-----+--+-------+---------+------+------+
+ * |sf|op| S| 0 1 0 1 1 |shift| 0|  Rm   |  imm6   |  Rn  |  Rd  |
+ * +--+--+--+-----------+-----+--+-------+---------+------+------+
+ *
+ *    sf: 0 -> 32bit, 1 -> 64bit
+ *    op: 0 -> add  , 1 -> sub
+ *     S: 1 -> set flags
+ * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
+ *  imm6: Shift amount to apply to Rm before the add/sub
+ */
 static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm6 = extract32(insn, 10, 6);
+    int rm = extract32(insn, 16, 5);
+    int shift_type = extract32(insn, 22, 2);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool sf = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rd = cpu_reg(s, rd);
+    TCGv_i64 tcg_rn, tcg_rm;
+    TCGv_i64 tcg_result;
+
+    if ((shift_type == 3) || (!sf && (imm6 > 31))) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    tcg_rn = read_cpu_reg(s, rn, sf);
+    tcg_rm = read_cpu_reg(s, rm, sf);
+
+    shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
+
+    tcg_result = tcg_temp_new_i64();
+
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
+        }
+    } else {
+        if (sub_op) {
+            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        } else {
+            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        }
+    }
+
+    if (sf) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
 /* Data-processing (3 source) */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 06/25] target-arm: A64: add support for move wide instructions
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (4 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 05/25] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 07/25] target-arm: A64: add support for 3 src data proc insns Peter Maydell
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This patch adds emulation for the mov wide instructions
(MOVN, MOVZ, MOVK).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 51 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index c0057a2..dbc865a 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1644,10 +1644,57 @@ static void disas_logic_imm(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Move wide (immediate) */
+/*
+ * C3.4.5 Move wide (immediate)
+ *
+ *  31 30 29 28         23 22 21 20             5 4    0
+ * +--+-----+-------------+-----+----------------+------+
+ * |sf| opc | 1 0 0 1 0 1 |  hw |  imm16         |  Rd  |
+ * +--+-----+-------------+-----+----------------+------+
+ *
+ * sf: 0 -> 32 bit, 1 -> 64 bit
+ * opc: 00 -> N, 10 -> Z, 11 -> K
+ * hw: shift/16 (0,16, and sf only 32, 48)
+ */
 static void disas_movw_imm(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    uint64_t imm = extract32(insn, 5, 16);
+    int sf = extract32(insn, 31, 1);
+    int opc = extract32(insn, 29, 2);
+    int pos = extract32(insn, 21, 2) << 4;
+    TCGv_i64 tcg_rd = cpu_reg(s, rd);
+    TCGv_i64 tcg_imm;
+
+    if (!sf && (pos >= 32)) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    switch (opc) {
+    case 0: /* MOVN */
+    case 2: /* MOVZ */
+        imm <<= pos;
+        if (opc == 0) {
+            imm = ~imm;
+        }
+        if (!sf) {
+            imm &= 0xffffffffu;
+        }
+        tcg_gen_movi_i64(tcg_rd, imm);
+        break;
+    case 3: /* MOVK */
+        tcg_imm = tcg_const_i64(imm);
+        tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16);
+        tcg_temp_free_i64(tcg_imm);
+        if (!sf) {
+            tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+        }
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* C3.4.2 Bitfield
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 07/25] target-arm: A64: add support for 3 src data proc insns
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (5 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 06/25] target-arm: A64: add support for move wide instructions Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 08/25] target-arm: A64: implement SVC, BRK Peter Maydell
                   ` (17 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alexander Graf <agraf@suse.de>

This patch adds emulation for the "Data-processing (3 source)"
family of instructions, namely MADD, MSUB, SMADDL, SMSUBL, SMULH,
UMADDL, UMSUBL, UMULH.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 97 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index dbc865a..3a9ffdf 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2128,10 +2128,103 @@ static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_result);
 }
 
-/* Data-processing (3 source) */
+/* C3.5.9 Data-processing (3 source)
+
+   31 30  29 28       24 23 21  20  16  15  14  10 9    5 4    0
+  +--+------+-----------+------+------+----+------+------+------+
+  |sf| op54 | 1 1 0 1 1 | op31 |  Rm  | o0 |  Ra  |  Rn  |  Rd  |
+  +--+------+-----------+------+------+----+------+------+------+
+
+ */
 static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int ra = extract32(insn, 10, 5);
+    int rm = extract32(insn, 16, 5);
+    int op_id = (extract32(insn, 29, 3) << 4) |
+        (extract32(insn, 21, 3) << 1) |
+        extract32(insn, 15, 1);
+    bool sf = extract32(insn, 31, 1);
+    bool is_sub = extract32(op_id, 0, 1);
+    bool is_high = extract32(op_id, 2, 1);
+    bool is_signed = false;
+    TCGv_i64 tcg_op1;
+    TCGv_i64 tcg_op2;
+    TCGv_i64 tcg_tmp;
+
+    /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
+    switch (op_id) {
+    case 0x42: /* SMADDL */
+    case 0x43: /* SMSUBL */
+    case 0x44: /* SMULH */
+        is_signed = true;
+        break;
+    case 0x0: /* MADD (32bit) */
+    case 0x1: /* MSUB (32bit) */
+    case 0x40: /* MADD (64bit) */
+    case 0x41: /* MSUB (64bit) */
+    case 0x4a: /* UMADDL */
+    case 0x4b: /* UMSUBL */
+    case 0x4c: /* UMULH */
+        break;
+    default:
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (is_high) {
+        TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
+        TCGv_i64 tcg_rd = cpu_reg(s, rd);
+        TCGv_i64 tcg_rn = cpu_reg(s, rn);
+        TCGv_i64 tcg_rm = cpu_reg(s, rm);
+
+        if (is_signed) {
+            tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
+        }
+
+        tcg_temp_free_i64(low_bits);
+        return;
+    }
+
+    tcg_op1 = tcg_temp_new_i64();
+    tcg_op2 = tcg_temp_new_i64();
+    tcg_tmp = tcg_temp_new_i64();
+
+    if (op_id < 0x42) {
+        tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
+        tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
+    } else {
+        if (is_signed) {
+            tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
+            tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
+        } else {
+            tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
+            tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
+        }
+    }
+
+    if (ra == 31 && !is_sub) {
+        /* Special-case MADD with rA == XZR; it is the standard MUL alias */
+        tcg_gen_mul_i64(cpu_reg(s, rd), tcg_op1, tcg_op2);
+    } else {
+        tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
+        if (is_sub) {
+            tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+        } else {
+            tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+        }
+    }
+
+    if (!sf) {
+        tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
+    }
+
+    tcg_temp_free_i64(tcg_op1);
+    tcg_temp_free_i64(tcg_op2);
+    tcg_temp_free_i64(tcg_tmp);
 }
 
 /* Add/subtract (with carry) */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 08/25] target-arm: A64: implement SVC, BRK
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (6 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 07/25] target-arm: A64: add support for 3 src data proc insns Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 09/25] target-arm: A64: Add decoder skeleton for FP instructions Peter Maydell
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alexander Graf <agraf@suse.de>

Add decoding for the exception generating instructions, and implement
SVC (syscalls) and BRK (software breakpoint).

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 51 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 3a9ffdf..9ca6460 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -808,10 +808,57 @@ static void disas_system(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Exception generation */
+/* C3.2.3 Exception generation
+ *
+ *  31             24 23 21 20                     5 4   2 1  0
+ * +-----------------+-----+------------------------+-----+----+
+ * | 1 1 0 1 0 1 0 0 | opc |          imm16         | op2 | LL |
+ * +-----------------------+------------------------+----------+
+ */
 static void disas_exc(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int opc = extract32(insn, 21, 3);
+    int op2_ll = extract32(insn, 0, 5);
+
+    switch (opc) {
+    case 0:
+        /* SVC, HVC, SMC; since we don't support the Virtualization
+         * or TrustZone extensions these all UNDEF except SVC.
+         */
+        if (op2_ll != 1) {
+            unallocated_encoding(s);
+            break;
+        }
+        gen_exception_insn(s, 0, EXCP_SWI);
+        break;
+    case 1:
+        if (op2_ll != 0) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* BRK */
+        gen_exception_insn(s, 0, EXCP_BKPT);
+        break;
+    case 2:
+        if (op2_ll != 0) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* HLT */
+        unsupported_encoding(s, insn);
+        break;
+    case 5:
+        if (op2_ll < 1 || op2_ll > 3) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* DCPS1, DCPS2, DCPS3 */
+        unsupported_encoding(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* C3.2.7 Unconditional branch (register)
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 09/25] target-arm: A64: Add decoder skeleton for FP instructions
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (7 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 08/25] target-arm: A64: implement SVC, BRK Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 10/25] target-arm: A64: implement FMOV Peter Maydell
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Add a top level decoder skeleton for FP instructions.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 170 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 169 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 9ca6460..079c2f7 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2670,10 +2670,178 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
     }
 }
 
+/* C3.6.22 Floating point compare
+ *   31  30  29 28       24 23  22  21 20  16 15 14 13  10    9    5 4     0
+ * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | op  | 1 0 0 0 |  Rn  |  op2  |
+ * +---+---+---+-----------+------+---+------+-----+---------+------+-------+
+ */
+static void disas_fp_compare(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.23 Floating point conditional compare
+ *   31  30  29 28       24 23  22  21 20  16 15  12 11 10 9    5  4   3    0
+ * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | cond | 0 1 |  Rn  | op | nzcv |
+ * +---+---+---+-----------+------+---+------+------+-----+------+----+------+
+ */
+static void disas_fp_ccomp(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.24 Floating point conditional select
+ *   31  30  29 28       24 23  22  21 20  16 15  12 11 10 9    5 4    0
+ * +---+---+---+-----------+------+---+------+------+-----+------+------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | cond | 1 1 |  Rn  |  Rd  |
+ * +---+---+---+-----------+------+---+------+------+-----+------+------+
+ */
+static void disas_fp_csel(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.25 Floating point data-processing (1 source)
+ *   31  30  29 28       24 23  22  21 20    15 14       10 9    5 4    0
+ * +---+---+---+-----------+------+---+--------+-----------+------+------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 | opcode | 1 0 0 0 0 |  Rn  |  Rd  |
+ * +---+---+---+-----------+------+---+--------+-----------+------+------+
+ */
+static void disas_fp_1src(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.26 Floating point data-processing (2 source)
+ *   31  30  29 28       24 23  22  21 20  16 15    12 11 10 9    5 4    0
+ * +---+---+---+-----------+------+---+------+--------+-----+------+------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 |  Rm  | opcode | 1 0 |  Rn  |  Rd  |
+ * +---+---+---+-----------+------+---+------+--------+-----+------+------+
+ */
+static void disas_fp_2src(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.27 Floating point data-processing (3 source)
+ *   31  30  29 28       24 23  22  21  20  16  15  14  10 9    5 4    0
+ * +---+---+---+-----------+------+----+------+----+------+------+------+
+ * | M | 0 | S | 1 1 1 1 1 | type | o1 |  Rm  | o0 |  Ra  |  Rn  |  Rd  |
+ * +---+---+---+-----------+------+----+------+----+------+------+------+
+ */
+static void disas_fp_3src(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.28 Floating point immediate
+ *   31  30  29 28       24 23  22  21 20        13 12   10 9    5 4    0
+ * +---+---+---+-----------+------+---+------------+-------+------+------+
+ * | M | 0 | S | 1 1 1 1 0 | type | 1 |    imm8    | 1 0 0 | imm5 |  Rd  |
+ * +---+---+---+-----------+------+---+------------+-------+------+------+
+ */
+static void disas_fp_imm(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.29 Floating point <-> fixed point conversions
+ *   31   30  29 28       24 23  22  21 20   19 18    16 15   10 9    5 4    0
+ * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
+ * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opcode | scale |  Rn  |  Rd  |
+ * +----+---+---+-----------+------+---+-------+--------+-------+------+------+
+ */
+static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* C3.6.30 Floating point <-> integer conversions
+ *   31   30  29 28       24 23  22  21 20   19 18 16 15         10 9  5 4  0
+ * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
+ * | sf | 0 | S | 1 1 1 1 0 | type | 0 | rmode | opc | 0 0 0 0 0 0 | Rn | Rd |
+ * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
+ */
+static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
+{
+    unsupported_encoding(s, insn);
+}
+
+/* FP-specific subcases of table C3-6 (SIMD and FP data processing)
+ *   31  30  29 28     25 24                          0
+ * +---+---+---+---------+-----------------------------+
+ * |   | 0 |   | 1 1 1 1 |                             |
+ * +---+---+---+---------+-----------------------------+
+ */
+static void disas_data_proc_fp(DisasContext *s, uint32_t insn)
+{
+    if (extract32(insn, 24, 1)) {
+        /* Floating point data-processing (3 source) */
+        disas_fp_3src(s, insn);
+    } else if (extract32(insn, 21, 1) == 0) {
+        /* Floating point to fixed point conversions */
+        disas_fp_fixed_conv(s, insn);
+    } else {
+        switch (extract32(insn, 10, 2)) {
+        case 1:
+            /* Floating point conditional compare */
+            disas_fp_ccomp(s, insn);
+            break;
+        case 2:
+            /* Floating point data-processing (2 source) */
+            disas_fp_2src(s, insn);
+            break;
+        case 3:
+            /* Floating point conditional select */
+            disas_fp_csel(s, insn);
+            break;
+        case 0:
+            switch (ctz32(extract32(insn, 12, 4))) {
+            case 0: /* [15:12] == xxx1 */
+                /* Floating point immediate */
+                disas_fp_imm(s, insn);
+                break;
+            case 1: /* [15:12] == xx10 */
+                /* Floating point compare */
+                disas_fp_compare(s, insn);
+                break;
+            case 2: /* [15:12] == x100 */
+                /* Floating point data-processing (1 source) */
+                disas_fp_1src(s, insn);
+                break;
+            case 3: /* [15:12] == 1000 */
+                unallocated_encoding(s);
+                break;
+            default: /* [15:12] == 0000 */
+                /* Floating point <-> integer conversions */
+                disas_fp_int_conv(s, insn);
+                break;
+            }
+            break;
+        }
+    }
+}
+
+static void disas_data_proc_simd(DisasContext *s, uint32_t insn)
+{
+    /* Note that this is called with all non-FP cases from
+     * table C3-6 so it must UNDEF for entries not specifically
+     * allocated to instructions in that table.
+     */
+    unsupported_encoding(s, insn);
+}
+
 /* C3.6 Data processing - SIMD and floating point */
 static void disas_data_proc_simd_fp(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    if (extract32(insn, 28, 1) == 1 && extract32(insn, 30, 1) == 0) {
+        disas_data_proc_fp(s, insn);
+    } else {
+        /* SIMD, including crypto */
+        disas_data_proc_simd(s, insn);
+    }
 }
 
 /* C3.1 A64 instruction index by encoding */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 10/25] target-arm: A64: implement FMOV
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (8 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 09/25] target-arm: A64: Add decoder skeleton for FP instructions Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function Peter Maydell
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Implement FMOV, ie non-converting moves between general purpose
registers and floating point registers. This is a subtype of
the floating point <-> integer instruction class.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 86 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 85 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 079c2f7..7d98337 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2758,6 +2758,63 @@ static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
     unsupported_encoding(s, insn);
 }
 
+static void handle_fmov(DisasContext *s, int rd, int rn, int type, bool itof)
+{
+    /* FMOV: gpr to or from float, double, or top half of quad fp reg,
+     * without conversion.
+     */
+
+    if (itof) {
+        int freg_offs = offsetof(CPUARMState, vfp.regs[rd * 2]);
+        TCGv_i64 tcg_rn = cpu_reg(s, rn);
+
+        switch (type) {
+        case 0:
+        {
+            /* 32 bit */
+            TCGv_i64 tmp = tcg_temp_new_i64();
+            tcg_gen_ext32u_i64(tmp, tcg_rn);
+            tcg_gen_st_i64(tmp, cpu_env, freg_offs);
+            tcg_gen_movi_i64(tmp, 0);
+            tcg_gen_st_i64(tmp, cpu_env, freg_offs + sizeof(float64));
+            tcg_temp_free_i64(tmp);
+            break;
+        }
+        case 1:
+        {
+            /* 64 bit */
+            TCGv_i64 tmp = tcg_const_i64(0);
+            tcg_gen_st_i64(tcg_rn, cpu_env, freg_offs);
+            tcg_gen_st_i64(tmp, cpu_env, freg_offs + sizeof(float64));
+            tcg_temp_free_i64(tmp);
+            break;
+        }
+        case 2:
+            /* 64 bit to top half. */
+            tcg_gen_st_i64(tcg_rn, cpu_env, freg_offs + sizeof(float64));
+            break;
+        }
+    } else {
+        int freg_offs = offsetof(CPUARMState, vfp.regs[rn * 2]);
+        TCGv_i64 tcg_rd = cpu_reg(s, rd);
+
+        switch (type) {
+        case 0:
+            /* 32 bit */
+            tcg_gen_ld32u_i64(tcg_rd, cpu_env, freg_offs);
+            break;
+        case 2:
+            /* 64 bits from top half */
+            freg_offs += sizeof(float64);
+            /* fall through */
+        case 1:
+            /* 64 bit */
+            tcg_gen_ld_i64(tcg_rd, cpu_env, freg_offs);
+            break;
+        }
+    }
+}
+
 /* C3.6.30 Floating point <-> integer conversions
  *   31   30  29 28       24 23  22  21 20   19 18 16 15         10 9  5 4  0
  * +----+---+---+-----------+------+---+-------+-----+-------------+----+----+
@@ -2766,7 +2823,34 @@ static void disas_fp_fixed_conv(DisasContext *s, uint32_t insn)
  */
 static void disas_fp_int_conv(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int opcode = extract32(insn, 16, 3);
+    int rmode = extract32(insn, 19, 2);
+    int type = extract32(insn, 22, 2);
+    bool sbit = extract32(insn, 29, 1);
+    bool sf = extract32(insn, 31, 1);
+
+    if (!sbit && (rmode < 2) && (opcode > 5)) {
+        /* FMOV */
+        bool itof = opcode & 1;
+
+        switch (sf << 3 | type << 1 | rmode) {
+        case 0x0: /* 32 bit */
+        case 0xa: /* 64 bit */
+        case 0xd: /* 64 bit to top half of quad */
+            break;
+        default:
+            /* all other sf/type/rmode combinations are invalid */
+            unallocated_encoding(s);
+            break;
+        }
+
+        handle_fmov(s, rd, rn, type, itof);
+    } else {
+        /* actual FP conversions */
+        unsupported_encoding(s, insn);
+    }
 }
 
 /* FP-specific subcases of table C3-6 (SIMD and FP data processing)
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (9 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 10/25] target-arm: A64: implement FMOV Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-23 19:51   ` Richard Henderson
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64 Peter Maydell
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

define_one_arm_cp_reg_with_opaque() has a set of nested loops which
insert a cpreg entry into the hashtable for each of the possible
opc/crn/crm values allowed by wildcard specifications. We're about
to add an extra loop to this nesting, so pull the core of the loop
(which adds a single entry to the hashtable) out into its own
function for clarity.

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

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 6ebd7dc..d833163 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1937,6 +1937,57 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
     return cpu_list;
 }
 
+static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
+                                   void *opaque, int crm, int opc1, int opc2)
+{
+    /* Private utility function for define_one_arm_cp_reg_with_opaque():
+     * add a single reginfo struct to the hash table.
+     */
+    uint32_t *key = g_new(uint32_t, 1);
+    ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
+    int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
+    *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
+    if (opaque) {
+        r2->opaque = opaque;
+    }
+    /* Make sure reginfo passed to helpers for wildcarded regs
+     * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
+     */
+    r2->crm = crm;
+    r2->opc1 = opc1;
+    r2->opc2 = opc2;
+    /* By convention, for wildcarded registers only the first
+     * entry is used for migration; the others are marked as
+     * NO_MIGRATE so we don't try to transfer the register
+     * multiple times. Special registers (ie NOP/WFI) are
+     * never migratable.
+     */
+    if ((r->type & ARM_CP_SPECIAL) ||
+        ((r->crm == CP_ANY) && crm != 0) ||
+        ((r->opc1 == CP_ANY) && opc1 != 0) ||
+        ((r->opc2 == CP_ANY) && opc2 != 0)) {
+        r2->type |= ARM_CP_NO_MIGRATE;
+    }
+
+    /* Overriding of an existing definition must be explicitly
+     * requested.
+     */
+    if (!(r->type & ARM_CP_OVERRIDE)) {
+        ARMCPRegInfo *oldreg;
+        oldreg = g_hash_table_lookup(cpu->cp_regs, key);
+        if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
+            fprintf(stderr, "Register redefined: cp=%d %d bit "
+                    "crn=%d crm=%d opc1=%d opc2=%d, "
+                    "was %s, now %s\n", r2->cp, 32 + 32 * is64,
+                    r2->crn, r2->crm, r2->opc1, r2->opc2,
+                    oldreg->name, r2->name);
+            g_assert_not_reached();
+        }
+    }
+    g_hash_table_insert(cpu->cp_regs, key, r2);
+}
+
+
 void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
                                        const ARMCPRegInfo *r, void *opaque)
 {
@@ -1977,48 +2028,7 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
     for (crm = crmmin; crm <= crmmax; crm++) {
         for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
             for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
-                uint32_t *key = g_new(uint32_t, 1);
-                ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
-                int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
-                *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
-                if (opaque) {
-                    r2->opaque = opaque;
-                }
-                /* Make sure reginfo passed to helpers for wildcarded regs
-                 * has the correct crm/opc1/opc2 for this reg, not CP_ANY:
-                 */
-                r2->crm = crm;
-                r2->opc1 = opc1;
-                r2->opc2 = opc2;
-                /* By convention, for wildcarded registers only the first
-                 * entry is used for migration; the others are marked as
-                 * NO_MIGRATE so we don't try to transfer the register
-                 * multiple times. Special registers (ie NOP/WFI) are
-                 * never migratable.
-                 */
-                if ((r->type & ARM_CP_SPECIAL) ||
-                    ((r->crm == CP_ANY) && crm != 0) ||
-                    ((r->opc1 == CP_ANY) && opc1 != 0) ||
-                    ((r->opc2 == CP_ANY) && opc2 != 0)) {
-                    r2->type |= ARM_CP_NO_MIGRATE;
-                }
-
-                /* Overriding of an existing definition must be explicitly
-                 * requested.
-                 */
-                if (!(r->type & ARM_CP_OVERRIDE)) {
-                    ARMCPRegInfo *oldreg;
-                    oldreg = g_hash_table_lookup(cpu->cp_regs, key);
-                    if (oldreg && !(oldreg->type & ARM_CP_OVERRIDE)) {
-                        fprintf(stderr, "Register redefined: cp=%d %d bit "
-                                "crn=%d crm=%d opc1=%d opc2=%d, "
-                                "was %s, now %s\n", r2->cp, 32 + 32 * is64,
-                                r2->crn, r2->crm, r2->opc1, r2->opc2,
-                                oldreg->name, r2->name);
-                        g_assert_not_reached();
-                    }
-                }
-                g_hash_table_insert(cpu->cp_regs, key, r2);
+                add_cpreg_to_hashtable(cpu, r, opaque, crm, opc1, opc2);
             }
         }
     }
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (10 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2014-01-02  1:51   ` Peter Crosthwaite
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder Peter Maydell
                   ` (12 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Update the generic cpreg support code to also handle AArch64:
AArch64-visible registers coexist in the same hash table with
AArch32-visible ones, with a bit in the hash key distinguishing
them.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h        |  74 +++++++++++++++++++++++++++++++---
 target-arm/helper.c     | 105 ++++++++++++++++++++++++++++++++++++++++++++++--
 target-arm/kvm-consts.h |  37 +++++++++++++++++
 3 files changed, 207 insertions(+), 9 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 56ed591..b082bca 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -572,18 +572,43 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
  *    or via MRRC/MCRR?)
  * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
  * (In this case crn and opc2 should be zero.)
+ * For AArch64, there is no 32/64 bit size distinction;
+ * instead all registers have a 2 bit op0, 3 bit op1 and op2,
+ * and 4 bit CRn and CRm. The encoding patterns are chosen
+ * to be easy to convert to and from the KVM encodings, and also
+ * so that the hashtable can contain both AArch32 and AArch64
+ * registers (to allow for interprocessing where we might run
+ * 32 bit code on a 64 bit core).
  */
+/* This bit is private to our hashtable cpreg; in KVM register
+ * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64
+ * in the upper bits of the 64 bit ID.
+ */
+#define CP_REG_AA64_SHIFT 28
+#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
+
 #define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2)   \
     (((cp) << 16) | ((is64) << 15) | ((crn) << 11) |    \
      ((crm) << 7) | ((opc1) << 3) | (opc2))
 
+#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
+    (CP_REG_AA64_MASK |                                 \
+     ((cp) << CP_REG_ARM_COPROC_SHIFT) |                \
+     ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
+     ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
+     ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) |         \
+     ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) |         \
+     ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
+
 /* Convert a full 64 bit KVM register ID to the truncated 32 bit
  * version used as a key for the coprocessor register hashtable
  */
 static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
 {
     uint32_t cpregid = kvmid;
-    if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
+    if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) {
+        cpregid |= CP_REG_AA64_MASK;
+    } else if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
         cpregid |= (1 << 15);
     }
     return cpregid;
@@ -594,11 +619,18 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
  */
 static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 {
-    uint64_t kvmid = cpregid & ~(1 << 15);
-    if (cpregid & (1 << 15)) {
-        kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
+    uint64_t kvmid;
+
+    if (cpregid & CP_REG_AA64_MASK) {
+        kvmid = cpregid & ~CP_REG_AA64_MASK;
+        kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
     } else {
-        kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
+        kvmid = cpregid & ~(1 << 15);
+        if (cpregid & (1 << 15)) {
+            kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
+        } else {
+            kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
+        }
     }
     return kvmid;
 }
@@ -634,6 +666,17 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 /* Mask of only the flag bits in a type field */
 #define ARM_CP_FLAG_MASK 0x7f
 
+/* Valid values for ARMCPRegInfo state field, indicating which of
+ * the AArch32 and AArch64 execution states this register is visible in.
+ * If the reginfo doesn't explicitly specify then it is AArch32 only.
+ * If the reginfo is declared to be visible in both states then a second
+ * reginfo is synthesised for the AArch32 view of the AArch64 register,
+ * such that the AArch32 view is the lower 32 bits of the AArch64 one.
+ */
+#define ARM_CP_STATE_AA32 0
+#define ARM_CP_STATE_AA64 1
+#define ARM_CP_STATE_BOTH 2
+
 /* Return true if cptype is a valid type field. This is used to try to
  * catch errors where the sentinel has been accidentally left off the end
  * of a list of registers.
@@ -655,6 +698,8 @@ static inline bool cptype_valid(int cptype)
  * (ie anything visible in PL2 is visible in S-PL1, some things are only
  * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the
  * terminology a little and call this PL3.
+ * In AArch64 things are somewhat simpler as the PLx bits line up exactly
+ * with the ELx exception levels.
  *
  * If access permissions for a register are more complex than can be
  * described with these bits, then use a laxer set of restrictions, and
@@ -676,6 +721,10 @@ static inline bool cptype_valid(int cptype)
 
 static inline int arm_current_pl(CPUARMState *env)
 {
+    if (env->aarch64) {
+        return extract32(env->pstate, 2, 2);
+    }
+
     if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR) {
         return 0;
     }
@@ -713,12 +762,22 @@ struct ARMCPRegInfo {
      * then behave differently on read/write if necessary.
      * For 64 bit registers, only crm and opc1 are relevant; crn and opc2
      * must both be zero.
+     * For AArch64-visible registers, opc0 is also used.
+     * Since there are no "coprocessors" in AArch64, cp is purely used as a
+     * way to distinguish (for KVM's benefit) guest-visible system registers
+     * from demuxed ones provided to preserve the "no side effects on
+     * KVM register read/write from QEMU" semantics. cp==0x13 is guest
+     * visible (to match KVM's encoding); cp==0 will be converted to
+     * cp==0x13 when the ARMCPRegInfo is registered, for convenience.
      */
     uint8_t cp;
     uint8_t crn;
     uint8_t crm;
+    uint8_t opc0;
     uint8_t opc1;
     uint8_t opc2;
+    /* Execution state in which this register is visible: ARM_CP_STATE_* */
+    int state;
     /* Register type: ARM_CP_* bits/values */
     int type;
     /* Access rights: PL*_[RW] */
@@ -798,6 +857,11 @@ int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
 /* CPReadFn that can be used for read-as-zero behaviour */
 int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value);
 
+/* CPResetFn that does nothing, for use if no reset is required even
+ * if fieldoffset is non zero.
+ */
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
+
 static inline bool cp_access_ok(CPUARMState *env,
                                 const ARMCPRegInfo *ri, int isread)
 {
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d833163..3dac694 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1938,7 +1938,8 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
 }
 
 static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
-                                   void *opaque, int crm, int opc1, int opc2)
+                                   void *opaque, int state,
+                                   int crm, int opc1, int opc2)
 {
     /* Private utility function for define_one_arm_cp_reg_with_opaque():
      * add a single reginfo struct to the hash table.
@@ -1946,7 +1947,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
     uint32_t *key = g_new(uint32_t, 1);
     ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
     int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
-    *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
+    if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) {
+        /* The AArch32 view of a shared register sees the lower 32 bits
+         * of a 64 bit backing field. It is not migratable as the AArch64
+         * view handles that. AArch64 also handles reset.
+         * We assume it is a cp15 register.
+         */
+        r2->cp = 15;
+        r2->type |= ARM_CP_NO_MIGRATE;
+        r2->resetfn = arm_cp_reset_ignore;
+#ifdef HOST_WORDS_BIGENDIAN
+        if (r2->fieldoffset) {
+            r2->fieldoffset += sizeof(uint32_t);
+        }
+#endif
+    }
+    if (state == ARM_CP_STATE_AA64) {
+        /* To allow abbreviation of ARMCPRegInfo
+         * definitions, we treat cp == 0 as equivalent to
+         * the value for "standard guest-visible sysreg".
+         */
+        if (r->cp == 0) {
+            r2->cp = CP_REG_ARM64_SYSREG_CP;
+        }
+        *key = ENCODE_AA64_CP_REG(r2->cp, r->crn, crm,
+                                  r->opc0, opc1, opc2);
+    } else {
+        *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
+    }
     if (opaque) {
         r2->opaque = opaque;
     }
@@ -2002,8 +2030,19 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
      * At least one of the original and the second definition should
      * include ARM_CP_OVERRIDE in its type bits -- this is just a guard
      * against accidental use.
+     *
+     * The state field defines whether the register is to be
+     * visible in the AArch32 or AArch64 execution state. If the
+     * state is set to ARM_CP_STATE_BOTH then we synthesise a
+     * reginfo structure for the AArch32 view, which sees the lower
+     * 32 bits of the 64 bit register.
+     *
+     * Only registers visible in AArch64 may set r->opc0; opc0 cannot
+     * be wildcarded. AArch64 registers are always considered to be 64
+     * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
+     * the register, if any.
      */
-    int crm, opc1, opc2;
+    int crm, opc1, opc2, state;
     int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
     int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
     int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
@@ -2012,6 +2051,52 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
     int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
     /* 64 bit registers have only CRm and Opc1 fields */
     assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
+    /* op0 only exists in the AArch64 encodings */
+    assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
+    /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
+    assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
+    /* The AArch64 pseudocode CheckSystemAccess() specifies that op1
+     * encodes a minimum access level for the register. We roll this
+     * runtime check into our general permission check code, so check
+     * here that the reginfo's specified permissions are strict enough
+     * to encompass the generic architectural permission check.
+     */
+    if (r->state != ARM_CP_STATE_AA32) {
+        int mask = 0;
+        switch (r->opc1) {
+        case 0: case 1: case 2:
+            /* min_EL EL1 */
+            mask = PL1_RW;
+            break;
+        case 3:
+            /* min_EL EL0 */
+            mask = PL0_RW;
+            break;
+        case 4:
+            /* min_EL EL2 */
+            mask = PL2_RW;
+            break;
+        case 5:
+            /* unallocated encoding, so not possible */
+            assert(false);
+            break;
+        case 6:
+            /* min_EL EL3 */
+            mask = PL3_RW;
+            break;
+        case 7:
+            /* min_EL EL1, secure mode only (we don't check the latter) */
+            mask = PL1_RW;
+            break;
+        default:
+            /* broken reginfo with out-of-range opc1 */
+            assert(false);
+            break;
+        }
+        /* assert our permissions are not too lax (stricter is fine) */
+        assert((r->access & ~mask) == 0);
+    }
+
     /* Check that the register definition has enough info to handle
      * reads and writes if they are permitted.
      */
@@ -2028,7 +2113,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
     for (crm = crmmin; crm <= crmmax; crm++) {
         for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
             for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
-                add_cpreg_to_hashtable(cpu, r, opaque, crm, opc1, opc2);
+                for (state = ARM_CP_STATE_AA32;
+                     state <= ARM_CP_STATE_AA64; state++) {
+                    if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
+                        continue;
+                    }
+                    add_cpreg_to_hashtable(cpu, r, opaque, state,
+                                           crm, opc1, opc2);
+                }
             }
         }
     }
@@ -2063,6 +2155,11 @@ int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value)
     return 0;
 }
 
+void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
+{
+    /* Helper coprocessor reset function for do-nothing-on-reset registers */
+}
+
 static int bad_mode_switch(CPUARMState *env, int mode)
 {
     /* Return true if it is not valid for us to switch to
diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h
index 2bba0bd..0e7f889 100644
--- a/target-arm/kvm-consts.h
+++ b/target-arm/kvm-consts.h
@@ -29,12 +29,14 @@
 #define CP_REG_SIZE_U32        0x0020000000000000ULL
 #define CP_REG_SIZE_U64        0x0030000000000000ULL
 #define CP_REG_ARM             0x4000000000000000ULL
+#define CP_REG_ARCH_MASK       0xff00000000000000ULL
 
 MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT)
 MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK)
 MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32)
 MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64)
 MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM)
+MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
 
 #define PSCI_FN_BASE 0x95c1ba5e
 #define PSCI_FN(n) (PSCI_FN_BASE + (n))
@@ -59,6 +61,41 @@ MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
 MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
 #endif
 
+#define CP_REG_ARM64                   0x6000000000000000ULL
+#define CP_REG_ARM_COPROC_MASK         0x000000000FFF0000
+#define CP_REG_ARM_COPROC_SHIFT        16
+#define CP_REG_ARM64_SYSREG            (0x0013 << CP_REG_ARM_COPROC_SHIFT)
+#define CP_REG_ARM64_SYSREG_OP0_MASK   0x000000000000c000
+#define CP_REG_ARM64_SYSREG_OP0_SHIFT  14
+#define CP_REG_ARM64_SYSREG_OP1_MASK   0x0000000000003800
+#define CP_REG_ARM64_SYSREG_OP1_SHIFT  11
+#define CP_REG_ARM64_SYSREG_CRN_MASK   0x0000000000000780
+#define CP_REG_ARM64_SYSREG_CRN_SHIFT  7
+#define CP_REG_ARM64_SYSREG_CRM_MASK   0x0000000000000078
+#define CP_REG_ARM64_SYSREG_CRM_SHIFT  3
+#define CP_REG_ARM64_SYSREG_OP2_MASK   0x0000000000000007
+#define CP_REG_ARM64_SYSREG_OP2_SHIFT  0
+
+/* No kernel define but it's useful to QEMU */
+#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
+
+#ifdef TARGET_AARCH64
+MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64)
+MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK)
+MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP0_SHIFT)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP1_SHIFT)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_CRN_SHIFT)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRM_MASK)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRM_SHIFT)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK)
+MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT)
+#endif
+
 #undef MISMATCH_CHECK
 
 #endif
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (11 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64 Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-23 20:11   ` Richard Henderson
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 14/25] target-arm: A64: Implement MRS/MSR/SYS/SYSL Peter Maydell
                   ` (11 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

The cpregs APIs used by the decoder (get_arm_cp_reginfo() and
cp_access_ok()) currently take either a CPUARMState* or an ARMCPU*.
This is problematic for the A64 decoder, which doesn't pass the
environment pointer around everywhere the way the 32 bit decoder
does. Adjust the parameters these functions take so that we can
copy only the relevant info from the CPUARMState into the
DisasContext and then use that.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/cpu.h           |  6 +++---
 target-arm/helper.c        | 12 ++++++------
 target-arm/translate-a64.c |  2 ++
 target-arm/translate.c     |  7 ++++---
 target-arm/translate.h     |  2 ++
 5 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index b082bca..66490ce 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -849,7 +849,7 @@ static inline void define_one_arm_cp_reg(ARMCPU *cpu, const ARMCPRegInfo *regs)
 {
     define_one_arm_cp_reg_with_opaque(cpu, regs, 0);
 }
-const ARMCPRegInfo *get_arm_cp_reginfo(ARMCPU *cpu, uint32_t encoded_cp);
+const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp);
 
 /* CPWriteFn that can be used to implement writes-ignored behaviour */
 int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -862,10 +862,10 @@ int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value);
  */
 void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
 
-static inline bool cp_access_ok(CPUARMState *env,
+static inline bool cp_access_ok(int current_pl,
                                 const ARMCPRegInfo *ri, int isread)
 {
-    return (ri->access >> ((arm_current_pl(env) * 2) + isread)) & 1;
+    return (ri->access >> ((current_pl * 2) + isread)) & 1;
 }
 
 /**
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 3dac694..66214293 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -186,7 +186,7 @@ bool write_cpustate_to_list(ARMCPU *cpu)
         uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]);
         const ARMCPRegInfo *ri;
         uint64_t v;
-        ri = get_arm_cp_reginfo(cpu, regidx);
+        ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
         if (!ri) {
             ok = false;
             continue;
@@ -214,7 +214,7 @@ bool write_list_to_cpustate(ARMCPU *cpu)
         uint64_t readback;
         const ARMCPRegInfo *ri;
 
-        ri = get_arm_cp_reginfo(cpu, regidx);
+        ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
         if (!ri) {
             ok = false;
             continue;
@@ -242,7 +242,7 @@ static void add_cpreg_to_list(gpointer key, gpointer opaque)
     const ARMCPRegInfo *ri;
 
     regidx = *(uint32_t *)key;
-    ri = get_arm_cp_reginfo(cpu, regidx);
+    ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
 
     if (!(ri->type & ARM_CP_NO_MIGRATE)) {
         cpu->cpreg_indexes[cpu->cpreg_array_len] = cpreg_to_kvm_id(regidx);
@@ -258,7 +258,7 @@ static void count_cpreg(gpointer key, gpointer opaque)
     const ARMCPRegInfo *ri;
 
     regidx = *(uint32_t *)key;
-    ri = get_arm_cp_reginfo(cpu, regidx);
+    ri = get_arm_cp_reginfo(cpu->cp_regs, regidx);
 
     if (!(ri->type & ARM_CP_NO_MIGRATE)) {
         cpu->cpreg_array_len++;
@@ -2136,9 +2136,9 @@ void define_arm_cp_regs_with_opaque(ARMCPU *cpu,
     }
 }
 
-const ARMCPRegInfo *get_arm_cp_reginfo(ARMCPU *cpu, uint32_t encoded_cp)
+const ARMCPRegInfo *get_arm_cp_reginfo(GHashTable *cpregs, uint32_t encoded_cp)
 {
-    return g_hash_table_lookup(cpu->cp_regs, &encoded_cp);
+    return g_hash_table_lookup(cpregs, &encoded_cp);
 }
 
 int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7d98337..e35d2f3 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -3007,6 +3007,8 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
     dc->vfp_enabled = 0;
     dc->vec_len = 0;
     dc->vec_stride = 0;
+    dc->cp_regs = cpu->cp_regs;
+    dc->current_pl = arm_current_pl(env);
 
     init_tmp_a64_array(dc);
 
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 1403ecf..8bfe950 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6498,7 +6498,6 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
 {
     int cpnum, is64, crn, crm, opc1, opc2, isread, rt, rt2;
     const ARMCPRegInfo *ri;
-    ARMCPU *cpu = arm_env_get_cpu(env);
 
     cpnum = (insn >> 8) & 0xf;
     if (arm_feature(env, ARM_FEATURE_XSCALE)
@@ -6541,11 +6540,11 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
     isread = (insn >> 20) & 1;
     rt = (insn >> 12) & 0xf;
 
-    ri = get_arm_cp_reginfo(cpu,
+    ri = get_arm_cp_reginfo(s->cp_regs,
                             ENCODE_CP_REG(cpnum, is64, crn, crm, opc1, opc2));
     if (ri) {
         /* Check access permissions */
-        if (!cp_access_ok(env, ri, isread)) {
+        if (!cp_access_ok(s->current_pl, ri, isread)) {
             return 1;
         }
 
@@ -10269,6 +10268,8 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
     dc->vfp_enabled = ARM_TBFLAG_VFPEN(tb->flags);
     dc->vec_len = ARM_TBFLAG_VECLEN(tb->flags);
     dc->vec_stride = ARM_TBFLAG_VECSTRIDE(tb->flags);
+    dc->cp_regs = cpu->cp_regs;
+    dc->current_pl = arm_current_pl(env);
 
     cpu_F0s = tcg_temp_new_i32();
     cpu_F1s = tcg_temp_new_i32();
diff --git a/target-arm/translate.h b/target-arm/translate.h
index a6f6b3e..67da699 100644
--- a/target-arm/translate.h
+++ b/target-arm/translate.h
@@ -24,6 +24,8 @@ typedef struct DisasContext {
     int vec_len;
     int vec_stride;
     int aarch64;
+    int current_pl;
+    GHashTable *cp_regs;
 #define TMP_A64_MAX 16
     int tmp_a64_count;
     TCGv_i64 tmp_a64[TMP_A64_MAX];
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 14/25] target-arm: A64: Implement MRS/MSR/SYS/SYSL
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (12 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs Peter Maydell
                   ` (10 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

The AArch64 equivalent of the traditional AArch32
cp15 coprocessor registers is the set of instructions
MRS/MSR/SYS/SYSL, which cover between them both true
system registers and the "operations with side effects"
such as cache maintenance which in AArch32 are mixed
in with other cp15 registers. Implement these instructions
to look in the cpregs hashtable for the register or
operation.

Since we don't yet populate the cpregs hashtable with
any registers with the "AA64" bit set, everything will
still UNDEF at this point.

MSR/MRS is the first user of is_jmp = DISAS_UPDATE, so
fix an infelicity in its handling where the main loop
was requiring the caller to do the update of PC rather
than just doing it itself.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 112 +++++++++++++++++++++++++++++++++------------
 1 file changed, 82 insertions(+), 30 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index e35d2f3..7a9ee82 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -733,28 +733,88 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
     unsupported_encoding(s, insn);
 }
 
-/* C5.6.204 SYS */
-static void handle_sys(DisasContext *s, uint32_t insn, unsigned int l,
-                       unsigned int op1, unsigned int op2,
+/* C5.6.129 MRS - move from system register
+ * C5.6.131 MSR (register) - move to system register
+ * C5.6.204 SYS
+ * C5.6.205 SYSL
+ * These are all essentially the same insn in 'read' and 'write'
+ * versions, with varying op0 fields.
+ */
+static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
+                       unsigned int op0, unsigned int op1, unsigned int op2,
                        unsigned int crn, unsigned int crm, unsigned int rt)
 {
-    unsupported_encoding(s, insn);
-}
+    const ARMCPRegInfo *ri;
+    TCGv_i64 tcg_rt;
 
-/* C5.6.129 MRS - move from system register */
-static void handle_mrs(DisasContext *s, uint32_t insn, unsigned int op0,
-                       unsigned int op1, unsigned int op2,
-                       unsigned int crn, unsigned int crm, unsigned int rt)
-{
-    unsupported_encoding(s, insn);
-}
+    ri = get_arm_cp_reginfo(s->cp_regs,
+                            ENCODE_AA64_CP_REG(CP_REG_ARM64_SYSREG_CP,
+                                               crn, crm, op0, op1, op2));
 
-/* C5.6.131 MSR (register) - move to system register */
-static void handle_msr(DisasContext *s, uint32_t insn, unsigned int op0,
-                       unsigned int op1, unsigned int op2,
-                       unsigned int crn, unsigned int crm, unsigned int rt)
-{
-    unsupported_encoding(s, insn);
+    if (!ri) {
+        /* Unknown register */
+        unallocated_encoding(s);
+        return;
+    }
+
+    /* Check access permissions */
+    if (!cp_access_ok(s->current_pl, ri, isread)) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    /* Handle special cases first */
+    switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
+    case ARM_CP_NOP:
+        return;
+    default:
+        break;
+    }
+
+    if (use_icount && (ri->type & ARM_CP_IO)) {
+        gen_io_start();
+    }
+
+    tcg_rt = cpu_reg(s, rt);
+
+    if (isread) {
+        if (ri->type & ARM_CP_CONST) {
+            tcg_gen_movi_i64(tcg_rt, ri->resetvalue);
+        } else if (ri->readfn) {
+            TCGv_ptr tmpptr;
+            gen_a64_set_pc_im(s->pc - 4);
+            tmpptr = tcg_const_ptr(ri);
+            gen_helper_get_cp_reg64(tcg_rt, cpu_env, tmpptr);
+            tcg_temp_free_ptr(tmpptr);
+        } else {
+            tcg_gen_ld_i64(tcg_rt, cpu_env, ri->fieldoffset);
+        }
+    } else {
+        if (ri->type & ARM_CP_CONST) {
+            /* If not forbidden by access permissions, treat as WI */
+            return;
+        } else if (ri->writefn) {
+            TCGv_ptr tmpptr;
+            gen_a64_set_pc_im(s->pc - 4);
+            tmpptr = tcg_const_ptr(ri);
+            gen_helper_set_cp_reg64(cpu_env, tmpptr, tcg_rt);
+            tcg_temp_free_ptr(tmpptr);
+        } else {
+            tcg_gen_st_i64(tcg_rt, cpu_env, ri->fieldoffset);
+        }
+    }
+
+    if (use_icount && (ri->type & ARM_CP_IO)) {
+        /* I/O operations must end the TB here (whether read or write) */
+        gen_io_end();
+        s->is_jmp = DISAS_UPDATE;
+    } else if (!isread && !(ri->type & ARM_CP_SUPPRESS_TB_END)) {
+        /* We default to ending the TB on a coprocessor register write,
+         * but allow this to be suppressed by the register definition
+         * (usually only necessary to work around guest bugs).
+         */
+        s->is_jmp = DISAS_UPDATE;
+    }
 }
 
 /* C3.2.4 System
@@ -795,17 +855,7 @@ static void disas_system(DisasContext *s, uint32_t insn)
         }
         return;
     }
-
-    if (op0 == 1) {
-        /* C5.6.204 SYS */
-        handle_sys(s, insn, l, op1, op2, crn, crm, rt);
-    } else if (l) { /* op0 > 1 */
-        /* C5.6.129 MRS - move from system register */
-        handle_mrs(s, insn, op0, op1, op2, crn, crm, rt);
-    } else {
-        /* C5.6.131 MSR (register) - move to system register */
-        handle_msr(s, insn, op0, op1, op2, crn, crm, rt);
-    }
+    handle_sys(s, insn, l, op0, op1, op2, crn, crm, rt);
 }
 
 /* C3.2.3 Exception generation
@@ -3098,8 +3148,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
             gen_goto_tb(dc, 1, dc->pc);
             break;
         default:
-        case DISAS_JUMP:
         case DISAS_UPDATE:
+            gen_a64_set_pc_im(dc->pc);
+            /* fall through */
+        case DISAS_JUMP:
             /* indicate that the hash table must be used to find the next TB */
             tcg_gen_exit_tb(0);
             break;
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (13 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 14/25] target-arm: A64: Implement MRS/MSR/SYS/SYSL Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2014-01-04  2:34   ` Peter Crosthwaite
  2014-01-04 13:32   ` Peter Crosthwaite
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits Peter Maydell
                   ` (9 subsequent siblings)
  24 siblings, 2 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Implement an initial minimal set of EL0-visible system registers:
 * NZCV
 * FPCR
 * FPSR
 * CTR_EL0
 * DCZID_EL0

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/cpu.h           |  3 ++-
 target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 66490ce..1e0800e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_IO 64
 #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
 #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
-#define ARM_LAST_SPECIAL ARM_CP_WFI
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
+#define ARM_LAST_SPECIAL ARM_CP_NZCV
 /* 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/helper.c b/target-arm/helper.c
index 66214293..ca27c8e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpcr(env);
+    return 0;
+}
+
+static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpcr(env, value);
+    return 0;
+}
+
+static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpsr(env);
+    return 0;
+}
+
+static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpsr(env, value);
+    return 0;
+}
+
+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.
+     */
+    { .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 = "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 },
+    {. 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 },
+    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
+     * It will eventually need to have a CPU-specified reset value.
+     */
+    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
+      .access = PL0_R, .type = ARM_CP_CONST,
+      .resetvalue = 0x80030003 },
+    /* 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 },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
     } else {
         define_arm_cp_regs(cpu, not_v7_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        define_arm_cp_regs(cpu, v8_cp_reginfo);
+    }
     if (arm_feature(env, ARM_FEATURE_MPU)) {
         /* These are the MPU registers prior to PMSAv6. Any new
          * PMSA core later than the ARM946 will require that we
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7a9ee82..c8ed799 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
     unsupported_encoding(s, insn);
 }
 
+static void gen_get_nzcv(TCGv_i64 tcg_rt)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* build bit 31, N */
+    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
+    /* build bit 30, Z */
+    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
+    /* build bit 29, C */
+    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
+    /* build bit 28, V */
+    tcg_gen_shri_i32(tmp, cpu_VF, 31);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
+    /* generate result */
+    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
+
+    tcg_temp_free_i32(nzcv);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_set_nzcv(TCGv_i64 tcg_rt)
+
+{
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* take NZCV from R[t] */
+    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
+
+    /* bit 31, N */
+    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
+    /* bit 30, Z */
+    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
+    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
+    /* bit 29, C */
+    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
+    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
+    /* bit 28, V */
+    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
+    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
+    tcg_temp_free_i32(nzcv);
+}
+
 /* C5.6.129 MRS - move from system register
  * C5.6.131 MSR (register) - move to system register
  * C5.6.204 SYS
@@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
     switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
     case ARM_CP_NOP:
         return;
+    case ARM_CP_NZCV:
+        tcg_rt = cpu_reg(s, rt);
+        if (isread) {
+            gen_get_nzcv(tcg_rt);
+        } else {
+            gen_set_nzcv(tcg_rt);
+        }
+        return;
     default:
         break;
     }
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (14 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-23 20:23   ` Richard Henderson
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 17/25] target-arm: A64: add support for add/sub with carry Peter Maydell
                   ` (8 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

The common pattern for system registers in a 64-bit capable ARM
CPU is that when in AArch32 the cp15 register is a view of the
bottom 32 bits of the 64-bit AArch64 system register; writes in
AArch32 leave the top half unchanged. The most natural way to
model this is to have the state field in the CPU struct be a
64 bit value, and simply have the AArch32 TCG code operate on
a pointer to its lower half.

For aarch64-linux-user the only registers we need to share like
this are the thread-local-storage ones. Widen their fields to
64 bits and provide the 64 bit reginfo struct to make them
visible in AArch64 state. Note that minor cleanup of the AArch64
system register encoding space means We can share the TPIDR_EL1
reginfo but need split encodings for TPIDR_EL0 and TPIDRRO_EL0.

Since we're touching almost every line in QEMU that uses the
c13_tls* fields in this patch anyway, we take the opportunity
to rename them in line with the standard ARM architectural names
for these registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/aarch64/target_cpu.h |  5 ++++-
 linux-user/arm/target_cpu.h     |  2 +-
 linux-user/main.c               |  2 +-
 target-arm/cpu.h                | 18 +++++++++++++++---
 target-arm/helper.c             | 22 +++++++++++++++-------
 5 files changed, 36 insertions(+), 13 deletions(-)

diff --git a/linux-user/aarch64/target_cpu.h b/linux-user/aarch64/target_cpu.h
index 6f5539b..21560ef 100644
--- a/linux-user/aarch64/target_cpu.h
+++ b/linux-user/aarch64/target_cpu.h
@@ -29,7 +29,10 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
 
 static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
 {
-    env->sr.tpidr_el0 = newtls;
+    /* Note that AArch64 Linux keeps the TLS pointer in TPIDR; this is
+     * different from AArch32 Linux, which uses TPIDRRO.
+     */
+    env->cp15.tpidr_el0 = newtls;
 }
 
 #endif
diff --git a/linux-user/arm/target_cpu.h b/linux-user/arm/target_cpu.h
index ed323c0..39d65b6 100644
--- a/linux-user/arm/target_cpu.h
+++ b/linux-user/arm/target_cpu.h
@@ -29,7 +29,7 @@ static inline void cpu_clone_regs(CPUARMState *env, target_ulong newsp)
 
 static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
 {
-    env->cp15.c13_tls2 = newtls;
+    env->cp15.tpidrro_el0 = newtls;
 }
 
 #endif
diff --git a/linux-user/main.c b/linux-user/main.c
index 54f71fe..c0df8b5 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -566,7 +566,7 @@ do_kernel_trap(CPUARMState *env)
         end_exclusive();
         break;
     case 0xffff0fe0: /* __kernel_get_tls */
-        env->regs[0] = env->cp15.c13_tls2;
+        env->regs[0] = env->cp15.tpidrro_el0;
         break;
     case 0xffff0f60: /* __kernel_cmpxchg64 */
         arm_kernel_cmpxchg64_helper(env);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 1e0800e..45f8973 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -66,6 +66,18 @@
 /* ARM-specific interrupt pending bits.  */
 #define CPU_INTERRUPT_FIQ   CPU_INTERRUPT_TGT_EXT_1
 
+/* The usual mapping for an AArch64 system register to its AArch32
+ * counterpart is for the 32 bit world to have access to the lower
+ * half only (with writes leaving the upper half untouched). It's
+ * therefore useful to be able to pass TCG the offset of the least
+ * significant half of a uint64_t struct member.
+ */
+#ifdef HOST_WORDS_BIGENDIAN
+#define offsetoflow32(S, M) (offsetof(S, M + sizeof(uint32_t))
+#else
+#define offsetoflow32(S, M) offsetof(S, M)
+#endif
+
 /* Meanings of the ARMCPU object's two inbound GPIO lines */
 #define ARM_CPU_IRQ 0
 #define ARM_CPU_FIQ 1
@@ -188,9 +200,9 @@ typedef struct CPUARMState {
         uint32_t c12_vbar; /* vector base address register */
         uint32_t c13_fcse; /* FCSE PID.  */
         uint32_t c13_context; /* Context ID.  */
-        uint32_t c13_tls1; /* User RW Thread register.  */
-        uint32_t c13_tls2; /* User RO Thread register.  */
-        uint32_t c13_tls3; /* Privileged Thread register.  */
+        uint64_t tpidr_el0; /* User RW Thread register.  */
+        uint64_t tpidrro_el0; /* User RO Thread register.  */
+        uint64_t tpidr_el1; /* Privileged Thread register.  */
         uint32_t c14_cntfrq; /* Counter Frequency register */
         uint32_t c14_cntkctl; /* Timer Control register */
         ARMGenericTimer c14_timer[NUM_GTIMERS];
diff --git a/target-arm/helper.c b/target-arm/helper.c
index ca27c8e..0e7ba06 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -740,18 +740,26 @@ static const ARMCPRegInfo t2ee_cp_reginfo[] = {
 };
 
 static const ARMCPRegInfo v6k_cp_reginfo[] = {
+    { .name = "TPIDR_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 2, .crn = 13, .crm = 0,
+      .access = PL0_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el0), .resetvalue = 0 },
     { .name = "TPIDRURW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 2,
       .access = PL0_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c13_tls1),
-      .resetvalue = 0 },
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidr_el0),
+      .resetfn = arm_cp_reset_ignore },
+    { .name = "TPIDRRO_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 3, .crn = 13, .crm = 0,
+      .access = PL0_R|PL1_W,
+      .fieldoffset = offsetof(CPUARMState, cp15.tpidrro_el0), .resetvalue = 0 },
     { .name = "TPIDRURO", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 3,
       .access = PL0_R|PL1_W,
-      .fieldoffset = offsetof(CPUARMState, cp15.c13_tls2),
-      .resetvalue = 0 },
-    { .name = "TPIDRPRW", .cp = 15, .crn = 13, .crm = 0, .opc1 = 0, .opc2 = 4,
+      .fieldoffset = offsetoflow32(CPUARMState, cp15.tpidrro_el0),
+      .resetfn = arm_cp_reset_ignore },
+    { .name = "TPIDR_EL1", .state = ARM_CP_STATE_BOTH,
+      .opc0 = 3, .opc1 = 0, .opc2 = 4, .crn = 13, .crm = 0,
       .access = PL1_RW,
-      .fieldoffset = offsetof(CPUARMState, cp15.c13_tls3),
-      .resetvalue = 0 },
+      .fieldoffset = offsetof(CPUARMState, cp15.tpidr_el1), .resetvalue = 0 },
     REGINFO_SENTINEL
 };
 
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 17/25] target-arm: A64: add support for add/sub with carry
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (15 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits Peter Maydell
@ 2013-12-22 22:49 ` Peter Maydell
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns Peter Maydell
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:49 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Claudio Fontana <claudio.fontana@linaro.org>

This patch adds support for C3.5.3 Add/subtract (with carry):
instructions ADC, ADCS, SBC, SBCS.

Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 105 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 103 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index c8ed799..9f508b9 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -393,6 +393,71 @@ static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
     }
 }
 
+/* dest = T0 + T1 + CF; do not compute flags. */
+static void gen_adc(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    TCGv_i64 flag = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(flag, cpu_CF);
+    tcg_gen_add_i64(dest, t0, t1);
+    tcg_gen_add_i64(dest, dest, flag);
+    tcg_temp_free_i64(flag);
+
+    if (!sf) {
+        tcg_gen_ext32u_i64(dest, dest);
+    }
+}
+
+/* dest = T0 + T1 + CF; compute C, N, V and Z flags. */
+static void gen_adc_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    if (sf) {
+        TCGv_i64 result, cf_64, vf_64, tmp;
+        result = tcg_temp_new_i64();
+        cf_64 = tcg_temp_new_i64();
+        vf_64 = tcg_temp_new_i64();
+        tmp = tcg_const_i64(0);
+
+        tcg_gen_extu_i32_i64(cf_64, cpu_CF);
+        tcg_gen_add2_i64(result, cf_64, t0, tmp, cf_64, tmp);
+        tcg_gen_add2_i64(result, cf_64, result, cf_64, t1, tmp);
+        tcg_gen_trunc_i64_i32(cpu_CF, cf_64);
+        gen_set_NZ64(result);
+
+        tcg_gen_xor_i64(vf_64, result, t0);
+        tcg_gen_xor_i64(tmp, t0, t1);
+        tcg_gen_andc_i64(vf_64, vf_64, tmp);
+        tcg_gen_shri_i64(vf_64, vf_64, 32);
+        tcg_gen_trunc_i64_i32(cpu_VF, vf_64);
+
+        tcg_gen_mov_i64(dest, result);
+
+        tcg_temp_free_i64(tmp);
+        tcg_temp_free_i64(vf_64);
+        tcg_temp_free_i64(cf_64);
+        tcg_temp_free_i64(result);
+    } else {
+        TCGv_i32 t0_32, t1_32, tmp;
+        t0_32 = tcg_temp_new_i32();
+        t1_32 = tcg_temp_new_i32();
+        tmp = tcg_const_i32(0);
+
+        tcg_gen_trunc_i64_i32(t0_32, t0);
+        tcg_gen_trunc_i64_i32(t1_32, t1);
+        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, cpu_CF, tmp);
+        tcg_gen_add2_i32(cpu_NF, cpu_CF, cpu_NF, cpu_CF, t1_32, tmp);
+
+        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
+        tcg_gen_xor_i32(tmp, t0_32, t1_32);
+        tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
+        tcg_gen_extu_i32_i64(dest, cpu_NF);
+
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(t1_32);
+        tcg_temp_free_i32(t0_32);
+    }
+}
+
 /*
  * Load/Store generators
  */
@@ -2376,10 +2441,46 @@ static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_tmp);
 }
 
-/* Add/subtract (with carry) */
+/* C3.5.3 - Add/subtract (with carry)
+ *  31 30 29 28 27 26 25 24 23 22 21  20  16  15   10  9    5 4   0
+ * +--+--+--+------------------------+------+---------+------+-----+
+ * |sf|op| S| 1  1  0  1  0  0  0  0 |  rm  | opcode2 |  Rn  |  Rd |
+ * +--+--+--+------------------------+------+---------+------+-----+
+ *                                            [000000]
+ */
+
 static void disas_adc_sbc(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    unsigned int sf, op, setflags, rm, rn, rd;
+    TCGv_i64 tcg_y, tcg_rn, tcg_rd;
+
+    if (extract32(insn, 10, 6) != 0) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    sf = extract32(insn, 31, 1);
+    op = extract32(insn, 30, 1);
+    setflags = extract32(insn, 29, 1);
+    rm = extract32(insn, 16, 5);
+    rn = extract32(insn, 5, 5);
+    rd = extract32(insn, 0, 5);
+
+    tcg_rd = cpu_reg(s, rd);
+    tcg_rn = cpu_reg(s, rn);
+
+    if (op) {
+        tcg_y = new_tmp_a64(s);
+        tcg_gen_not_i64(tcg_y, cpu_reg(s, rm));
+    } else {
+        tcg_y = cpu_reg(s, rm);
+    }
+
+    if (setflags) {
+        gen_adc_CC(sf, tcg_rd, tcg_rn, tcg_y);
+    } else {
+        gen_adc(sf, tcg_rd, tcg_rn, tcg_y);
+    }
 }
 
 /* Conditional compare (immediate) */
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (16 preceding siblings ...)
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 17/25] target-arm: A64: add support for add/sub with carry Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-23 20:37   ` Richard Henderson
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 19/25] target-arm: aarch64: add support for ld lit Peter Maydell
                   ` (6 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Claudio Fontana <claudio.fontana@linaro.org>

this patch adds support for C3.5.4 - C3.5.5
Conditional compare (both immediate and register)

Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 73 +++++++++++++++++++++++++++++++++++++---------
 1 file changed, 60 insertions(+), 13 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 9f508b9..538d69e 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2483,16 +2483,67 @@ static void disas_adc_sbc(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Conditional compare (immediate) */
-static void disas_cc_imm(DisasContext *s, uint32_t insn)
+/* C3.5.4 - C3.5.5 Conditional compare (immediate / register)
+ *  31 30 29 28 27 26 25 24 23 22 21  20    16 15  12  11  10  9   5  4 3   0
+ * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
+ * |sf|op| S| 1  1  0  1  0  0  1  0 |imm5/rm | cond |i/r |o2|  Rn  |o3|nzcv |
+ * +--+--+--+------------------------+--------+------+----+--+------+--+-----+
+ *        [1]                             y                [0]       [0]
+ */
+static void disas_cc(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
-}
+    unsigned int sf, op, y, cond, rn, nzcv, is_imm;
+    int label_continue = -1;
+    TCGv_i64 tcg_tmp, tcg_y, tcg_rn;
 
-/* Conditional compare (register) */
-static void disas_cc_reg(DisasContext *s, uint32_t insn)
-{
-    unsupported_encoding(s, insn);
+    if (!extract32(insn, 29, 1)) {
+        unallocated_encoding(s);
+        return;
+    }
+    if (insn & (1 << 10 | 1 << 4)) {
+        unallocated_encoding(s);
+        return;
+    }
+    sf = extract32(insn, 31, 1);
+    op = extract32(insn, 30, 1);
+    is_imm = extract32(insn, 11, 1);
+    y = extract32(insn, 16, 5); /* y = rm (reg) or imm5 (imm) */
+    cond = extract32(insn, 12, 4);
+    rn = extract32(insn, 5, 5);
+    nzcv = extract32(insn, 0, 4);
+
+    if (cond < 0x0e) { /* not always */
+        int label_match = gen_new_label();
+        label_continue = gen_new_label();
+        arm_gen_test_cc(cond, label_match);
+        /* nomatch: */
+        tcg_tmp = tcg_temp_new_i64();
+        tcg_gen_movi_i64(tcg_tmp, nzcv << 28);
+        gen_set_nzcv(tcg_tmp);
+        tcg_temp_free_i64(tcg_tmp);
+        tcg_gen_br(label_continue);
+        gen_set_label(label_match);
+    }
+    /* match, or condition is always */
+    if (is_imm) {
+        tcg_y = new_tmp_a64(s);
+        tcg_gen_movi_i64(tcg_y, y);
+    } else {
+        tcg_y = cpu_reg(s, y);
+    }
+    tcg_rn = cpu_reg(s, rn);
+
+    tcg_tmp = tcg_temp_new_i64();
+    if (op) {
+        gen_sub_CC(sf, tcg_tmp, tcg_rn, tcg_y);
+    } else {
+        gen_add_CC(sf, tcg_tmp, tcg_rn, tcg_y);
+    }
+    tcg_temp_free_i64(tcg_tmp);
+
+    if (cond < 0x0e) { /* continue */
+        gen_set_label(label_continue);
+    }
 }
 
 /* C3.5.6 Conditional select
@@ -2846,11 +2897,7 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
             disas_adc_sbc(s, insn);
             break;
         case 0x2: /* Conditional compare */
-            if (insn & (1 << 11)) { /* (immediate) */
-                disas_cc_imm(s, insn);
-            } else {            /* (register) */
-                disas_cc_reg(s, insn);
-            }
+            disas_cc(s, insn); /* both imm and reg forms */
             break;
         case 0x4: /* Conditional select */
             disas_cond_select(s, insn);
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 19/25] target-arm: aarch64: add support for ld lit
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (17 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits Peter Maydell
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alexander Graf <agraf@suse.de>

Adds support for Load Register (literal), both normal
and SIMD/FP forms.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/translate-a64.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 538d69e..6197441 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1112,10 +1112,53 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
     unsupported_encoding(s, insn);
 }
 
-/* Load register (literal) */
+/*
+ * C3.3.5 Load register (literal)
+ *
+ *  31 30 29   27  26 25 24 23                5 4     0
+ * +-----+-------+---+-----+-------------------+-------+
+ * | opc | 0 1 1 | V | 0 0 |     imm19         |  Rt   |
+ * +-----+-------+---+-----+-------------------+-------+
+ *
+ * V: 1 -> vector (simd/fp)
+ * opc (non-vector): 00 -> 32 bit, 01 -> 64 bit,
+ *                   10-> 32 bit signed, 11 -> prefetch
+ * opc (vector): 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit (11 unallocated)
+ */
 static void disas_ld_lit(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rt = extract32(insn, 0, 5);
+    int64_t imm = sextract32(insn, 5, 19) << 2;
+    bool is_vector = extract32(insn, 26, 1);
+    int opc = extract32(insn, 30, 2);
+    bool is_signed = false;
+    int size = 2;
+    TCGv_i64 tcg_rt, tcg_addr;
+
+    if (is_vector) {
+        if (opc == 3) {
+            unallocated_encoding(s);
+            return;
+        }
+        size = 2 + opc;
+    } else {
+        if (opc == 3) {
+            /* PRFM (literal) : prefetch */
+            return;
+        }
+        size = 2 + extract32(opc, 0, 1);
+        is_signed = extract32(opc, 1, 1);
+    }
+
+    tcg_rt = cpu_reg(s, rt);
+
+    tcg_addr = tcg_const_i64((s->pc - 4) + imm);
+    if (is_vector) {
+        do_fp_ld(s, rt, tcg_addr, size);
+    } else {
+        do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
+    }
+    tcg_temp_free_i64(tcg_addr);
 }
 
 /*
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (18 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 19/25] target-arm: aarch64: add support for ld lit Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-23 21:27   ` Richard Henderson
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive Peter Maydell
                   ` (4 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

In preparation for adding support for A64 load/store exclusive instructions,
widen the fields in the CPU state struct that deal with address and data values
for exclusives from 32 to 64 bits. Although in practice AArch64 and AArch32
exclusive accesses will be generally separate there are some odd theoretical
corner cases (eg you should be able to do the exclusive load in AArch32, take
an exception to AArch64 and successfully do the store exclusive there), and it's
also easier to reason about.

The changes in semantics for the variables are:
 exclusive_addr  -> extended to 64 bits; -1ULL for "monitor lost",
   otherwise always < 2^32 for AArch32
 exclusive_val   -> extended to 64 bits. 64 bit exclusives in AArch32 now
   use the high half of exclusive_val instead of a separate exclusive_high
 exclusive_high  -> is no longer used in AArch32; extended to 64 bits as
   it will be needed for AArch64's pair-of-64-bit-values exclusives.
 exclusive_test  -> extended to 64 bits, as it is an address. Since this is
   a linux-user-only field, in arm-linux-user it will always have the top
   32 bits zero.
 exclusive_info  -> stays 32 bits, as it is neither data nor address, but
   simply holds register indexes etc. AArch64 will be able to fit all its
   information into 32 bits as well.

Note that the refactoring of gen_store_exclusive() coincidentally fixes
a minor bug where ldrexd would incorrectly update the first CPU register
even if the load for the second register faulted.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/main.c      | 25 +++++++++++--------
 target-arm/cpu.h       |  8 +++----
 target-arm/machine.c   | 12 +++++-----
 target-arm/translate.c | 65 ++++++++++++++++++++++++++++++--------------------
 4 files changed, 64 insertions(+), 46 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index c0df8b5..20f9832 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -589,16 +589,21 @@ do_kernel_trap(CPUARMState *env)
 
 static int do_strex(CPUARMState *env)
 {
-    uint32_t val;
+    uint64_t val;
     int size;
     int rc = 1;
     int segv = 0;
     uint32_t addr;
     start_exclusive();
-    addr = env->exclusive_addr;
-    if (addr != env->exclusive_test) {
+    if (env->exclusive_addr != env->exclusive_test) {
         goto fail;
     }
+    /* We know we're always AArch32 so the address is in uint32_t range
+     * unless it was the -1 exclusive-monitor-lost value (which won't
+     * match exclusive_test above).
+     */
+    assert(extract64(env->exclusive_addr, 32, 32) == 0);
+    addr = env->exclusive_addr;
     size = env->exclusive_info & 0xf;
     switch (size) {
     case 0:
@@ -618,19 +623,19 @@ static int do_strex(CPUARMState *env)
         env->cp15.c6_data = addr;
         goto done;
     }
-    if (val != env->exclusive_val) {
-        goto fail;
-    }
     if (size == 3) {
-        segv = get_user_u32(val, addr + 4);
+        uint32_t valhi;
+        segv = get_user_u32(valhi, addr + 4);
         if (segv) {
             env->cp15.c6_data = addr + 4;
             goto done;
         }
-        if (val != env->exclusive_high) {
-            goto fail;
-        }
+        val = deposit64(val, 32, 32, valhi);
+    }
+    if (val != env->exclusive_val) {
+        goto fail;
     }
+
     val = env->regs[(env->exclusive_info >> 8) & 0xf];
     switch (size) {
     case 0:
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 45f8973..6c84e22 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -278,11 +278,11 @@ typedef struct CPUARMState {
         float_status fp_status;
         float_status standard_fp_status;
     } vfp;
-    uint32_t exclusive_addr;
-    uint32_t exclusive_val;
-    uint32_t exclusive_high;
+    uint64_t exclusive_addr;
+    uint64_t exclusive_val;
+    uint64_t exclusive_high;
 #if defined(CONFIG_USER_ONLY)
-    uint32_t exclusive_test;
+    uint64_t exclusive_test;
     uint32_t exclusive_info;
 #endif
 
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 74f010f..8f9e7d4 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 = 13,
-    .minimum_version_id = 13,
-    .minimum_version_id_old = 13,
+    .version_id = 14,
+    .minimum_version_id = 14,
+    .minimum_version_id_old = 14,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -253,9 +253,9 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_VARRAY_INT32(cpreg_vmstate_values, ARMCPU,
                              cpreg_vmstate_array_len,
                              0, vmstate_info_uint64, uint64_t),
-        VMSTATE_UINT32(env.exclusive_addr, ARMCPU),
-        VMSTATE_UINT32(env.exclusive_val, ARMCPU),
-        VMSTATE_UINT32(env.exclusive_high, ARMCPU),
+        VMSTATE_UINT64(env.exclusive_addr, ARMCPU),
+        VMSTATE_UINT64(env.exclusive_val, ARMCPU),
+        VMSTATE_UINT64(env.exclusive_high, ARMCPU),
         VMSTATE_UINT64(env.features, ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
         VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 8bfe950..4387547 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -61,11 +61,10 @@ TCGv_ptr cpu_env;
 static TCGv_i64 cpu_V0, cpu_V1, cpu_M0;
 static TCGv_i32 cpu_R[16];
 static TCGv_i32 cpu_CF, cpu_NF, cpu_VF, cpu_ZF;
-static TCGv_i32 cpu_exclusive_addr;
-static TCGv_i32 cpu_exclusive_val;
-static TCGv_i32 cpu_exclusive_high;
+static TCGv_i64 cpu_exclusive_addr;
+static TCGv_i64 cpu_exclusive_val;
 #ifdef CONFIG_USER_ONLY
-static TCGv_i32 cpu_exclusive_test;
+static TCGv_i64 cpu_exclusive_test;
 static TCGv_i32 cpu_exclusive_info;
 #endif
 
@@ -96,14 +95,12 @@ void arm_translate_init(void)
     cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
     cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
 
-    cpu_exclusive_addr = tcg_global_mem_new_i32(TCG_AREG0,
+    cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
         offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
-    cpu_exclusive_val = tcg_global_mem_new_i32(TCG_AREG0,
+    cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
         offsetof(CPUARMState, exclusive_val), "exclusive_val");
-    cpu_exclusive_high = tcg_global_mem_new_i32(TCG_AREG0,
-        offsetof(CPUARMState, exclusive_high), "exclusive_high");
 #ifdef CONFIG_USER_ONLY
-    cpu_exclusive_test = tcg_global_mem_new_i32(TCG_AREG0,
+    cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
         offsetof(CPUARMState, exclusive_test), "exclusive_test");
     cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
         offsetof(CPUARMState, exclusive_info), "exclusive_info");
@@ -6758,30 +6755,34 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
     default:
         abort();
     }
-    tcg_gen_mov_i32(cpu_exclusive_val, tmp);
-    store_reg(s, rt, tmp);
+
     if (size == 3) {
         TCGv_i32 tmp2 = tcg_temp_new_i32();
+        TCGv_i32 tmp3 = tcg_temp_new_i32();
+
         tcg_gen_addi_i32(tmp2, addr, 4);
-        tmp = tcg_temp_new_i32();
-        gen_aa32_ld32u(tmp, tmp2, IS_USER(s));
+        gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
         tcg_temp_free_i32(tmp2);
-        tcg_gen_mov_i32(cpu_exclusive_high, tmp);
-        store_reg(s, rt2, tmp);
+        tcg_gen_concat_i32_i64(cpu_exclusive_val, tmp, tmp3);
+        store_reg(s, rt2, tmp3);
+    } else {
+        tcg_gen_extu_i32_i64(cpu_exclusive_val, tmp);
     }
-    tcg_gen_mov_i32(cpu_exclusive_addr, addr);
+
+    store_reg(s, rt, tmp);
+    tcg_gen_extu_i32_i64(cpu_exclusive_addr, addr);
 }
 
 static void gen_clrex(DisasContext *s)
 {
-    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
 }
 
 #ifdef CONFIG_USER_ONLY
 static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
                                 TCGv_i32 addr, int size)
 {
-    tcg_gen_mov_i32(cpu_exclusive_test, addr);
+    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);
@@ -6791,6 +6792,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
                                 TCGv_i32 addr, int size)
 {
     TCGv_i32 tmp;
+    TCGv_i64 val64, extaddr;
     int done_label;
     int fail_label;
 
@@ -6802,7 +6804,11 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
        } */
     fail_label = gen_new_label();
     done_label = gen_new_label();
-    tcg_gen_brcond_i32(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
+    extaddr = tcg_temp_new_i64();
+    tcg_gen_extu_i32_i64(extaddr, addr);
+    tcg_gen_brcond_i64(TCG_COND_NE, extaddr, cpu_exclusive_addr, fail_label);
+    tcg_temp_free_i64(extaddr);
+
     tmp = tcg_temp_new_i32();
     switch (size) {
     case 0:
@@ -6818,17 +6824,24 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     default:
         abort();
     }
-    tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
-    tcg_temp_free_i32(tmp);
+
+    val64 = tcg_temp_new_i64();
     if (size == 3) {
         TCGv_i32 tmp2 = tcg_temp_new_i32();
+        TCGv_i32 tmp3 = tcg_temp_new_i32();
         tcg_gen_addi_i32(tmp2, addr, 4);
-        tmp = tcg_temp_new_i32();
-        gen_aa32_ld32u(tmp, tmp2, IS_USER(s));
+        gen_aa32_ld32u(tmp3, tmp2, IS_USER(s));
         tcg_temp_free_i32(tmp2);
-        tcg_gen_brcond_i32(TCG_COND_NE, tmp, cpu_exclusive_high, fail_label);
-        tcg_temp_free_i32(tmp);
+        tcg_gen_concat_i32_i64(val64, tmp, tmp3);
+        tcg_temp_free_i32(tmp3);
+    } else {
+        tcg_gen_extu_i32_i64(val64, tmp);
     }
+    tcg_temp_free_i32(tmp);
+
+    tcg_gen_brcond_i64(TCG_COND_NE, val64, cpu_exclusive_val, fail_label);
+    tcg_temp_free_i64(val64);
+
     tmp = load_reg(s, rt);
     switch (size) {
     case 0:
@@ -6856,7 +6869,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
     gen_set_label(fail_label);
     tcg_gen_movi_i32(cpu_R[rd], 1);
     gen_set_label(done_label);
-    tcg_gen_movi_i32(cpu_exclusive_addr, -1);
+    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
 }
 #endif
 
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (19 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-23 21:34   ` Richard Henderson
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS Peter Maydell
                   ` (3 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Michael Matz <matz@suse.de>

This implement exclusive loads/stores for aarch64 along the lines of
arm32 and ppc implementations. The exclusive load remembers the address
and loaded value. The exclusive store throws an an exception which uses
those values to check for equality in a proper exclusive region.

This is not actually the architecture mandated semantics (for either
AArch32 or AArch64) but it is close enough for typical guest code
sequences to work correctly, and saves us from having to monitor all
guest stores. It's fairly easy to come up with test cases where we
don't behave like hardware - we don't for example model cache line
behaviour. However in the common patterns this works, and the existing
32 bit ARM exclusive access implementation has the same limitations.

AArch64 also implements new acquire/release loads/stores (which may be
either exclusive or non-exclusive). These imposes extra ordering
constraints on memory operations (ie they act as if they have an implicit
barrier built into them). As TCG is single-threaded all our barriers
are no-ops, so these just behave like normal loads and stores.

Signed-off-by: Michael Matz <matz@suse.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/main.c          | 127 +++++++++++++++++++++++++++++++++++-
 target-arm/translate-a64.c | 156 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 277 insertions(+), 6 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index 20f9832..cabc9e1 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -585,8 +585,8 @@ do_kernel_trap(CPUARMState *env)
 
     return 0;
 }
-#endif
 
+/* Store exclusive handling for AArch32 */
 static int do_strex(CPUARMState *env)
 {
     uint64_t val;
@@ -670,7 +670,6 @@ done:
     return segv;
 }
 
-#ifdef TARGET_ABI32
 void cpu_loop(CPUARMState *env)
 {
     CPUState *cs = CPU(arm_env_get_cpu(env));
@@ -885,6 +884,122 @@ void cpu_loop(CPUARMState *env)
 
 #else
 
+/*
+ * Handle AArch64 store-release exclusive
+ *
+ * rs = gets the status result of store exclusive
+ * rt = is the register that is stored
+ * rt2 = is the second register store (in STP)
+ *
+ */
+static int do_strex_a64(CPUARMState *env)
+{
+    uint64_t val;
+    int size;
+    bool is_pair;
+    int rc = 1;
+    int segv = 0;
+    uint64_t addr;
+    int rs, rt, rt2;
+
+    start_exclusive();
+    /* size | is_pair << 2 | (rs << 4) | (rt << 9) | (rt2 << 14)); */
+    size = extract32(env->exclusive_info, 0, 2);
+    is_pair = extract32(env->exclusive_info, 2, 1);
+    rs = extract32(env->exclusive_info, 4, 5);
+    rt = extract32(env->exclusive_info, 9, 5);
+    rt2 = extract32(env->exclusive_info, 14, 5);
+
+    addr = env->exclusive_addr;
+
+    if (addr != env->exclusive_test) {
+        goto finish;
+    }
+
+    switch (size) {
+    case 0:
+        segv = get_user_u8(val, addr);
+        break;
+    case 1:
+        segv = get_user_u16(val, addr);
+        break;
+    case 2:
+        segv = get_user_u32(val, addr);
+        break;
+    case 3:
+        segv = get_user_u64(val, addr);
+        break;
+    default:
+        abort();
+    }
+    if (segv) {
+        env->cp15.c6_data = addr;
+        goto error;
+    }
+    if (val != env->exclusive_val) {
+        goto finish;
+    }
+    if (is_pair) {
+        if (size == 2) {
+            segv = get_user_u32(val, addr + 4);
+        } else {
+            segv = get_user_u64(val, addr + 8);
+        }
+        if (segv) {
+            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+            goto error;
+        }
+        if (val != env->exclusive_high) {
+            goto finish;
+        }
+    }
+    val = env->xregs[rt];
+    switch (size) {
+    case 0:
+        segv = put_user_u8(val, addr);
+        break;
+    case 1:
+        segv = put_user_u16(val, addr);
+        break;
+    case 2:
+        segv = put_user_u32(val, addr);
+        break;
+    case 3:
+        segv = put_user_u64(val, addr);
+        break;
+    }
+    if (segv) {
+        goto error;
+    }
+    if (is_pair) {
+        val = env->xregs[rt2];
+        if (size == 2) {
+            segv = put_user_u32(val, addr + 4);
+        } else {
+            segv = put_user_u64(val, addr + 8);
+        }
+        if (segv) {
+            env->cp15.c6_data = addr + (size == 2 ? 4 : 8);
+            goto error;
+        }
+    }
+    rc = 0;
+finish:
+    env->pc += 4;
+    /* rs == 31 encodes a write to the ZR, thus throwing away
+     * the status return. This is rather silly but valid.
+     */
+    if (rs < 31) {
+        env->xregs[rs] = rc;
+    }
+error:
+    /* instruction faulted, PC does not advance */
+    /* either way a strex releases any exclusive lock we have */
+    env->exclusive_addr = -1;
+    end_exclusive();
+    return segv;
+}
+
 /* AArch64 main loop */
 void cpu_loop(CPUARMState *env)
 {
@@ -944,7 +1059,7 @@ void cpu_loop(CPUARMState *env)
             }
             break;
         case EXCP_STREX:
-            if (do_strex(env)) {
+            if (do_strex_a64(env)) {
                 addr = env->cp15.c6_data;
                 goto do_segv;
             }
@@ -956,6 +1071,12 @@ void cpu_loop(CPUARMState *env)
             abort();
         }
         process_pending_signals(env);
+        /* Exception return on AArch64 always clears the exclusive monitor,
+         * so any return to running guest code implies this.
+         * A strex (successful or otherwise) also clears the monitor, so
+         * we don't need to specialcase EXCP_STREX.
+         */
+        env->exclusive_addr = -1;
     }
 }
 #endif /* ndef TARGET_ABI32 */
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 6197441..40c6fc4 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -38,6 +38,15 @@ static TCGv_i64 cpu_X[32];
 static TCGv_i64 cpu_pc;
 static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
 
+/* Load/store exclusive handling */
+static TCGv_i64 cpu_exclusive_addr;
+static TCGv_i64 cpu_exclusive_val;
+static TCGv_i64 cpu_exclusive_high;
+#ifdef CONFIG_USER_ONLY
+static TCGv_i64 cpu_exclusive_test;
+static TCGv_i32 cpu_exclusive_info;
+#endif
+
 static const char *regnames[] = {
     "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
     "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
@@ -70,6 +79,19 @@ void a64_translate_init(void)
     cpu_ZF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, ZF), "ZF");
     cpu_CF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, CF), "CF");
     cpu_VF = tcg_global_mem_new_i32(TCG_AREG0, offsetof(CPUARMState, VF), "VF");
+
+    cpu_exclusive_addr = tcg_global_mem_new_i64(TCG_AREG0,
+        offsetof(CPUARMState, exclusive_addr), "exclusive_addr");
+    cpu_exclusive_val = tcg_global_mem_new_i64(TCG_AREG0,
+        offsetof(CPUARMState, exclusive_val), "exclusive_val");
+    cpu_exclusive_high = tcg_global_mem_new_i64(TCG_AREG0,
+        offsetof(CPUARMState, exclusive_high), "exclusive_high");
+#ifdef CONFIG_USER_ONLY
+    cpu_exclusive_test = tcg_global_mem_new_i64(TCG_AREG0,
+        offsetof(CPUARMState, exclusive_test), "exclusive_test");
+    cpu_exclusive_info = tcg_global_mem_new_i32(TCG_AREG0,
+        offsetof(CPUARMState, exclusive_info), "exclusive_info");
+#endif
 }
 
 void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
@@ -767,6 +789,11 @@ static void handle_hint(DisasContext *s, uint32_t insn,
     }
 }
 
+static void gen_clrex(DisasContext *s, uint32_t insn)
+{
+    tcg_gen_movi_i64(cpu_exclusive_addr, -1);
+}
+
 /* CLREX, DSB, DMB, ISB */
 static void handle_sync(DisasContext *s, uint32_t insn,
                         unsigned int op1, unsigned int op2, unsigned int crm)
@@ -778,7 +805,7 @@ static void handle_sync(DisasContext *s, uint32_t insn,
 
     switch (op2) {
     case 2: /* CLREX */
-        unsupported_encoding(s, insn);
+        gen_clrex(s, insn);
         return;
     case 4: /* DSB */
     case 5: /* DMB */
@@ -1106,10 +1133,133 @@ static void disas_b_exc_sys(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Load/store exclusive */
+/*
+ * Load/Store exclusive instructions are implemented by remembering
+ * the value/address loaded, and seeing if these are the same
+ * when the store is performed. This is not actually the architecturally
+ * mandated semantics, but it works for typical guest code sequences
+ * and avoids having to monitor regular stores.
+ *
+ * In system emulation mode only one CPU will be running at once, so
+ * this sequence is effectively atomic.  In user emulation mode we
+ * throw an exception and handle the atomic operation elsewhere.
+ */
+static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
+                               TCGv_i64 addr, int size, bool is_pair)
+{
+    TCGv_i64 tmp = tcg_temp_new_i64();
+    TCGMemOp memop = MO_TE + size;
+
+    g_assert(size <= 3);
+    tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), memop);
+
+    if (is_pair) {
+        TCGv_i64 addr2 = tcg_temp_new_i64();
+        TCGv_i64 hitmp = tcg_temp_new_i64();
+
+        g_assert(size >= 2);
+        tcg_gen_addi_i64(addr2, addr, 1 << size);
+        tcg_gen_qemu_ld_i64(hitmp, addr2, get_mem_index(s), memop);
+        tcg_temp_free_i64(addr2);
+        tcg_gen_mov_i64(cpu_exclusive_high, hitmp);
+        tcg_gen_mov_i64(cpu_reg(s, rt2), hitmp);
+        tcg_temp_free_i64(hitmp);
+    }
+
+    tcg_gen_mov_i64(cpu_exclusive_val, tmp);
+    tcg_gen_mov_i64(cpu_reg(s, rt), tmp);
+
+    tcg_temp_free_i64(tmp);
+    tcg_gen_mov_i64(cpu_exclusive_addr, addr);
+}
+
+#ifdef CONFIG_USER_ONLY
+static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
+                                TCGv_i64 addr, int size, int is_pair)
+{
+    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);
+}
+#else
+static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
+                                TCGv_i64 addr, int size, int is_pair)
+{
+    qemu_log_mask(LOG_UNIMP,
+                  "%s:%d: system mode store_exclusive unsupported "
+                  "at pc=%016" PRIx64 "\n",
+                  __FILE__, __LINE__, s->pc - 4);
+}
+#endif
+
+/* C3.3.6 Load/store exclusive
+ *
+ *  31 30 29         24  23  22   21  20  16  15  14   10 9    5 4    0
+ * +-----+-------------+----+---+----+------+----+-------+------+------+
+ * | sz  | 0 0 1 0 0 0 | o2 | L | o1 |  Rs  | o0 |  Rt2  |  Rn  | Rt   |
+ * +-----+-------------+----+---+----+------+----+-------+------+------+
+ *
+ *  sz: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64 bit
+ *   L: 0 -> store, 1 -> load
+ *  o2: 0 -> exclusive, 1 -> not
+ *  o1: 0 -> single register, 1 -> register pair
+ *  o0: 1 -> load-acquire/store-release, 0 -> not
+ *
+ *  o0 == 0 AND o2 == 1 is un-allocated
+ *  o1 == 1 is un-allocated except for 32 and 64 bit sizes
+ */
 static void disas_ldst_excl(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int rt2 = extract32(insn, 10, 5);
+    int is_lasr = extract32(insn, 15, 1);
+    int rs = extract32(insn, 16, 5);
+    int is_pair = extract32(insn, 21, 1);
+    int is_store = !extract32(insn, 22, 1);
+    int is_excl = !extract32(insn, 23, 1);
+    int size = extract32(insn, 30, 2);
+    TCGv_i64 tcg_addr;
+
+    if ((!is_excl && !is_lasr) ||
+        (is_pair && size < 2)) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    /* Note that since TCG is single threaded load-acquire/store-release
+     * semantics require no extra if (is_lasr) { ... } handling.
+     */
+
+    if (is_excl) {
+        if (!is_store) {
+            gen_load_exclusive(s, rt, rt2, tcg_addr, size, is_pair);
+        } else {
+            gen_store_exclusive(s, rs, rt, rt2, tcg_addr, size, is_pair);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false);
+        }
+        if (is_pair) {
+            TCGv_i64 tcg_rt2 = cpu_reg(s, rt);
+            tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
+            if (is_store) {
+                do_gpr_st(s, tcg_rt2, tcg_addr, size);
+            } else {
+                do_gpr_ld(s, tcg_rt2, tcg_addr, size, false, false);
+            }
+        }
+    }
 }
 
 /*
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (20 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-23 21:41   ` Richard Henderson
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext Peter Maydell
                   ` (2 subsequent siblings)
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Claudio Fontana <claudio.fontana@linaro.org>

The AArch64 linux-user support was written before but merged after
commit 4ce6243dc621 which cleaned up the handling of the clone()
syscall argument order, so we failed to notice that AArch64 also needs
TARGET_CLONE_BACKWARDS to be defined. Add this define so that clone
and fork syscalls work correctly.

Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/aarch64/syscall.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/linux-user/aarch64/syscall.h b/linux-user/aarch64/syscall.h
index aef419e..18f44a8 100644
--- a/linux-user/aarch64/syscall.h
+++ b/linux-user/aarch64/syscall.h
@@ -7,3 +7,4 @@ struct target_pt_regs {
 
 #define UNAME_MACHINE "aarch64"
 #define UNAME_MINIMUM_RELEASE "3.8.0"
+#define TARGET_CLONE_BACKWARDS
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (21 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-23 21:43   ` Richard Henderson
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 24/25] .travis.yml: Add aarch64-* targets Peter Maydell
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 25/25] default-configs: Add config for aarch64-linux-user Peter Maydell
  24 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Will Newton <will.newton@linaro.org>

Use the helpers provided for getting the correct FPSR and FPCR
values for the signal context.

Signed-off-by: Will Newton <will.newton@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 linux-user/signal.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 4e7148a..6c74b18 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1189,8 +1189,8 @@ static int target_setup_sigframe(struct target_rt_sigframe *sf,
         __put_user(env->vfp.regs[i * 2 + 1], &aux->fpsimd.vregs[i * 2 + 1]);
 #endif
     }
-    __put_user(/*env->fpsr*/0, &aux->fpsimd.fpsr);
-    __put_user(/*env->fpcr*/0, &aux->fpsimd.fpcr);
+    __put_user(vfp_get_fpsr(env), &aux->fpsimd.fpsr);
+    __put_user(vfp_get_fpcr(env), &aux->fpsimd.fpcr);
     __put_user(TARGET_FPSIMD_MAGIC, &aux->fpsimd.head.magic);
     __put_user(sizeof(struct target_fpsimd_context),
             &aux->fpsimd.head.size);
@@ -1209,7 +1209,7 @@ static int target_restore_sigframe(CPUARMState *env,
     int i;
     struct target_aux_context *aux =
         (struct target_aux_context *)sf->uc.tuc_mcontext.__reserved;
-    uint32_t magic, size;
+    uint32_t magic, size, fpsr, fpcr;
     uint64_t pstate;
 
     target_to_host_sigset(&set, &sf->uc.tuc_sigmask);
@@ -1235,6 +1235,10 @@ static int target_restore_sigframe(CPUARMState *env,
     for (i = 0; i < 32 * 2; i++) {
         __get_user(env->vfp.regs[i], &aux->fpsimd.vregs[i]);
     }
+    __get_user(fpsr, &aux->fpsimd.fpsr);
+    vfp_set_fpsr(env, fpsr);
+    __get_user(fpcr, &aux->fpsimd.fpcr);
+    vfp_set_fpcr(env, fpcr);
 
     return 0;
 }
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 24/25] .travis.yml: Add aarch64-* targets
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (22 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 25/25] default-configs: Add config for aarch64-linux-user Peter Maydell
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

Now the AArch64 targets are in mainline we can include them in our
Travis test matrix.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 .travis.yml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.travis.yml b/.travis.yml
index 90f1676..c7ff4da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,6 +16,7 @@ env:
   matrix:
   - TARGETS=alpha-softmmu,alpha-linux-user
   - TARGETS=arm-softmmu,arm-linux-user
+  - TARGETS=aarch64-softmmu,aarch64-linux-user
   - TARGETS=cris-softmmu
   - TARGETS=i386-softmmu,x86_64-softmmu
   - TARGETS=lm32-softmmu
-- 
1.8.5

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

* [Qemu-devel] [PATCH v2 25/25] default-configs: Add config for aarch64-linux-user
  2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
                   ` (23 preceding siblings ...)
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 24/25] .travis.yml: Add aarch64-* targets Peter Maydell
@ 2013-12-22 22:50 ` Peter Maydell
  24 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2013-12-22 22:50 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall, Richard Henderson

Add a config for aarch64-linux-user, thereby enabling it as
a valid target.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 default-configs/aarch64-linux-user.mak | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 default-configs/aarch64-linux-user.mak

diff --git a/default-configs/aarch64-linux-user.mak b/default-configs/aarch64-linux-user.mak
new file mode 100644
index 0000000..3df7de5
--- /dev/null
+++ b/default-configs/aarch64-linux-user.mak
@@ -0,0 +1,3 @@
+# Default configuration for aarch64-linux-user
+
+CONFIG_GDBSTUB_XML=y
-- 
1.8.5

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

* Re: [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair Peter Maydell
@ 2013-12-23 19:49   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 19:49 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:49 PM, Peter Maydell wrote:
> This patch support the basic load and store pair instructions and
> includes the generic helper functions:
> 
>   * do_gpr_st()
>   * do_fp_st()
>   * do_gpr_ld()
>   * do_fp_ld()
>   * read_cpu_reg_sp()
>   * gen_check_sp_alignment()
> 
> The last function gen_check_sp_alignment() is a NULL op currently but
> put in place to make it easy to add SP alignment checking later.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/translate-a64.c | 279 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 277 insertions(+), 2 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function Peter Maydell
@ 2013-12-23 19:51   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 19:51 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:49 PM, Peter Maydell wrote:
> define_one_arm_cp_reg_with_opaque() has a set of nested loops which
> insert a cpreg entry into the hashtable for each of the possible
> opc/crn/crm values allowed by wildcard specifications. We're about
> to add an extra loop to this nesting, so pull the core of the loop
> (which adds a single entry to the hashtable) out into its own
> function for clarity.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/helper.c | 94 +++++++++++++++++++++++++++++------------------------
>  1 file changed, 52 insertions(+), 42 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder Peter Maydell
@ 2013-12-23 20:11   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 20:11 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:49 PM, Peter Maydell wrote:
> The cpregs APIs used by the decoder (get_arm_cp_reginfo() and
> cp_access_ok()) currently take either a CPUARMState* or an ARMCPU*.
> This is problematic for the A64 decoder, which doesn't pass the
> environment pointer around everywhere the way the 32 bit decoder
> does. Adjust the parameters these functions take so that we can
> copy only the relevant info from the CPUARMState into the
> DisasContext and then use that.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu.h           |  6 +++---
>  target-arm/helper.c        | 12 ++++++------
>  target-arm/translate-a64.c |  2 ++
>  target-arm/translate.c     |  7 ++++---
>  target-arm/translate.h     |  2 ++
>  5 files changed, 17 insertions(+), 12 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits Peter Maydell
@ 2013-12-23 20:23   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 20:23 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:49 PM, Peter Maydell wrote:
> The common pattern for system registers in a 64-bit capable ARM
> CPU is that when in AArch32 the cp15 register is a view of the
> bottom 32 bits of the 64-bit AArch64 system register; writes in
> AArch32 leave the top half unchanged. The most natural way to
> model this is to have the state field in the CPU struct be a
> 64 bit value, and simply have the AArch32 TCG code operate on
> a pointer to its lower half.
> 
> For aarch64-linux-user the only registers we need to share like
> this are the thread-local-storage ones. Widen their fields to
> 64 bits and provide the 64 bit reginfo struct to make them
> visible in AArch64 state. Note that minor cleanup of the AArch64
> system register encoding space means We can share the TPIDR_EL1
> reginfo but need split encodings for TPIDR_EL0 and TPIDRRO_EL0.
> 
> Since we're touching almost every line in QEMU that uses the
> c13_tls* fields in this patch anyway, we take the opportunity
> to rename them in line with the standard ARM architectural names
> for these registers.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/aarch64/target_cpu.h |  5 ++++-
>  linux-user/arm/target_cpu.h     |  2 +-
>  linux-user/main.c               |  2 +-
>  target-arm/cpu.h                | 18 +++++++++++++++---
>  target-arm/helper.c             | 22 +++++++++++++++-------
>  5 files changed, 36 insertions(+), 13 deletions(-)


Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns Peter Maydell
@ 2013-12-23 20:37   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 20:37 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:50 PM, Peter Maydell wrote:
> From: Claudio Fontana <claudio.fontana@linaro.org>
> 
> this patch adds support for C3.5.4 - C3.5.5
> Conditional compare (both immediate and register)
> 
> Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/translate-a64.c | 73 +++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 60 insertions(+), 13 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits Peter Maydell
@ 2013-12-23 21:27   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 21:27 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:50 PM, Peter Maydell wrote:
> In preparation for adding support for A64 load/store exclusive instructions,
> widen the fields in the CPU state struct that deal with address and data values
> for exclusives from 32 to 64 bits. Although in practice AArch64 and AArch32
> exclusive accesses will be generally separate there are some odd theoretical
> corner cases (eg you should be able to do the exclusive load in AArch32, take
> an exception to AArch64 and successfully do the store exclusive there), and it's
> also easier to reason about.
> 
> The changes in semantics for the variables are:
>  exclusive_addr  -> extended to 64 bits; -1ULL for "monitor lost",
>    otherwise always < 2^32 for AArch32
>  exclusive_val   -> extended to 64 bits. 64 bit exclusives in AArch32 now
>    use the high half of exclusive_val instead of a separate exclusive_high
>  exclusive_high  -> is no longer used in AArch32; extended to 64 bits as
>    it will be needed for AArch64's pair-of-64-bit-values exclusives.
>  exclusive_test  -> extended to 64 bits, as it is an address. Since this is
>    a linux-user-only field, in arm-linux-user it will always have the top
>    32 bits zero.
>  exclusive_info  -> stays 32 bits, as it is neither data nor address, but
>    simply holds register indexes etc. AArch64 will be able to fit all its
>    information into 32 bits as well.
> 
> Note that the refactoring of gen_store_exclusive() coincidentally fixes
> a minor bug where ldrexd would incorrectly update the first CPU register
> even if the load for the second register faulted.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive Peter Maydell
@ 2013-12-23 21:34   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 21:34 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:50 PM, Peter Maydell wrote:
> From: Michael Matz <matz@suse.de>
> 
> This implement exclusive loads/stores for aarch64 along the lines of
> arm32 and ppc implementations. The exclusive load remembers the address
> and loaded value. The exclusive store throws an an exception which uses
> those values to check for equality in a proper exclusive region.
> 
> This is not actually the architecture mandated semantics (for either
> AArch32 or AArch64) but it is close enough for typical guest code
> sequences to work correctly, and saves us from having to monitor all
> guest stores. It's fairly easy to come up with test cases where we
> don't behave like hardware - we don't for example model cache line
> behaviour. However in the common patterns this works, and the existing
> 32 bit ARM exclusive access implementation has the same limitations.
> 
> AArch64 also implements new acquire/release loads/stores (which may be
> either exclusive or non-exclusive). These imposes extra ordering
> constraints on memory operations (ie they act as if they have an implicit
> barrier built into them). As TCG is single-threaded all our barriers
> are no-ops, so these just behave like normal loads and stores.
> 
> Signed-off-by: Michael Matz <matz@suse.de>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/main.c          | 127 +++++++++++++++++++++++++++++++++++-
>  target-arm/translate-a64.c | 156 ++++++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 277 insertions(+), 6 deletions(-)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS Peter Maydell
@ 2013-12-23 21:41   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 21:41 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:50 PM, Peter Maydell wrote:
> From: Claudio Fontana <claudio.fontana@linaro.org>
> 
> The AArch64 linux-user support was written before but merged after
> commit 4ce6243dc621 which cleaned up the handling of the clone()
> syscall argument order, so we failed to notice that AArch64 also needs
> TARGET_CLONE_BACKWARDS to be defined. Add this define so that clone
> and fork syscalls work correctly.
> 
> Signed-off-by: Claudio Fontana <claudio.fontana@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/aarch64/syscall.h | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext
  2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext Peter Maydell
@ 2013-12-23 21:43   ` Richard Henderson
  0 siblings, 0 replies; 44+ messages in thread
From: Richard Henderson @ 2013-12-23 21:43 UTC (permalink / raw)
  To: Peter Maydell, qemu-devel
  Cc: Peter Crosthwaite, patches, Michael Matz, Alexander Graf,
	Claudio Fontana, Dirk Mueller, Will Newton, Laurent Desnogues,
	Alex Bennée, kvmarm, Christoffer Dall

On 12/22/2013 02:50 PM, Peter Maydell wrote:
> From: Will Newton <will.newton@linaro.org>
> 
> Use the helpers provided for getting the correct FPSR and FPCR
> values for the signal context.
> 
> Signed-off-by: Will Newton <will.newton@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  linux-user/signal.c | 10 +++++++---
>  1 file changed, 7 insertions(+), 3 deletions(-)


Reviewed-by: Richard Henderson <rth@twiddle.net>


r~

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

* Re: [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64 Peter Maydell
@ 2014-01-02  1:51   ` Peter Crosthwaite
  2014-01-02 10:23     ` Peter Maydell
  2014-01-04 19:58     ` Peter Maydell
  0 siblings, 2 replies; 44+ messages in thread
From: Peter Crosthwaite @ 2014-01-02  1:51 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Update the generic cpreg support code to also handle AArch64:
> AArch64-visible registers coexist in the same hash table with
> AArch32-visible ones, with a bit in the hash key distinguishing
> them.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
>  target-arm/cpu.h        |  74 +++++++++++++++++++++++++++++++---
>  target-arm/helper.c     | 105 ++++++++++++++++++++++++++++++++++++++++++++++--
>  target-arm/kvm-consts.h |  37 +++++++++++++++++
>  3 files changed, 207 insertions(+), 9 deletions(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 56ed591..b082bca 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -572,18 +572,43 @@ void armv7m_nvic_complete_irq(void *opaque, int irq);
>   *    or via MRRC/MCRR?)
>   * We allow 4 bits for opc1 because MRRC/MCRR have a 4 bit field.
>   * (In this case crn and opc2 should be zero.)
> + * For AArch64, there is no 32/64 bit size distinction;
> + * instead all registers have a 2 bit op0, 3 bit op1 and op2,
> + * and 4 bit CRn and CRm. The encoding patterns are chosen
> + * to be easy to convert to and from the KVM encodings, and also
> + * so that the hashtable can contain both AArch32 and AArch64
> + * registers (to allow for interprocessing where we might run
> + * 32 bit code on a 64 bit core).
>   */
> +/* This bit is private to our hashtable cpreg; in KVM register
> + * IDs the AArch64/32 distinction is the KVM_REG_ARM/ARM64
> + * in the upper bits of the 64 bit ID.
> + */
> +#define CP_REG_AA64_SHIFT 28
> +#define CP_REG_AA64_MASK (1 << CP_REG_AA64_SHIFT)
> +
>  #define ENCODE_CP_REG(cp, is64, crn, crm, opc1, opc2)   \
>      (((cp) << 16) | ((is64) << 15) | ((crn) << 11) |    \
>       ((crm) << 7) | ((opc1) << 3) | (opc2))
>
> +#define ENCODE_AA64_CP_REG(cp, crn, crm, op0, op1, op2) \
> +    (CP_REG_AA64_MASK |                                 \
> +     ((cp) << CP_REG_ARM_COPROC_SHIFT) |                \
> +     ((op0) << CP_REG_ARM64_SYSREG_OP0_SHIFT) |         \
> +     ((op1) << CP_REG_ARM64_SYSREG_OP1_SHIFT) |         \
> +     ((crn) << CP_REG_ARM64_SYSREG_CRN_SHIFT) |         \
> +     ((crm) << CP_REG_ARM64_SYSREG_CRM_SHIFT) |         \
> +     ((op2) << CP_REG_ARM64_SYSREG_OP2_SHIFT))
> +
>  /* Convert a full 64 bit KVM register ID to the truncated 32 bit
>   * version used as a key for the coprocessor register hashtable
>   */
>  static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
>  {
>      uint32_t cpregid = kvmid;
> -    if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
> +    if ((kvmid & CP_REG_ARCH_MASK) == CP_REG_ARM64) {
> +        cpregid |= CP_REG_AA64_MASK;
> +    } else if ((kvmid & CP_REG_SIZE_MASK) == CP_REG_SIZE_U64) {
>          cpregid |= (1 << 15);
>      }
>      return cpregid;
> @@ -594,11 +619,18 @@ static inline uint32_t kvm_to_cpreg_id(uint64_t kvmid)
>   */
>  static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  {
> -    uint64_t kvmid = cpregid & ~(1 << 15);
> -    if (cpregid & (1 << 15)) {
> -        kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
> +    uint64_t kvmid;
> +
> +    if (cpregid & CP_REG_AA64_MASK) {
> +        kvmid = cpregid & ~CP_REG_AA64_MASK;
> +        kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM64;
>      } else {
> -        kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
> +        kvmid = cpregid & ~(1 << 15);
> +        if (cpregid & (1 << 15)) {
> +            kvmid |= CP_REG_SIZE_U64 | CP_REG_ARM;
> +        } else {
> +            kvmid |= CP_REG_SIZE_U32 | CP_REG_ARM;
> +        }
>      }
>      return kvmid;
>  }
> @@ -634,6 +666,17 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  /* Mask of only the flag bits in a type field */
>  #define ARM_CP_FLAG_MASK 0x7f
>
> +/* Valid values for ARMCPRegInfo state field, indicating which of
> + * the AArch32 and AArch64 execution states this register is visible in.
> + * If the reginfo doesn't explicitly specify then it is AArch32 only.
> + * If the reginfo is declared to be visible in both states then a second
> + * reginfo is synthesised for the AArch32 view of the AArch64 register,
> + * such that the AArch32 view is the lower 32 bits of the AArch64 one.
> + */
> +#define ARM_CP_STATE_AA32 0
> +#define ARM_CP_STATE_AA64 1
> +#define ARM_CP_STATE_BOTH 2

You iterator below depends on this specific encoding ordering, so
maybe this should be enumified.

> +
>  /* Return true if cptype is a valid type field. This is used to try to
>   * catch errors where the sentinel has been accidentally left off the end
>   * of a list of registers.
> @@ -655,6 +698,8 @@ static inline bool cptype_valid(int cptype)
>   * (ie anything visible in PL2 is visible in S-PL1, some things are only
>   * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the
>   * terminology a little and call this PL3.
> + * In AArch64 things are somewhat simpler as the PLx bits line up exactly
> + * with the ELx exception levels.
>   *
>   * If access permissions for a register are more complex than can be
>   * described with these bits, then use a laxer set of restrictions, and
> @@ -676,6 +721,10 @@ static inline bool cptype_valid(int cptype)
>
>  static inline int arm_current_pl(CPUARMState *env)
>  {
> +    if (env->aarch64) {
> +        return extract32(env->pstate, 2, 2);
> +    }
> +

This does seem a little out of scope of this patch and more valid as a
patch in its own right (Adding aarch64 support to arm_current_pl
globally).

>      if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR) {
>          return 0;
>      }
> @@ -713,12 +762,22 @@ struct ARMCPRegInfo {
>       * then behave differently on read/write if necessary.
>       * For 64 bit registers, only crm and opc1 are relevant; crn and opc2
>       * must both be zero.
> +     * For AArch64-visible registers, opc0 is also used.
> +     * Since there are no "coprocessors" in AArch64, cp is purely used as a
> +     * way to distinguish (for KVM's benefit) guest-visible system registers
> +     * from demuxed ones provided to preserve the "no side effects on
> +     * KVM register read/write from QEMU" semantics. cp==0x13 is guest
> +     * visible (to match KVM's encoding); cp==0 will be converted to
> +     * cp==0x13 when the ARMCPRegInfo is registered, for convenience.
>       */
>      uint8_t cp;
>      uint8_t crn;
>      uint8_t crm;
> +    uint8_t opc0;
>      uint8_t opc1;
>      uint8_t opc2;
> +    /* Execution state in which this register is visible: ARM_CP_STATE_* */
> +    int state;
>      /* Register type: ARM_CP_* bits/values */
>      int type;
>      /* Access rights: PL*_[RW] */
> @@ -798,6 +857,11 @@ int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
>  /* CPReadFn that can be used for read-as-zero behaviour */
>  int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value);
>
> +/* CPResetFn that does nothing, for use if no reset is required even
> + * if fieldoffset is non zero.
> + */
> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
> +
>  static inline bool cp_access_ok(CPUARMState *env,
>                                  const ARMCPRegInfo *ri, int isread)
>  {
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index d833163..3dac694 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1938,7 +1938,8 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>  }
>
>  static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
> -                                   void *opaque, int crm, int opc1, int opc2)
> +                                   void *opaque, int state,
> +                                   int crm, int opc1, int opc2)
>  {
>      /* Private utility function for define_one_arm_cp_reg_with_opaque():
>       * add a single reginfo struct to the hash table.
> @@ -1946,7 +1947,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>      uint32_t *key = g_new(uint32_t, 1);
>      ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
>      int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
> -    *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
> +    if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) {
> +        /* The AArch32 view of a shared register sees the lower 32 bits
> +         * of a 64 bit backing field. It is not migratable as the AArch64
> +         * view handles that. AArch64 also handles reset.
> +         * We assume it is a cp15 register.
> +         */
> +        r2->cp = 15;
> +        r2->type |= ARM_CP_NO_MIGRATE;
> +        r2->resetfn = arm_cp_reset_ignore;
> +#ifdef HOST_WORDS_BIGENDIAN
> +        if (r2->fieldoffset) {
> +            r2->fieldoffset += sizeof(uint32_t);
> +        }
> +#endif

So my thinking is that this logic should be iffed by whether the
register storage itself is 64-bit, not the valid access modes ...

> +    }
> +    if (state == ARM_CP_STATE_AA64) {
> +        /* To allow abbreviation of ARMCPRegInfo
> +         * definitions, we treat cp == 0 as equivalent to
> +         * the value for "standard guest-visible sysreg".
> +         */
> +        if (r->cp == 0) {
> +            r2->cp = CP_REG_ARM64_SYSREG_CP;
> +        }
> +        *key = ENCODE_AA64_CP_REG(r2->cp, r->crn, crm,
> +                                  r->opc0, opc1, opc2);
> +    } else {
> +        *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
> +    }
>      if (opaque) {
>          r2->opaque = opaque;
>      }
> @@ -2002,8 +2030,19 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>       * At least one of the original and the second definition should
>       * include ARM_CP_OVERRIDE in its type bits -- this is just a guard
>       * against accidental use.
> +     *
> +     * The state field defines whether the register is to be
> +     * visible in the AArch32 or AArch64 execution state. If the
> +     * state is set to ARM_CP_STATE_BOTH then we synthesise a
> +     * reginfo structure for the AArch32 view, which sees the lower
> +     * 32 bits of the 64 bit register.
> +     *
> +     * Only registers visible in AArch64 may set r->opc0; opc0 cannot
> +     * be wildcarded. AArch64 registers are always considered to be 64
> +     * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
> +     * the register, if any.

... as I still don't like that assumption that all 64 visible regs are
64bit storage given the ARM ARM does explictly defines many as "32
bit". My thinking is when future ARM ARMs actually extend stuff into
that RES0 upper 32 bits, they will have to redefine the regs are
64-bit which is then our trigger to convert uint32_t to uin64_t. But
that is out of scope of this patch, so with the enum fixup:

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

Regards,
Peter

>       */
> -    int crm, opc1, opc2;
> +    int crm, opc1, opc2, state;
>      int crmmin = (r->crm == CP_ANY) ? 0 : r->crm;
>      int crmmax = (r->crm == CP_ANY) ? 15 : r->crm;
>      int opc1min = (r->opc1 == CP_ANY) ? 0 : r->opc1;
> @@ -2012,6 +2051,52 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>      int opc2max = (r->opc2 == CP_ANY) ? 7 : r->opc2;
>      /* 64 bit registers have only CRm and Opc1 fields */
>      assert(!((r->type & ARM_CP_64BIT) && (r->opc2 || r->crn)));
> +    /* op0 only exists in the AArch64 encodings */
> +    assert((r->state != ARM_CP_STATE_AA32) || (r->opc0 == 0));
> +    /* AArch64 regs are all 64 bit so ARM_CP_64BIT is meaningless */
> +    assert((r->state != ARM_CP_STATE_AA64) || !(r->type & ARM_CP_64BIT));
> +    /* The AArch64 pseudocode CheckSystemAccess() specifies that op1
> +     * encodes a minimum access level for the register. We roll this
> +     * runtime check into our general permission check code, so check
> +     * here that the reginfo's specified permissions are strict enough
> +     * to encompass the generic architectural permission check.
> +     */
> +    if (r->state != ARM_CP_STATE_AA32) {
> +        int mask = 0;
> +        switch (r->opc1) {
> +        case 0: case 1: case 2:
> +            /* min_EL EL1 */
> +            mask = PL1_RW;
> +            break;
> +        case 3:
> +            /* min_EL EL0 */
> +            mask = PL0_RW;
> +            break;
> +        case 4:
> +            /* min_EL EL2 */
> +            mask = PL2_RW;
> +            break;
> +        case 5:
> +            /* unallocated encoding, so not possible */
> +            assert(false);
> +            break;
> +        case 6:
> +            /* min_EL EL3 */
> +            mask = PL3_RW;
> +            break;
> +        case 7:
> +            /* min_EL EL1, secure mode only (we don't check the latter) */
> +            mask = PL1_RW;
> +            break;
> +        default:
> +            /* broken reginfo with out-of-range opc1 */
> +            assert(false);
> +            break;
> +        }
> +        /* assert our permissions are not too lax (stricter is fine) */
> +        assert((r->access & ~mask) == 0);
> +    }
> +
>      /* Check that the register definition has enough info to handle
>       * reads and writes if they are permitted.
>       */
> @@ -2028,7 +2113,14 @@ void define_one_arm_cp_reg_with_opaque(ARMCPU *cpu,
>      for (crm = crmmin; crm <= crmmax; crm++) {
>          for (opc1 = opc1min; opc1 <= opc1max; opc1++) {
>              for (opc2 = opc2min; opc2 <= opc2max; opc2++) {
> -                add_cpreg_to_hashtable(cpu, r, opaque, crm, opc1, opc2);
> +                for (state = ARM_CP_STATE_AA32;
> +                     state <= ARM_CP_STATE_AA64; state++) {
> +                    if (r->state != state && r->state != ARM_CP_STATE_BOTH) {
> +                        continue;
> +                    }
> +                    add_cpreg_to_hashtable(cpu, r, opaque, state,
> +                                           crm, opc1, opc2);
> +                }
>              }
>          }
>      }
> @@ -2063,6 +2155,11 @@ int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value)
>      return 0;
>  }
>
> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque)
> +{
> +    /* Helper coprocessor reset function for do-nothing-on-reset registers */
> +}
> +
>  static int bad_mode_switch(CPUARMState *env, int mode)
>  {
>      /* Return true if it is not valid for us to switch to
> diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h
> index 2bba0bd..0e7f889 100644
> --- a/target-arm/kvm-consts.h
> +++ b/target-arm/kvm-consts.h
> @@ -29,12 +29,14 @@
>  #define CP_REG_SIZE_U32        0x0020000000000000ULL
>  #define CP_REG_SIZE_U64        0x0030000000000000ULL
>  #define CP_REG_ARM             0x4000000000000000ULL
> +#define CP_REG_ARCH_MASK       0xff00000000000000ULL
>
>  MISMATCH_CHECK(CP_REG_SIZE_SHIFT, KVM_REG_SIZE_SHIFT)
>  MISMATCH_CHECK(CP_REG_SIZE_MASK, KVM_REG_SIZE_MASK)
>  MISMATCH_CHECK(CP_REG_SIZE_U32, KVM_REG_SIZE_U32)
>  MISMATCH_CHECK(CP_REG_SIZE_U64, KVM_REG_SIZE_U64)
>  MISMATCH_CHECK(CP_REG_ARM, KVM_REG_ARM)
> +MISMATCH_CHECK(CP_REG_ARCH_MASK, KVM_REG_ARCH_MASK)
>
>  #define PSCI_FN_BASE 0x95c1ba5e
>  #define PSCI_FN(n) (PSCI_FN_BASE + (n))
> @@ -59,6 +61,41 @@ MISMATCH_CHECK(PSCI_FN_MIGRATE, KVM_PSCI_FN_MIGRATE)
>  MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15)
>  #endif
>
> +#define CP_REG_ARM64                   0x6000000000000000ULL
> +#define CP_REG_ARM_COPROC_MASK         0x000000000FFF0000
> +#define CP_REG_ARM_COPROC_SHIFT        16
> +#define CP_REG_ARM64_SYSREG            (0x0013 << CP_REG_ARM_COPROC_SHIFT)
> +#define CP_REG_ARM64_SYSREG_OP0_MASK   0x000000000000c000
> +#define CP_REG_ARM64_SYSREG_OP0_SHIFT  14
> +#define CP_REG_ARM64_SYSREG_OP1_MASK   0x0000000000003800
> +#define CP_REG_ARM64_SYSREG_OP1_SHIFT  11
> +#define CP_REG_ARM64_SYSREG_CRN_MASK   0x0000000000000780
> +#define CP_REG_ARM64_SYSREG_CRN_SHIFT  7
> +#define CP_REG_ARM64_SYSREG_CRM_MASK   0x0000000000000078
> +#define CP_REG_ARM64_SYSREG_CRM_SHIFT  3
> +#define CP_REG_ARM64_SYSREG_OP2_MASK   0x0000000000000007
> +#define CP_REG_ARM64_SYSREG_OP2_SHIFT  0
> +
> +/* No kernel define but it's useful to QEMU */
> +#define CP_REG_ARM64_SYSREG_CP (CP_REG_ARM64_SYSREG >> CP_REG_ARM_COPROC_SHIFT)
> +
> +#ifdef TARGET_AARCH64
> +MISMATCH_CHECK(CP_REG_ARM64, KVM_REG_ARM64)
> +MISMATCH_CHECK(CP_REG_ARM_COPROC_MASK, KVM_REG_ARM_COPROC_MASK)
> +MISMATCH_CHECK(CP_REG_ARM_COPROC_SHIFT, KVM_REG_ARM_COPROC_SHIFT)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG, KVM_REG_ARM64_SYSREG)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_MASK, KVM_REG_ARM64_SYSREG_OP0_MASK)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP0_SHIFT, KVM_REG_ARM64_SYSREG_OP0_SHIFT)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_MASK, KVM_REG_ARM64_SYSREG_OP1_MASK)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP1_SHIFT, KVM_REG_ARM64_SYSREG_OP1_SHIFT)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_MASK, KVM_REG_ARM64_SYSREG_CRN_MASK)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRN_SHIFT, KVM_REG_ARM64_SYSREG_CRN_SHIFT)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_MASK, KVM_REG_ARM64_SYSREG_CRM_MASK)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_CRM_SHIFT, KVM_REG_ARM64_SYSREG_CRM_SHIFT)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_MASK, KVM_REG_ARM64_SYSREG_OP2_MASK)
> +MISMATCH_CHECK(CP_REG_ARM64_SYSREG_OP2_SHIFT, KVM_REG_ARM64_SYSREG_OP2_SHIFT)
> +#endif
> +
>  #undef MISMATCH_CHECK
>
>  #endif
> --
> 1.8.5
>
>

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

* Re: [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64
  2014-01-02  1:51   ` Peter Crosthwaite
@ 2014-01-02 10:23     ` Peter Maydell
  2014-01-04 19:58     ` Peter Maydell
  1 sibling, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2014-01-02 10:23 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On 2 January 2014 01:51, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +/* Valid values for ARMCPRegInfo state field, indicating which of
>> + * the AArch32 and AArch64 execution states this register is visible in.
>> + * If the reginfo doesn't explicitly specify then it is AArch32 only.
>> + * If the reginfo is declared to be visible in both states then a second
>> + * reginfo is synthesised for the AArch32 view of the AArch64 register,
>> + * such that the AArch32 view is the lower 32 bits of the AArch64 one.
>> + */
>> +#define ARM_CP_STATE_AA32 0
>> +#define ARM_CP_STATE_AA64 1
>> +#define ARM_CP_STATE_BOTH 2
>
> You iterator below depends on this specific encoding ordering, so
> maybe this should be enumified.

Could do. I'm a bit old-school about using #defines rather than enum :-)

>> +
>>  /* Return true if cptype is a valid type field. This is used to try to
>>   * catch errors where the sentinel has been accidentally left off the end
>>   * of a list of registers.
>> @@ -655,6 +698,8 @@ static inline bool cptype_valid(int cptype)
>>   * (ie anything visible in PL2 is visible in S-PL1, some things are only
>>   * visible in S-PL1) but "Secure PL1" is a bit of a mouthful, we bend the
>>   * terminology a little and call this PL3.
>> + * In AArch64 things are somewhat simpler as the PLx bits line up exactly
>> + * with the ELx exception levels.
>>   *
>>   * If access permissions for a register are more complex than can be
>>   * described with these bits, then use a laxer set of restrictions, and
>> @@ -676,6 +721,10 @@ static inline bool cptype_valid(int cptype)
>>
>>  static inline int arm_current_pl(CPUARMState *env)
>>  {
>> +    if (env->aarch64) {
>> +        return extract32(env->pstate, 2, 2);
>> +    }
>> +
>
> This does seem a little out of scope of this patch and more valid as a
> patch in its own right (Adding aarch64 support to arm_current_pl
> globally).

arm_current_pl() is only used by the cpreg code, so making it work
with aarch64 seemed to me to fit with the rest of the "make cpreg code
work with aarch64" changes.

>>      if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR) {
>>          return 0;
>>      }
>> @@ -713,12 +762,22 @@ struct ARMCPRegInfo {
>>       * then behave differently on read/write if necessary.
>>       * For 64 bit registers, only crm and opc1 are relevant; crn and opc2
>>       * must both be zero.
>> +     * For AArch64-visible registers, opc0 is also used.
>> +     * Since there are no "coprocessors" in AArch64, cp is purely used as a
>> +     * way to distinguish (for KVM's benefit) guest-visible system registers
>> +     * from demuxed ones provided to preserve the "no side effects on
>> +     * KVM register read/write from QEMU" semantics. cp==0x13 is guest
>> +     * visible (to match KVM's encoding); cp==0 will be converted to
>> +     * cp==0x13 when the ARMCPRegInfo is registered, for convenience.
>>       */
>>      uint8_t cp;
>>      uint8_t crn;
>>      uint8_t crm;
>> +    uint8_t opc0;
>>      uint8_t opc1;
>>      uint8_t opc2;
>> +    /* Execution state in which this register is visible: ARM_CP_STATE_* */
>> +    int state;
>>      /* Register type: ARM_CP_* bits/values */
>>      int type;
>>      /* Access rights: PL*_[RW] */
>> @@ -798,6 +857,11 @@ int arm_cp_write_ignore(CPUARMState *env, const ARMCPRegInfo *ri,
>>  /* CPReadFn that can be used for read-as-zero behaviour */
>>  int arm_cp_read_zero(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t *value);
>>
>> +/* CPResetFn that does nothing, for use if no reset is required even
>> + * if fieldoffset is non zero.
>> + */
>> +void arm_cp_reset_ignore(CPUARMState *env, const ARMCPRegInfo *opaque);
>> +
>>  static inline bool cp_access_ok(CPUARMState *env,
>>                                  const ARMCPRegInfo *ri, int isread)
>>  {
>> diff --git a/target-arm/helper.c b/target-arm/helper.c
>> index d833163..3dac694 100644
>> --- a/target-arm/helper.c
>> +++ b/target-arm/helper.c
>> @@ -1938,7 +1938,8 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
>>  }
>>
>>  static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>> -                                   void *opaque, int crm, int opc1, int opc2)
>> +                                   void *opaque, int state,
>> +                                   int crm, int opc1, int opc2)
>>  {
>>      /* Private utility function for define_one_arm_cp_reg_with_opaque():
>>       * add a single reginfo struct to the hash table.
>> @@ -1946,7 +1947,34 @@ static void add_cpreg_to_hashtable(ARMCPU *cpu, const ARMCPRegInfo *r,
>>      uint32_t *key = g_new(uint32_t, 1);
>>      ARMCPRegInfo *r2 = g_memdup(r, sizeof(ARMCPRegInfo));
>>      int is64 = (r->type & ARM_CP_64BIT) ? 1 : 0;
>> -    *key = ENCODE_CP_REG(r->cp, is64, r->crn, crm, opc1, opc2);
>> +    if (r->state == ARM_CP_STATE_BOTH && state == ARM_CP_STATE_AA32) {
>> +        /* The AArch32 view of a shared register sees the lower 32 bits
>> +         * of a 64 bit backing field. It is not migratable as the AArch64
>> +         * view handles that. AArch64 also handles reset.
>> +         * We assume it is a cp15 register.
>> +         */
>> +        r2->cp = 15;
>> +        r2->type |= ARM_CP_NO_MIGRATE;
>> +        r2->resetfn = arm_cp_reset_ignore;
>> +#ifdef HOST_WORDS_BIGENDIAN
>> +        if (r2->fieldoffset) {
>> +            r2->fieldoffset += sizeof(uint32_t);
>> +        }
>> +#endif
>
> So my thinking is that this logic should be iffed by whether the
> register storage itself is 64-bit, not the valid access modes ...

>> +     * The state field defines whether the register is to be
>> +     * visible in the AArch32 or AArch64 execution state. If the
>> +     * state is set to ARM_CP_STATE_BOTH then we synthesise a
>> +     * reginfo structure for the AArch32 view, which sees the lower
>> +     * 32 bits of the 64 bit register.
>> +     *
>> +     * Only registers visible in AArch64 may set r->opc0; opc0 cannot
>> +     * be wildcarded. AArch64 registers are always considered to be 64
>> +     * bits; the ARM_CP_64BIT* flag applies only to the AArch32 view of
>> +     * the register, if any.
>
> ... as I still don't like that assumption that all 64 visible regs are
> 64bit storage given the ARM ARM does explictly defines many as "32
> bit". My thinking is when future ARM ARMs actually extend stuff into
> that RES0 upper 32 bits, they will have to redefine the regs are
> 64-bit which is then our trigger to convert uint32_t to uin64_t. But
> that is out of scope of this patch, so with the enum fixup:

No, I did check, and "32 bit" is just a shorthand for "64 bits with
RES0 upper half". In particular:
 * there is absolutely no form of 32-bit-only access instruction
 * KVM in the kernel is also defining all system registers as 64 bit

We could probably use a way to specify the RES0 bits in the
reginfo though, so we don't have to make the choice between
lots of writefns and not getting RES0 right. (At the moment for
most registers we just let the guest write 32 bits even if there
are RES0 bits.)

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

Thanks.
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs Peter Maydell
@ 2014-01-04  2:34   ` Peter Crosthwaite
  2014-01-04 11:35     ` Peter Maydell
  2014-01-04 13:32   ` Peter Crosthwaite
  1 sibling, 1 reply; 44+ messages in thread
From: Peter Crosthwaite @ 2014-01-04  2:34 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement an initial minimal set of EL0-visible system registers:
>  * NZCV
>  * FPCR
>  * FPSR
>  * CTR_EL0
>  * DCZID_EL0
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-arm/cpu.h           |  3 ++-
>  target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 66490ce..1e0800e 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  #define ARM_CP_IO 64
>  #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>  #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_LAST_SPECIAL ARM_CP_WFI
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> +#define ARM_LAST_SPECIAL ARM_CP_NZCV
>  /* 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/helper.c b/target-arm/helper.c
> index 66214293..ca27c8e 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
>      REGINFO_SENTINEL
>  };
>
> +static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpcr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpcr(env, value);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpsr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpsr(env, value);
> +    return 0;
> +}
> +
> +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.
> +     */
> +    { .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 = "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 },

Indentation and spacing looks inconsistent.

Regards,
Peter

> +    {. 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 },
> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
> +     * It will eventually need to have a CPU-specified reset value.
> +     */
> +    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x80030003 },
> +    /* 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 },
> +    REGINFO_SENTINEL
> +};
> +
>  static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>  {
>      env->cp15.c1_sys = value;
> @@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>      } else {
>          define_arm_cp_regs(cpu, not_v7_cp_reginfo);
>      }
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        define_arm_cp_regs(cpu, v8_cp_reginfo);
> +    }
>      if (arm_feature(env, ARM_FEATURE_MPU)) {
>          /* These are the MPU registers prior to PMSAv6. Any new
>           * PMSA core later than the ARM946 will require that we
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 7a9ee82..c8ed799 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>      unsupported_encoding(s, insn);
>  }
>
> +static void gen_get_nzcv(TCGv_i64 tcg_rt)
> +{
> +    TCGv_i32 tmp = tcg_temp_new_i32();
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* build bit 31, N */
> +    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
> +    /* build bit 30, Z */
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
> +    /* build bit 29, C */
> +    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
> +    /* build bit 28, V */
> +    tcg_gen_shri_i32(tmp, cpu_VF, 31);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
> +    /* generate result */
> +    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
> +
> +    tcg_temp_free_i32(nzcv);
> +    tcg_temp_free_i32(tmp);
> +}
> +
> +static void gen_set_nzcv(TCGv_i64 tcg_rt)
> +
> +{
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* take NZCV from R[t] */
> +    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
> +
> +    /* bit 31, N */
> +    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
> +    /* bit 30, Z */
> +    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
> +    /* bit 29, C */
> +    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
> +    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
> +    /* bit 28, V */
> +    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
> +    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
> +    tcg_temp_free_i32(nzcv);
> +}
> +
>  /* C5.6.129 MRS - move from system register
>   * C5.6.131 MSR (register) - move to system register
>   * C5.6.204 SYS
> @@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>      switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>      case ARM_CP_NOP:
>          return;
> +    case ARM_CP_NZCV:
> +        tcg_rt = cpu_reg(s, rt);
> +        if (isread) {
> +            gen_get_nzcv(tcg_rt);
> +        } else {
> +            gen_set_nzcv(tcg_rt);
> +        }
> +        return;
>      default:
>          break;
>      }
> --
> 1.8.5
>
>

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

* Re: [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2014-01-04  2:34   ` Peter Crosthwaite
@ 2014-01-04 11:35     ` Peter Maydell
  2014-01-04 13:39       ` Peter Crosthwaite
  0 siblings, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2014-01-04 11:35 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On 4 January 2014 02:34, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +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.
>> +     */
>> +    { .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 = "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 },
>
> Indentation and spacing looks inconsistent.

So it does (I didn't even know it was syntactically valid to leave
a space after the '.' like that...) . Will fix.

Do you mind if I don't do a respin just for this?

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs Peter Maydell
  2014-01-04  2:34   ` Peter Crosthwaite
@ 2014-01-04 13:32   ` Peter Crosthwaite
  2014-01-04 14:11     ` Peter Maydell
  1 sibling, 1 reply; 44+ messages in thread
From: Peter Crosthwaite @ 2014-01-04 13:32 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> Implement an initial minimal set of EL0-visible system registers:
>  * NZCV
>  * FPCR
>  * FPSR
>  * CTR_EL0
>  * DCZID_EL0
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Reviewed-by: Richard Henderson <rth@twiddle.net>
> ---
>  target-arm/cpu.h           |  3 ++-
>  target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index 66490ce..1e0800e 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -660,7 +660,8 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  #define ARM_CP_IO 64
>  #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
>  #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
> -#define ARM_LAST_SPECIAL ARM_CP_WFI
> +#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
> +#define ARM_LAST_SPECIAL ARM_CP_NZCV
>  /* 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/helper.c b/target-arm/helper.c
> index 66214293..ca27c8e 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -1560,6 +1560,64 @@ static const ARMCPRegInfo lpae_cp_reginfo[] = {
>      REGINFO_SENTINEL
>  };
>
> +static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpcr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpcr(env, value);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
> +                          uint64_t *value)
> +{
> +    *value = vfp_get_fpsr(env);
> +    return 0;
> +}
> +
> +static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
> +                           uint64_t value)
> +{
> +    vfp_set_fpsr(env, value);
> +    return 0;
> +}
> +
> +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.
> +     */
> +    { .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 = "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 },
> +    {. 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 },
> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
> +     * It will eventually need to have a CPU-specified reset value.
> +     */

Not sure why this can't be solved short term as there is already the
ctr field in cpu state struct as used by 32.

> +    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
> +      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
> +      .access = PL0_R, .type = ARM_CP_CONST,
> +      .resetvalue = 0x80030003 },
> +    /* 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 },
> +    REGINFO_SENTINEL
> +};
> +
>  static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
>  {
>      env->cp15.c1_sys = value;
> @@ -1662,6 +1720,9 @@ void register_cp_regs_for_features(ARMCPU *cpu)
>      } else {
>          define_arm_cp_regs(cpu, not_v7_cp_reginfo);
>      }
> +    if (arm_feature(env, ARM_FEATURE_V8)) {
> +        define_arm_cp_regs(cpu, v8_cp_reginfo);
> +    }

But I guess this exact approach wouldn't work. v8_cp_reginfo
declaration would have to be brought inline here (like it is for the
existing A32 MIDR/CTR/friends RegInfo decl.).

Regards,
Peter

>      if (arm_feature(env, ARM_FEATURE_MPU)) {
>          /* These are the MPU registers prior to PMSAv6. Any new
>           * PMSA core later than the ARM946 will require that we
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 7a9ee82..c8ed799 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c,
> @@ -733,6 +733,50 @@ static void handle_msr_i(DisasContext *s, uint32_t insn,
>      unsupported_encoding(s, insn);
>  }
>
> +static void gen_get_nzcv(TCGv_i64 tcg_rt)
> +{
> +    TCGv_i32 tmp = tcg_temp_new_i32();
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* build bit 31, N */
> +    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
> +    /* build bit 30, Z */
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
> +    /* build bit 29, C */
> +    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
> +    /* build bit 28, V */
> +    tcg_gen_shri_i32(tmp, cpu_VF, 31);
> +    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
> +    /* generate result */
> +    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
> +
> +    tcg_temp_free_i32(nzcv);
> +    tcg_temp_free_i32(tmp);
> +}
> +
> +static void gen_set_nzcv(TCGv_i64 tcg_rt)
> +
> +{
> +    TCGv_i32 nzcv = tcg_temp_new_i32();
> +
> +    /* take NZCV from R[t] */
> +    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
> +
> +    /* bit 31, N */
> +    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
> +    /* bit 30, Z */
> +    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
> +    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
> +    /* bit 29, C */
> +    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
> +    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
> +    /* bit 28, V */
> +    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
> +    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
> +    tcg_temp_free_i32(nzcv);
> +}
> +
>  /* C5.6.129 MRS - move from system register
>   * C5.6.131 MSR (register) - move to system register
>   * C5.6.204 SYS
> @@ -767,6 +811,14 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
>      switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
>      case ARM_CP_NOP:
>          return;
> +    case ARM_CP_NZCV:
> +        tcg_rt = cpu_reg(s, rt);
> +        if (isread) {
> +            gen_get_nzcv(tcg_rt);
> +        } else {
> +            gen_set_nzcv(tcg_rt);
> +        }
> +        return;
>      default:
>          break;
>      }
> --
> 1.8.5
>
>

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

* Re: [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2014-01-04 11:35     ` Peter Maydell
@ 2014-01-04 13:39       ` Peter Crosthwaite
  0 siblings, 0 replies; 44+ messages in thread
From: Peter Crosthwaite @ 2014-01-04 13:39 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Michael Matz, qemu-devel@nongnu.org Developers,
	Alexander Graf, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Sat, Jan 4, 2014 at 9:35 PM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 4 January 2014 02:34, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> +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.
>>> +     */
>>> +    { .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 = "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 },
>>
>> Indentation and spacing looks inconsistent.
>
> So it does (I didn't even know it was syntactically valid to leave
> a space after the '.' like that...) . Will fix.
>

FWIW, I think in ".foo" the "." and "foo" will still be lexed as two
tokens by compilers so the standard rule of "whitespace doesn't
matter" applies and the parser has to sort it out.

Checkpatch could probably use a rule though.

> Do you mind if I don't do a respin just for this?
>

Not just for this, although I had a second read through and have a
comment on the CTR (separate mail). But i'd rather see it go through
considering the issue is flagged fixme, so just pending the
whitespace:

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

(I haven't gone line by line on the TCG stuff, but Richard has RB'd it
so I'm assuming thats covered).

Regards,
Peter

> thanks
> -- PMM
>

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

* Re: [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs
  2014-01-04 13:32   ` Peter Crosthwaite
@ 2014-01-04 14:11     ` Peter Maydell
  0 siblings, 0 replies; 44+ messages in thread
From: Peter Maydell @ 2014-01-04 14:11 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On 4 January 2014 13:32, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +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.
>> +     */
>> +    { .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 = "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 },
>> +    {. 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 },
>> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
>> +     * It will eventually need to have a CPU-specified reset value.
>> +     */
>
> Not sure why this can't be solved short term as there is already the
> ctr field in cpu state struct as used by 32.

I hadn't noticed that the register was aliased to the CTR AArch32 register.
NB that we can't just share a single reginfo for AArch64 and AArch32
though -- the permissions are different since in AArch32 this is accessible
only in EL1 and above.

My aim here was mostly to set out a framework for how the system
register integration will work with system emulation, but just to
provide low-effort implementations of the EL0-visible regs for
the initial user-emulation patchset. (In the SuSE patchset these are
actually just all implemented as special cases inline in translate-a64.c,
so to some extent this array is just those special cases converted over
to reginfo.)

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64
  2014-01-02  1:51   ` Peter Crosthwaite
  2014-01-02 10:23     ` Peter Maydell
@ 2014-01-04 19:58     ` Peter Maydell
  2014-01-05  2:44       ` Peter Crosthwaite
  1 sibling, 1 reply; 44+ messages in thread
From: Peter Maydell @ 2014-01-04 19:58 UTC (permalink / raw)
  To: Peter Crosthwaite
  Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Alexander Graf,
	qemu-devel@nongnu.org Developers, Claudio Fontana, Dirk Mueller,
	Will Newton, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On 2 January 2014 01:51, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +#define ARM_CP_STATE_AA32 0
>> +#define ARM_CP_STATE_AA64 1
>> +#define ARM_CP_STATE_BOTH 2
>
> You iterator below depends on this specific encoding ordering, so
> maybe this should be enumified.

Delta from this to my fixed version:

===begin===
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index b082bca..9430464 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -672,10 +672,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
  * If the reginfo is declared to be visible in both states then a second
  * reginfo is synthesised for the AArch32 view of the AArch64 register,
  * such that the AArch32 view is the lower 32 bits of the AArch64 one.
+ * Note that we rely on the values of these enums as we iterate through
+ * the various states in some places.
  */
-#define ARM_CP_STATE_AA32 0
-#define ARM_CP_STATE_AA64 1
-#define ARM_CP_STATE_BOTH 2
+enum {
+    ARM_CP_STATE_AA32 = 0,
+    ARM_CP_STATE_AA64 = 1,
+    ARM_CP_STATE_BOTH = 2,
+};

 /* Return true if cptype is a valid type field. This is used to try to
  * catch errors where the sentinel has been accidentally left off the end
===endit===

Personally I think the change to enum is less useful than the
comment saying "the values matter", but I don't particularly
object to enums.

thanks
-- PMM

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

* Re: [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64
  2014-01-04 19:58     ` Peter Maydell
@ 2014-01-05  2:44       ` Peter Crosthwaite
  0 siblings, 0 replies; 44+ messages in thread
From: Peter Crosthwaite @ 2014-01-05  2:44 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Michael Matz, qemu-devel@nongnu.org Developers,
	Alexander Graf, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

On Sun, Jan 5, 2014 at 5:58 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 2 January 2014 01:51, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
>> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>>> +#define ARM_CP_STATE_AA32 0
>>> +#define ARM_CP_STATE_AA64 1
>>> +#define ARM_CP_STATE_BOTH 2
>>
>> You iterator below depends on this specific encoding ordering, so
>> maybe this should be enumified.
>
> Delta from this to my fixed version:
>
> ===begin===
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index b082bca..9430464 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -672,10 +672,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>   * If the reginfo is declared to be visible in both states then a second
>   * reginfo is synthesised for the AArch32 view of the AArch64 register,
>   * such that the AArch32 view is the lower 32 bits of the AArch64 one.
> + * Note that we rely on the values of these enums as we iterate through
> + * the various states in some places.
>   */
> -#define ARM_CP_STATE_AA32 0
> -#define ARM_CP_STATE_AA64 1
> -#define ARM_CP_STATE_BOTH 2
> +enum {
> +    ARM_CP_STATE_AA32 = 0,
> +    ARM_CP_STATE_AA64 = 1,
> +    ARM_CP_STATE_BOTH = 2,
> +};
>

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

>  /* Return true if cptype is a valid type field. This is used to try to
>   * catch errors where the sentinel has been accidentally left off the end
> ===endit===
>
> Personally I think the change to enum is less useful than the
> comment saying "the values matter", but I don't particularly
> object to enums.
>
> thanks
> -- PMM
>

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

end of thread, other threads:[~2014-01-05  2:44 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-22 22:49 [Qemu-devel] [PATCH v2 00/25] target-arm: A64 decoder sets 3 and 4: everything but fp & simd Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 01/25] target-arm: A64: add support for ld/st pair Peter Maydell
2013-12-23 19:49   ` Richard Henderson
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 02/25] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 03/25] target-arm: A64: add support for ld/st with reg offset Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 04/25] target-arm: A64: add support for ld/st with index Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 05/25] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 06/25] target-arm: A64: add support for move wide instructions Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 07/25] target-arm: A64: add support for 3 src data proc insns Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 08/25] target-arm: A64: implement SVC, BRK Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 09/25] target-arm: A64: Add decoder skeleton for FP instructions Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 10/25] target-arm: A64: implement FMOV Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 11/25] target-arm: Pull "add one cpreg to hashtable" into its own function Peter Maydell
2013-12-23 19:51   ` Richard Henderson
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 12/25] target-arm: Update generic cpreg code for AArch64 Peter Maydell
2014-01-02  1:51   ` Peter Crosthwaite
2014-01-02 10:23     ` Peter Maydell
2014-01-04 19:58     ` Peter Maydell
2014-01-05  2:44       ` Peter Crosthwaite
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 13/25] target-arm: Remove ARMCPU/CPUARMState from cpregs APIs used by decoder Peter Maydell
2013-12-23 20:11   ` Richard Henderson
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 14/25] target-arm: A64: Implement MRS/MSR/SYS/SYSL Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs Peter Maydell
2014-01-04  2:34   ` Peter Crosthwaite
2014-01-04 11:35     ` Peter Maydell
2014-01-04 13:39       ` Peter Crosthwaite
2014-01-04 13:32   ` Peter Crosthwaite
2014-01-04 14:11     ` Peter Maydell
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 16/25] target-arm: Widen thread-local register state fields to 64 bits Peter Maydell
2013-12-23 20:23   ` Richard Henderson
2013-12-22 22:49 ` [Qemu-devel] [PATCH v2 17/25] target-arm: A64: add support for add/sub with carry Peter Maydell
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 18/25] target-arm: A64: add support for conditional compare insns Peter Maydell
2013-12-23 20:37   ` Richard Henderson
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 19/25] target-arm: aarch64: add support for ld lit Peter Maydell
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 20/25] target-arm: Widen exclusive-access support struct fields to 64 bits Peter Maydell
2013-12-23 21:27   ` Richard Henderson
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 21/25] target-arm: A64: support for ld/st/cl exclusive Peter Maydell
2013-12-23 21:34   ` Richard Henderson
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 22/25] linux-user: AArch64: define TARGET_CLONE_BACKWARDS Peter Maydell
2013-12-23 21:41   ` Richard Henderson
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 23/25] linux-user: AArch64: Use correct values for FPSR/FPCR in sigcontext Peter Maydell
2013-12-23 21:43   ` Richard Henderson
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 24/25] .travis.yml: Add aarch64-* targets Peter Maydell
2013-12-22 22:50 ` [Qemu-devel] [PATCH v2 25/25] default-configs: Add config for aarch64-linux-user 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.