* [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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).