All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers
@ 2013-08-09 16:17 Peter Maydell
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs Peter Maydell
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Peter Maydell @ 2013-08-09 16:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, patches

This patch series implements support for the 'generic timers',
which are a set of timers defined in the ARM Architecture Reference
Manual and implemented by the Cortex-A15. We've got away without
these up til now because Linux will generally fall back on whatever
random timer is present on the devboard if it can't find the
on-CPU timers, but this is less than ideal. (Among other things,
the proposed mach-virt should just use the generic timers so it
doesn't have to provide an sp804 timer.)

Changes v1->v2:
 * fixed nits spotted by Andreas: missing blank line, missing
   arm_ prefix for globally visible functions

Peter Maydell (4):
  target-arm: Allow raw_read() and raw_write() to handle 64 bit regs
  target-arm: Support coprocessor registers which do I/O
  target-arm: Implement the generic timer
  hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs

 hw/cpu/a15mpcore.c     |   18 ++++
 target-arm/cpu-qom.h   |    9 ++
 target-arm/cpu.c       |    9 ++
 target-arm/cpu.h       |   24 ++++-
 target-arm/helper.c    |  268 ++++++++++++++++++++++++++++++++++++++++++++++--
 target-arm/machine.c   |    8 +-
 target-arm/translate.c |   16 ++-
 7 files changed, 338 insertions(+), 14 deletions(-)

-- 
1.7.9.5

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

* [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs
  2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
@ 2013-08-09 16:17 ` Peter Maydell
  2013-08-14  5:42   ` Edgar E. Iglesias
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O Peter Maydell
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2013-08-09 16:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, patches

Extend the raw_read() and raw_write() helper accessors so that
they can be used for 64 bit registers as well as 32 bit registers.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
---
 target-arm/helper.c |   12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4968391..fc5f757 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -67,14 +67,22 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
 static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri,
                     uint64_t *value)
 {
-    *value = CPREG_FIELD32(env, ri);
+    if (ri->type & ARM_CP_64BIT) {
+        *value = CPREG_FIELD64(env, ri);
+    } else {
+        *value = CPREG_FIELD32(env, ri);
+    }
     return 0;
 }
 
 static int raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
                      uint64_t value)
 {
-    CPREG_FIELD32(env, ri) = value;
+    if (ri->type & ARM_CP_64BIT) {
+        CPREG_FIELD64(env, ri) = value;
+    } else {
+        CPREG_FIELD32(env, ri) = value;
+    }
     return 0;
 }
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O
  2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs Peter Maydell
@ 2013-08-09 16:17 ` Peter Maydell
  2013-08-14  5:20   ` Edgar E. Iglesias
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 3/4] target-arm: Implement the generic timer Peter Maydell
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Peter Maydell @ 2013-08-09 16:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, patches

Add an ARM_CP_IO flag which an ARMCPRegInfo definition can use to
indicate that the register's implementation does I/O and thus
its accesses need to be surrounded by gen_io_start()/gen_io_end()
in order for icount to work. Most notably, cp registers which
implement clocks or timers need this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
---
 target-arm/cpu.h       |    6 +++++-
 target-arm/translate.c |   16 +++++++++++++---
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index b2dc494..770a240 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -469,6 +469,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
  * old must have the OVERRIDE bit set.
  * NO_MIGRATE indicates that this register should be ignored for migration;
  * (eg because any state is accessed via some other coprocessor register).
+ * IO indicates that this register does I/O and therefore its accesses
+ * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
+ * registers which implement clocks or timers require this.
  */
 #define ARM_CP_SPECIAL 1
 #define ARM_CP_CONST 2
@@ -476,13 +479,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_SUPPRESS_TB_END 8
 #define ARM_CP_OVERRIDE 16
 #define ARM_CP_NO_MIGRATE 32
+#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
 /* Used only as a terminator for ARMCPRegInfo lists */
 #define ARM_CP_SENTINEL 0xffff
 /* Mask of only the flag bits in a type field */
-#define ARM_CP_FLAG_MASK 0x3f
+#define ARM_CP_FLAG_MASK 0x7f
 
 /* 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
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6db4c50..d1e8538 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -6280,6 +6280,10 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
             break;
         }
 
+        if (use_icount && (ri->type & ARM_CP_IO)) {
+            gen_io_start();
+        }
+
         if (isread) {
             /* Read */
             if (is64) {
@@ -6369,14 +6373,20 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
                     store_cpu_offset(tmp, 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();
+            gen_lookup_tb(s);
+        } 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).
              */
-            if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) {
-                gen_lookup_tb(s);
-            }
+            gen_lookup_tb(s);
         }
+
         return 0;
     }
 
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH v2 3/4] target-arm: Implement the generic timer
  2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs Peter Maydell
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O Peter Maydell
@ 2013-08-09 16:17 ` Peter Maydell
  2013-08-09 16:18 ` [Qemu-devel] [PATCH v2 4/4] hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs Peter Maydell
  2013-08-20 13:10 ` [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
  4 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2013-08-09 16:17 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, patches

The ARMv7 architecture specifies a 'generic timer' which is implemented
via cp15 registers. Newer kernels will prefer to use this rather than
a devboard-level timer. Implement the generic timer for TCG; for KVM
we will already use the hardware's virtualized timer for this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
---
 target-arm/cpu-qom.h |    9 ++
 target-arm/cpu.c     |    9 ++
 target-arm/cpu.h     |   18 ++++
 target-arm/helper.c  |  256 +++++++++++++++++++++++++++++++++++++++++++++++++-
 target-arm/machine.c |    8 +-
 5 files changed, 292 insertions(+), 8 deletions(-)

diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h
index cf36587..9f47bae 100644
--- a/target-arm/cpu-qom.h
+++ b/target-arm/cpu-qom.h
@@ -86,6 +86,11 @@ typedef struct ARMCPU {
     uint64_t *cpreg_vmstate_values;
     int32_t cpreg_vmstate_array_len;
 
+    /* Timers used by the generic (architected) timer */
+    QEMUTimer *gt_timer[NUM_GTIMERS];
+    /* GPIO outputs for generic timer */
+    qemu_irq gt_timer_outputs[NUM_GTIMERS];
+
     /* The instance init functions for implementation-specific subclasses
      * set these fields to specify the implementation-dependent values of
      * various constant registers and reset values of non-constant
@@ -152,4 +157,8 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
 int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
 int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
 
+/* Callback functions for the generic timer's timers. */
+void arm_gt_ptimer_cb(void *opaque);
+void arm_gt_vtimer_cb(void *opaque);
+
 #endif
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 5a7566b..0791999 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -145,6 +145,15 @@ static void arm_cpu_initfn(Object *obj)
     cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal,
                                          g_free, g_free);
 
+#ifndef CONFIG_USER_ONLY
+    cpu->gt_timer[GTIMER_PHYS] = qemu_new_timer(vm_clock, GTIMER_SCALE,
+                                                arm_gt_ptimer_cb, cpu);
+    cpu->gt_timer[GTIMER_VIRT] = qemu_new_timer(vm_clock, GTIMER_SCALE,
+                                                arm_gt_vtimer_cb, cpu);
+    qdev_init_gpio_out(DEVICE(cpu), cpu->gt_timer_outputs,
+                       ARRAY_SIZE(cpu->gt_timer_outputs));
+#endif
+
     if (tcg_enabled() && !inited) {
         inited = true;
         arm_translate_init();
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 770a240..27715b5 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -76,6 +76,21 @@ struct arm_boot_info;
    s<2n+1> maps to the most significant half of d<n>
  */
 
+/* CPU state for each instance of a generic timer (in cp15 c14) */
+typedef struct ARMGenericTimer {
+    uint64_t cval; /* Timer CompareValue register */
+    uint32_t ctl; /* Timer Control register */
+} ARMGenericTimer;
+
+#define GTIMER_PHYS 0
+#define GTIMER_VIRT 1
+#define NUM_GTIMERS 2
+
+/* Scale factor for generic timers, ie number of ns per tick.
+ * This gives a 62.5MHz timer.
+ */
+#define GTIMER_SCALE 16
+
 typedef struct CPUARMState {
     /* Regs for current mode.  */
     uint32_t regs[16];
@@ -143,6 +158,9 @@ typedef struct CPUARMState {
         uint32_t c13_tls1; /* User RW Thread register.  */
         uint32_t c13_tls2; /* User RO Thread register.  */
         uint32_t c13_tls3; /* Privileged Thread register.  */
+        uint32_t c14_cntfrq; /* Counter Frequency register */
+        uint32_t c14_cntkctl; /* Timer Control register */
+        ARMGenericTimer c14_timer[NUM_GTIMERS];
         uint32_t c15_cpar; /* XScale Coprocessor Access Register */
         uint32_t c15_ticonfig; /* TI925T configuration byte.  */
         uint32_t c15_i_max; /* Maximum D-cache dirty line index.  */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index fc5f757..3c57558 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -695,15 +695,261 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+#ifndef CONFIG_USER_ONLY
+
+static uint64_t gt_get_countervalue(CPUARMState *env)
+{
+    return qemu_get_clock_ns(vm_clock) / GTIMER_SCALE;
+}
+
+static void gt_recalc_timer(ARMCPU *cpu, int timeridx)
+{
+    ARMGenericTimer *gt = &cpu->env.cp15.c14_timer[timeridx];
+
+    if (gt->ctl & 1) {
+        /* Timer enabled: calculate and set current ISTATUS, irq, and
+         * reset timer to when ISTATUS next has to change
+         */
+        uint64_t count = gt_get_countervalue(&cpu->env);
+        /* Note that this must be unsigned 64 bit arithmetic: */
+        int istatus = count >= gt->cval;
+        uint64_t nexttick;
+
+        gt->ctl = deposit32(gt->ctl, 2, 1, istatus);
+        qemu_set_irq(cpu->gt_timer_outputs[timeridx],
+                     (istatus && !(gt->ctl & 2)));
+        if (istatus) {
+            /* Next transition is when count rolls back over to zero */
+            nexttick = UINT64_MAX;
+        } else {
+            /* Next transition is when we hit cval */
+            nexttick = gt->cval;
+        }
+        /* Note that the desired next expiry time might be beyond the
+         * signed-64-bit range of a QEMUTimer -- in this case we just
+         * set the timer for as far in the future as possible. When the
+         * timer expires we will reset the timer for any remaining period.
+         */
+        if (nexttick > INT64_MAX / GTIMER_SCALE) {
+            nexttick = INT64_MAX / GTIMER_SCALE;
+        }
+        qemu_mod_timer(cpu->gt_timer[timeridx], nexttick);
+    } else {
+        /* Timer disabled: ISTATUS and timer output always clear */
+        gt->ctl &= ~4;
+        qemu_set_irq(cpu->gt_timer_outputs[timeridx], 0);
+        qemu_del_timer(cpu->gt_timer[timeridx]);
+    }
+}
+
+static int gt_cntfrq_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    /* Not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */
+    if (arm_current_pl(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) {
+        return EXCP_UDEF;
+    }
+    *value = env->cp15.c14_cntfrq;
+    return 0;
+}
+
+static void gt_cnt_reset(CPUARMState *env, const ARMCPRegInfo *ri)
+{
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    int timeridx = ri->opc1 & 1;
+
+    qemu_del_timer(cpu->gt_timer[timeridx]);
+}
+
+static int gt_cnt_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                       uint64_t *value)
+{
+    int timeridx = ri->opc1 & 1;
+
+    if (arm_current_pl(env) == 0 &&
+        !extract32(env->cp15.c14_cntkctl, timeridx, 1)) {
+        return EXCP_UDEF;
+    }
+    *value = gt_get_countervalue(env);
+    return 0;
+}
+
+static int gt_cval_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t *value)
+{
+    int timeridx = ri->opc1 & 1;
+
+    if (arm_current_pl(env) == 0 &&
+        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
+        return EXCP_UDEF;
+    }
+    *value = env->cp15.c14_timer[timeridx].cval;
+    return 0;
+}
+
+static int gt_cval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                         uint64_t value)
+{
+    int timeridx = ri->opc1 & 1;
+
+    env->cp15.c14_timer[timeridx].cval = value;
+    gt_recalc_timer(arm_env_get_cpu(env), timeridx);
+    return 0;
+}
+static int gt_tval_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t *value)
+{
+    int timeridx = ri->crm & 1;
+
+    if (arm_current_pl(env) == 0 &&
+        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
+        return EXCP_UDEF;
+    }
+    *value = (uint32_t)(env->cp15.c14_timer[timeridx].cval -
+                        gt_get_countervalue(env));
+    return 0;
+}
+
+static int gt_tval_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                         uint64_t value)
+{
+    int timeridx = ri->crm & 1;
+
+    env->cp15.c14_timer[timeridx].cval = gt_get_countervalue(env) +
+        + sextract64(value, 0, 32);
+    gt_recalc_timer(arm_env_get_cpu(env), timeridx);
+    return 0;
+}
+
+static int gt_ctl_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                       uint64_t *value)
+{
+    int timeridx = ri->crm & 1;
+
+    if (arm_current_pl(env) == 0 &&
+        !extract32(env->cp15.c14_cntkctl, 9 - timeridx, 1)) {
+        return EXCP_UDEF;
+    }
+    *value = env->cp15.c14_timer[timeridx].ctl;
+    return 0;
+}
+
+static int gt_ctl_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                        uint64_t value)
+{
+    ARMCPU *cpu = arm_env_get_cpu(env);
+    int timeridx = ri->crm & 1;
+    uint32_t oldval = env->cp15.c14_timer[timeridx].ctl;
+
+    env->cp15.c14_timer[timeridx].ctl = value & 3;
+    if ((oldval ^ value) & 1) {
+        /* Enable toggled */
+        gt_recalc_timer(cpu, timeridx);
+    } else if ((oldval & value) & 2) {
+        /* IMASK toggled: don't need to recalculate,
+         * just set the interrupt line based on ISTATUS
+         */
+        qemu_set_irq(cpu->gt_timer_outputs[timeridx],
+                     (oldval & 4) && (value & 2));
+    }
+    return 0;
+}
+
+void arm_gt_ptimer_cb(void *opaque)
+{
+    ARMCPU *cpu = opaque;
+
+    gt_recalc_timer(cpu, GTIMER_PHYS);
+}
+
+void arm_gt_vtimer_cb(void *opaque)
+{
+    ARMCPU *cpu = opaque;
+
+    gt_recalc_timer(cpu, GTIMER_VIRT);
+}
+
 static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
-    /* Dummy implementation: RAZ/WI the whole crn=14 space */
-    { .name = "GENERIC_TIMER", .cp = 15, .crn = 14,
-      .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY,
-      .access = PL1_RW, .type = ARM_CP_CONST | ARM_CP_NO_MIGRATE,
-      .resetvalue = 0 },
+    /* Note that CNTFRQ is purely reads-as-written for the benefit
+     * of software; writing it doesn't actually change the timer frequency.
+     * Our reset value matches the fixed frequency we implement the timer at.
+     */
+    { .name = "CNTFRQ", .cp = 15, .crn = 14, .crm = 0, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW | PL0_R,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_cntfrq),
+      .resetvalue = (1000 * 1000 * 1000) / GTIMER_SCALE,
+      .readfn = gt_cntfrq_read, .raw_readfn = raw_read,
+    },
+    /* overall control: mostly access permissions */
+    { .name = "CNTKCTL", .cp = 15, .crn = 14, .crm = 1, .opc1 = 0, .opc2 = 0,
+      .access = PL1_RW,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_cntkctl),
+      .resetvalue = 0,
+    },
+    /* per-timer control */
+    { .name = "CNTP_CTL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 1,
+      .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].ctl),
+      .resetvalue = 0,
+      .readfn = gt_ctl_read, .writefn = gt_ctl_write,
+      .raw_readfn = raw_read, .raw_writefn = raw_write,
+    },
+    { .name = "CNTV_CTL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 1,
+      .type = ARM_CP_IO, .access = PL1_RW | PL0_R,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].ctl),
+      .resetvalue = 0,
+      .readfn = gt_ctl_read, .writefn = gt_ctl_write,
+      .raw_readfn = raw_read, .raw_writefn = raw_write,
+    },
+    /* TimerValue views: a 32 bit downcounting view of the underlying state */
+    { .name = "CNTP_TVAL", .cp = 15, .crn = 14, .crm = 2, .opc1 = 0, .opc2 = 0,
+      .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
+      .readfn = gt_tval_read, .writefn = gt_tval_write,
+    },
+    { .name = "CNTV_TVAL", .cp = 15, .crn = 14, .crm = 3, .opc1 = 0, .opc2 = 0,
+      .type = ARM_CP_NO_MIGRATE | ARM_CP_IO, .access = PL1_RW | PL0_R,
+      .readfn = gt_tval_read, .writefn = gt_tval_write,
+    },
+    /* The counter itself */
+    { .name = "CNTPCT", .cp = 15, .crm = 14, .opc1 = 0,
+      .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
+      .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
+    },
+    { .name = "CNTVCT", .cp = 15, .crm = 14, .opc1 = 1,
+      .access = PL0_R, .type = ARM_CP_64BIT | ARM_CP_NO_MIGRATE | ARM_CP_IO,
+      .readfn = gt_cnt_read, .resetfn = gt_cnt_reset,
+    },
+    /* Comparison value, indicating when the timer goes off */
+    { .name = "CNTP_CVAL", .cp = 15, .crm = 14, .opc1 = 2,
+      .access = PL1_RW | PL0_R,
+      .type = ARM_CP_64BIT | ARM_CP_IO,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_PHYS].cval),
+      .resetvalue = 0,
+      .readfn = gt_cval_read, .writefn = gt_cval_write,
+      .raw_readfn = raw_read, .raw_writefn = raw_write,
+    },
+    { .name = "CNTV_CVAL", .cp = 15, .crm = 14, .opc1 = 3,
+      .access = PL1_RW | PL0_R,
+      .type = ARM_CP_64BIT | ARM_CP_IO,
+      .fieldoffset = offsetof(CPUARMState, cp15.c14_timer[GTIMER_VIRT].cval),
+      .resetvalue = 0,
+      .readfn = gt_cval_read, .writefn = gt_cval_write,
+      .raw_readfn = raw_read, .raw_writefn = raw_write,
+    },
     REGINFO_SENTINEL
 };
 
+#else
+/* In user-mode none of the generic timer registers are accessible,
+ * and their implementation depends on vm_clock and qdev gpio outputs,
+ * so instead just don't register any of them.
+ */
+static const ARMCPRegInfo generic_timer_cp_reginfo[] = {
+    REGINFO_SENTINEL
+};
+
+#endif
+
 static int par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     if (arm_feature(env, ARM_FEATURE_LPAE)) {
diff --git a/target-arm/machine.c b/target-arm/machine.c
index 6d4c2d4..5b6f375 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 = 12,
-    .minimum_version_id = 12,
-    .minimum_version_id_old = 12,
+    .version_id = 13,
+    .minimum_version_id = 13,
+    .minimum_version_id_old = 13,
     .pre_save = cpu_pre_save,
     .post_load = cpu_post_load,
     .fields = (VMStateField[]) {
@@ -257,6 +257,8 @@ const VMStateDescription vmstate_arm_cpu = {
         VMSTATE_UINT32(env.exclusive_val, ARMCPU),
         VMSTATE_UINT32(env.exclusive_high, ARMCPU),
         VMSTATE_UINT64(env.features, ARMCPU),
+        VMSTATE_TIMER(gt_timer[GTIMER_PHYS], ARMCPU),
+        VMSTATE_TIMER(gt_timer[GTIMER_VIRT], ARMCPU),
         VMSTATE_END_OF_LIST()
     },
     .subsections = (VMStateSubsection[]) {
-- 
1.7.9.5

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

* [Qemu-devel] [PATCH v2 4/4] hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs
  2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
                   ` (2 preceding siblings ...)
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 3/4] target-arm: Implement the generic timer Peter Maydell
@ 2013-08-09 16:18 ` Peter Maydell
  2013-08-20 13:10 ` [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
  4 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2013-08-09 16:18 UTC (permalink / raw)
  To: qemu-devel; +Cc: Andreas Färber, patches

Now our A15 CPU implements the generic timers, we can wire them
up to the appropriate inputs on the GIC.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
---
 hw/cpu/a15mpcore.c |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/hw/cpu/a15mpcore.c b/hw/cpu/a15mpcore.c
index 4f37964..af182da 100644
--- a/hw/cpu/a15mpcore.c
+++ b/hw/cpu/a15mpcore.c
@@ -49,6 +49,8 @@ static int a15mp_priv_init(SysBusDevice *dev)
     A15MPPrivState *s = A15MPCORE_PRIV(dev);
     SysBusDevice *busdev;
     const char *gictype = "arm_gic";
+    int i;
+    CPUState *cpu;
 
     if (kvm_irqchip_in_kernel()) {
         gictype = "kvm-arm-gic";
@@ -67,6 +69,22 @@ static int a15mp_priv_init(SysBusDevice *dev)
     /* Pass through inbound GPIO lines to the GIC */
     qdev_init_gpio_in(DEVICE(dev), a15mp_priv_set_irq, s->num_irq - 32);
 
+    /* Wire the outputs from each CPU's generic timer to the
+     * appropriate GIC PPI inputs
+     */
+    for (i = 0, cpu = first_cpu; i < s->num_cpu; i++, cpu = cpu->next_cpu) {
+        DeviceState *cpudev = DEVICE(cpu);
+        int ppibase = s->num_irq - 32 + i * 32;
+        /* physical timer; we wire it up to the non-secure timer's ID,
+         * since a real A15 always has TrustZone but QEMU doesn't.
+         */
+        qdev_connect_gpio_out(cpudev, 0,
+                              qdev_get_gpio_in(s->gic, ppibase + 30));
+        /* virtual timer */
+        qdev_connect_gpio_out(cpudev, 1,
+                              qdev_get_gpio_in(s->gic, ppibase + 27));
+    }
+
     /* Memory map (addresses are offsets from PERIPHBASE):
      *  0x0000-0x0fff -- reserved
      *  0x1000-0x1fff -- GIC Distributor
-- 
1.7.9.5

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

* Re: [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O Peter Maydell
@ 2013-08-14  5:20   ` Edgar E. Iglesias
  0 siblings, 0 replies; 8+ messages in thread
From: Edgar E. Iglesias @ 2013-08-14  5:20 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, Andreas Färber

On Fri, Aug 09, 2013 at 05:17:58PM +0100, Peter Maydell wrote:
> Add an ARM_CP_IO flag which an ARMCPRegInfo definition can use to
> indicate that the register's implementation does I/O and thus
> its accesses need to be surrounded by gen_io_start()/gen_io_end()
> in order for icount to work. Most notably, cp registers which
> implement clocks or timers need this.

Good timing, I was just looking for this kind of mechanism... :)

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>

> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
> ---
>  target-arm/cpu.h       |    6 +++++-
>  target-arm/translate.c |   16 +++++++++++++---
>  2 files changed, 18 insertions(+), 4 deletions(-)
> 
> diff --git a/target-arm/cpu.h b/target-arm/cpu.h
> index b2dc494..770a240 100644
> --- a/target-arm/cpu.h
> +++ b/target-arm/cpu.h
> @@ -469,6 +469,9 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>   * old must have the OVERRIDE bit set.
>   * NO_MIGRATE indicates that this register should be ignored for migration;
>   * (eg because any state is accessed via some other coprocessor register).
> + * IO indicates that this register does I/O and therefore its accesses
> + * need to be surrounded by gen_io_start()/gen_io_end(). In particular,
> + * registers which implement clocks or timers require this.
>   */
>  #define ARM_CP_SPECIAL 1
>  #define ARM_CP_CONST 2
> @@ -476,13 +479,14 @@ static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
>  #define ARM_CP_SUPPRESS_TB_END 8
>  #define ARM_CP_OVERRIDE 16
>  #define ARM_CP_NO_MIGRATE 32
> +#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
>  /* Used only as a terminator for ARMCPRegInfo lists */
>  #define ARM_CP_SENTINEL 0xffff
>  /* Mask of only the flag bits in a type field */
> -#define ARM_CP_FLAG_MASK 0x3f
> +#define ARM_CP_FLAG_MASK 0x7f
>  
>  /* 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
> diff --git a/target-arm/translate.c b/target-arm/translate.c
> index 6db4c50..d1e8538 100644
> --- a/target-arm/translate.c
> +++ b/target-arm/translate.c
> @@ -6280,6 +6280,10 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>              break;
>          }
>  
> +        if (use_icount && (ri->type & ARM_CP_IO)) {
> +            gen_io_start();
> +        }
> +
>          if (isread) {
>              /* Read */
>              if (is64) {
> @@ -6369,14 +6373,20 @@ static int disas_coproc_insn(CPUARMState * env, DisasContext *s, uint32_t insn)
>                      store_cpu_offset(tmp, 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();
> +            gen_lookup_tb(s);
> +        } 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).
>               */
> -            if (!(ri->type & ARM_CP_SUPPRESS_TB_END)) {
> -                gen_lookup_tb(s);
> -            }
> +            gen_lookup_tb(s);
>          }
> +
>          return 0;
>      }
>  
> -- 
> 1.7.9.5
> 
> 

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

* Re: [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs
  2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs Peter Maydell
@ 2013-08-14  5:42   ` Edgar E. Iglesias
  0 siblings, 0 replies; 8+ messages in thread
From: Edgar E. Iglesias @ 2013-08-14  5:42 UTC (permalink / raw)
  To: Peter Maydell; +Cc: patches, qemu-devel, Andreas Färber

On Fri, Aug 09, 2013 at 05:17:57PM +0100, Peter Maydell wrote:
> Extend the raw_read() and raw_write() helper accessors so that
> they can be used for 64 bit registers as well as 32 bit registers.
>

Reviewed-by: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> Tested-by: Laurent Desnogues <laurent.desnogues@gmail.com>
> ---
>  target-arm/helper.c |   12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/target-arm/helper.c b/target-arm/helper.c
> index 4968391..fc5f757 100644
> --- a/target-arm/helper.c
> +++ b/target-arm/helper.c
> @@ -67,14 +67,22 @@ static int vfp_gdb_set_reg(CPUARMState *env, uint8_t *buf, int reg)
>  static int raw_read(CPUARMState *env, const ARMCPRegInfo *ri,
>                      uint64_t *value)
>  {
> -    *value = CPREG_FIELD32(env, ri);
> +    if (ri->type & ARM_CP_64BIT) {
> +        *value = CPREG_FIELD64(env, ri);
> +    } else {
> +        *value = CPREG_FIELD32(env, ri);
> +    }
>      return 0;
>  }
>  
>  static int raw_write(CPUARMState *env, const ARMCPRegInfo *ri,
>                       uint64_t value)
>  {
> -    CPREG_FIELD32(env, ri) = value;
> +    if (ri->type & ARM_CP_64BIT) {
> +        CPREG_FIELD64(env, ri) = value;
> +    } else {
> +        CPREG_FIELD32(env, ri) = value;
> +    }
>      return 0;
>  }
>  
> -- 
> 1.7.9.5
> 
> 

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

* Re: [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers
  2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
                   ` (3 preceding siblings ...)
  2013-08-09 16:18 ` [Qemu-devel] [PATCH v2 4/4] hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs Peter Maydell
@ 2013-08-20 13:10 ` Peter Maydell
  4 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2013-08-20 13:10 UTC (permalink / raw)
  To: QEMU Developers; +Cc: Andreas Färber, Patch Tracking

On 9 August 2013 17:17, Peter Maydell <peter.maydell@linaro.org> wrote:
> This patch series implements support for the 'generic timers',
> which are a set of timers defined in the ARM Architecture Reference
> Manual and implemented by the Cortex-A15. We've got away without
> these up til now because Linux will generally fall back on whatever
> random timer is present on the devboard if it can't find the
> on-CPU timers, but this is less than ideal. (Among other things,
> the proposed mach-virt should just use the generic timers so it
> doesn't have to provide an sp804 timer.)

Applying to target-arm.next.

-- PMM

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

end of thread, other threads:[~2013-08-20 13:10 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-08-09 16:17 [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers Peter Maydell
2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 1/4] target-arm: Allow raw_read() and raw_write() to handle 64 bit regs Peter Maydell
2013-08-14  5:42   ` Edgar E. Iglesias
2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 2/4] target-arm: Support coprocessor registers which do I/O Peter Maydell
2013-08-14  5:20   ` Edgar E. Iglesias
2013-08-09 16:17 ` [Qemu-devel] [PATCH v2 3/4] target-arm: Implement the generic timer Peter Maydell
2013-08-09 16:18 ` [Qemu-devel] [PATCH v2 4/4] hw/cpu/a15mpcore: Wire generic timer outputs to GIC inputs Peter Maydell
2013-08-20 13:10 ` [Qemu-devel] [PATCH v2 0/4] target-arm: Implement support for generic timers 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.