* [Qemu-devel] [PULL 01/25] i.MX: add support for lower and upper interrupt in GPIO.
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
@ 2015-12-17 11:49 ` Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 02/25] arm: explicitly mark device loads as little-endian Peter Maydell
` (24 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:49 UTC (permalink / raw)
To: qemu-devel
From: Jean-Christophe Dubois <jcd@tribudubois.net>
The i.MX6 GPIO device supports 2 interrupts instead of one.
* 1 for the lower 16 GPIOs.
* 1 for the upper 16 GPIOs.
i.MX31 and i.MX25 only support 1 interrupt for the 32 GPIOs.
So we add a property to turn the behavior on when required.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Message-id: 1447497668-1603-1-git-send-email-jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/gpio/imx_gpio.c | 12 ++++++++++--
include/hw/gpio/imx_gpio.h | 3 ++-
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/hw/gpio/imx_gpio.c b/hw/gpio/imx_gpio.c
index 3170585..a6d7cab 100644
--- a/hw/gpio/imx_gpio.c
+++ b/hw/gpio/imx_gpio.c
@@ -62,7 +62,12 @@ static const char *imx_gpio_reg_name(uint32_t reg)
static void imx_gpio_update_int(IMXGPIOState *s)
{
- qemu_set_irq(s->irq, (s->isr & s->imr) ? 1 : 0);
+ if (s->has_upper_pin_irq) {
+ qemu_set_irq(s->irq[0], (s->isr & s->imr & 0x0000FFFF) ? 1 : 0);
+ qemu_set_irq(s->irq[1], (s->isr & s->imr & 0xFFFF0000) ? 1 : 0);
+ } else {
+ qemu_set_irq(s->irq[0], (s->isr & s->imr) ? 1 : 0);
+ }
}
static void imx_gpio_set_int_line(IMXGPIOState *s, int line, IMXGPIOLevel level)
@@ -282,6 +287,8 @@ static const VMStateDescription vmstate_imx_gpio = {
static Property imx_gpio_properties[] = {
DEFINE_PROP_BOOL("has-edge-sel", IMXGPIOState, has_edge_sel, true),
+ DEFINE_PROP_BOOL("has-upper-pin-irq", IMXGPIOState, has_upper_pin_irq,
+ false),
DEFINE_PROP_END_OF_LIST(),
};
@@ -311,7 +318,8 @@ static void imx_gpio_realize(DeviceState *dev, Error **errp)
qdev_init_gpio_in(DEVICE(s), imx_gpio_set, IMX_GPIO_PIN_COUNT);
qdev_init_gpio_out(DEVICE(s), s->output, IMX_GPIO_PIN_COUNT);
- sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[0]);
+ sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[1]);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
}
diff --git a/include/hw/gpio/imx_gpio.h b/include/hw/gpio/imx_gpio.h
index 517b261..b15a09f 100644
--- a/include/hw/gpio/imx_gpio.h
+++ b/include/hw/gpio/imx_gpio.h
@@ -54,8 +54,9 @@ typedef struct IMXGPIOState {
uint32_t isr;
bool has_edge_sel;
uint32_t edge_sel;
+ bool has_upper_pin_irq;
- qemu_irq irq;
+ qemu_irq irq[2];
qemu_irq output[IMX_GPIO_PIN_COUNT];
} IMXGPIOState;
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 02/25] arm: explicitly mark device loads as little-endian
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 01/25] i.MX: add support for lower and upper interrupt in GPIO Peter Maydell
@ 2015-12-17 11:49 ` Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 03/25] arm: soc-dma: use hwaddr instead of target_ulong in printf Peter Maydell
` (23 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:49 UTC (permalink / raw)
To: qemu-devel
From: Paolo Bonzini <pbonzini@redhat.com>
Behaviour of emulated devices should not depend on the endianness
of the CPU, so avoid using the endian-dependent load and store
functions in the PXA2xx and OMAP display devices. These devices
are little endian when they do DMA access.
(Since ARM softmmu is always compiled as little endian, this means
that the endian-dependent load and store functions are always little
endian, so this commit makes no functionally visible change.)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
[PMM: rewrote commit message]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/display/omap_lcd_template.h | 4 ++--
hw/display/pxa2xx_lcd.c | 8 ++++----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/hw/display/omap_lcd_template.h b/hw/display/omap_lcd_template.h
index e5dd447..f0ce71f 100644
--- a/hw/display/omap_lcd_template.h
+++ b/hw/display/omap_lcd_template.h
@@ -136,7 +136,7 @@ static void glue(draw_line12_, DEPTH)(void *opaque,
uint8_t r, g, b;
do {
- v = lduw_p((void *) s);
+ v = lduw_le_p((void *) s);
r = (v >> 4) & 0xf0;
g = v & 0xf0;
b = (v << 4) & 0xf0;
@@ -159,7 +159,7 @@ static void glue(draw_line16_, DEPTH)(void *opaque,
uint8_t r, g, b;
do {
- v = lduw_p((void *) s);
+ v = lduw_le_p((void *) s);
r = (v >> 8) & 0xf8;
g = (v >> 3) & 0xfc;
b = (v << 3) & 0xf8;
diff --git a/hw/display/pxa2xx_lcd.c b/hw/display/pxa2xx_lcd.c
index 494700d..4d36c94 100644
--- a/hw/display/pxa2xx_lcd.c
+++ b/hw/display/pxa2xx_lcd.c
@@ -309,10 +309,10 @@ static void pxa2xx_descriptor_load(PXA2xxLCDState *s)
}
cpu_physical_memory_read(descptr, &desc, sizeof(desc));
- s->dma_ch[i].descriptor = tswap32(desc.fdaddr);
- s->dma_ch[i].source = tswap32(desc.fsaddr);
- s->dma_ch[i].id = tswap32(desc.fidr);
- s->dma_ch[i].command = tswap32(desc.ldcmd);
+ s->dma_ch[i].descriptor = le32_to_cpu(desc.fdaddr);
+ s->dma_ch[i].source = le32_to_cpu(desc.fsaddr);
+ s->dma_ch[i].id = le32_to_cpu(desc.fidr);
+ s->dma_ch[i].command = le32_to_cpu(desc.ldcmd);
}
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 03/25] arm: soc-dma: use hwaddr instead of target_ulong in printf
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 01/25] i.MX: add support for lower and upper interrupt in GPIO Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 02/25] arm: explicitly mark device loads as little-endian Peter Maydell
@ 2015-12-17 11:49 ` Peter Maydell
2015-12-17 11:49 ` [Qemu-devel] [PULL 04/25] target-arm: raise exception on misaligned LDREX operands Peter Maydell
` (22 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:49 UTC (permalink / raw)
To: qemu-devel
From: Paolo Bonzini <pbonzini@redhat.com>
This is a first baby step towards removing widespread inclusion of
cpu.h and compiling more devices once (so that arm, aarch64 and
in the future target-multi can share the object files).
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
[PMM: changed __FUNCTION__ to __func__ since we're touching
these lines of code anyway]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/dma/soc_dma.c | 39 +++++++++++++++++----------------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/hw/dma/soc_dma.c b/hw/dma/soc_dma.c
index c06aabb..94be376 100644
--- a/hw/dma/soc_dma.c
+++ b/hw/dma/soc_dma.c
@@ -269,11 +269,10 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
if (entry->type == soc_dma_port_mem) {
if (entry->addr <= virt_base &&
entry->addr + entry->u.mem.size > virt_base) {
- fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
- " collides with RAM region at " TARGET_FMT_lx
- "-" TARGET_FMT_lx "\n", __FUNCTION__,
- (target_ulong) virt_base,
- (target_ulong) entry->addr, (target_ulong)
+ fprintf(stderr, "%s: FIFO at %"PRIx64
+ " collides with RAM region at %"PRIx64
+ "-%"PRIx64 "\n", __func__,
+ virt_base, entry->addr,
(entry->addr + entry->u.mem.size));
exit(-1);
}
@@ -284,10 +283,9 @@ void soc_dma_port_add_fifo(struct soc_dma_s *soc, hwaddr virt_base,
while (entry < dma->memmap + dma->memmap_size &&
entry->addr <= virt_base) {
if (entry->addr == virt_base && entry->u.fifo.out == out) {
- fprintf(stderr, "%s: FIFO at " TARGET_FMT_lx
- " collides FIFO at " TARGET_FMT_lx "\n",
- __FUNCTION__, (target_ulong) virt_base,
- (target_ulong) entry->addr);
+ fprintf(stderr, "%s: FIFO at %"PRIx64
+ " collides FIFO at %"PRIx64 "\n",
+ __func__, virt_base, entry->addr);
exit(-1);
}
@@ -322,13 +320,11 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
if ((entry->addr >= virt_base && entry->addr < virt_base + size) ||
(entry->addr <= virt_base &&
entry->addr + entry->u.mem.size > virt_base)) {
- fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
- " collides with RAM region at " TARGET_FMT_lx
- "-" TARGET_FMT_lx "\n", __FUNCTION__,
- (target_ulong) virt_base,
- (target_ulong) (virt_base + size),
- (target_ulong) entry->addr, (target_ulong)
- (entry->addr + entry->u.mem.size));
+ fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64
+ " collides with RAM region at %"PRIx64
+ "-%"PRIx64 "\n", __func__,
+ virt_base, virt_base + size,
+ entry->addr, entry->addr + entry->u.mem.size);
exit(-1);
}
@@ -337,12 +333,11 @@ void soc_dma_port_add_mem(struct soc_dma_s *soc, uint8_t *phys_base,
} else {
if (entry->addr >= virt_base &&
entry->addr < virt_base + size) {
- fprintf(stderr, "%s: RAM at " TARGET_FMT_lx "-" TARGET_FMT_lx
- " collides with FIFO at " TARGET_FMT_lx
- "\n", __FUNCTION__,
- (target_ulong) virt_base,
- (target_ulong) (virt_base + size),
- (target_ulong) entry->addr);
+ fprintf(stderr, "%s: RAM at %"PRIx64 "-%"PRIx64
+ " collides with FIFO at %"PRIx64
+ "\n", __func__,
+ virt_base, virt_base + size,
+ entry->addr);
exit(-1);
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 04/25] target-arm: raise exception on misaligned LDREX operands
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2015-12-17 11:49 ` [Qemu-devel] [PULL 03/25] arm: soc-dma: use hwaddr instead of target_ulong in printf Peter Maydell
@ 2015-12-17 11:49 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 05/25] target-arm: Fix and improve AA32 singlestep translation completion code Peter Maydell
` (21 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:49 UTC (permalink / raw)
To: qemu-devel
From: Andrew Baumann <Andrew.Baumann@microsoft.com>
Qemu does not generally perform alignment checks. However, the ARM ARM
requires implementation of alignment exceptions for a number of cases
including LDREX, and Windows-on-ARM relies on this.
This change adds plumbing to enable alignment checks on loads using
MO_ALIGN, a do_unaligned_access hook to raise the exception (data
abort), and uses the new aligned loads in LDREX (for all but
single-byte loads).
Signed-off-by: Andrew Baumann <Andrew.Baumann@microsoft.com>
Message-id: 1449167808-5656-1-git-send-email-Andrew.Baumann@microsoft.com
[PMM: set WnR bits in syndrome and FSR as appropriate]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/cpu.c | 1 +
target-arm/helper.c | 8 ++++++++
target-arm/internals.h | 7 +++++++
target-arm/op_helper.c | 40 +++++++++++++++++++++++++++++++++++++++-
target-arm/translate.c | 11 +++++++----
5 files changed, 62 insertions(+), 5 deletions(-)
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 30739fc..35a1f12 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1417,6 +1417,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
cc->handle_mmu_fault = arm_cpu_handle_mmu_fault;
#else
cc->do_interrupt = arm_cpu_do_interrupt;
+ cc->do_unaligned_access = arm_cpu_do_unaligned_access;
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug;
cc->vmsd = &vmstate_arm_cpu;
cc->virtio_is_big_endian = arm_cpu_is_big_endian;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index afc4163..59d5a41 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5996,6 +5996,14 @@ static inline bool regime_using_lpae_format(CPUARMState *env,
return false;
}
+/* Returns true if the translation regime is using LPAE format page tables.
+ * Used when raising alignment exceptions, whose FSR changes depending on
+ * whether the long or short descriptor format is in use. */
+bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx)
+{
+ return regime_using_lpae_format(env, mmu_idx);
+}
+
static inline bool regime_is_user(CPUARMState *env, ARMMMUIdx mmu_idx)
{
switch (mmu_idx) {
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 347998c..b925aaa 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -441,4 +441,11 @@ struct ARMMMUFaultInfo {
bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx,
uint32_t *fsr, ARMMMUFaultInfo *fi);
+/* Return true if the translation regime is using LPAE format page tables */
+bool arm_regime_using_lpae_format(CPUARMState *env, ARMMMUIdx mmu_idx);
+
+/* Raise a data fault alignment exception for the specified virtual address */
+void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
+ int is_user, uintptr_t retaddr);
+
#endif
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 6cd54c8..e42d287 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -126,7 +126,45 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
raise_exception(env, exc, syn, target_el);
}
}
-#endif
+
+/* Raise a data fault alignment exception for the specified virtual address */
+void arm_cpu_do_unaligned_access(CPUState *cs, vaddr vaddr, int is_write,
+ int is_user, uintptr_t retaddr)
+{
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+ int target_el;
+ bool same_el;
+
+ if (retaddr) {
+ /* now we have a real cpu fault */
+ cpu_restore_state(cs, retaddr);
+ }
+
+ target_el = exception_target_el(env);
+ same_el = (arm_current_el(env) == target_el);
+
+ env->exception.vaddress = vaddr;
+
+ /* the DFSR for an alignment fault depends on whether we're using
+ * the LPAE long descriptor format, or the short descriptor format
+ */
+ if (arm_regime_using_lpae_format(env, cpu_mmu_index(env, false))) {
+ env->exception.fsr = 0x21;
+ } else {
+ env->exception.fsr = 0x1;
+ }
+
+ if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) {
+ env->exception.fsr |= (1 << 11);
+ }
+
+ raise_exception(env, EXCP_DATA_ABORT,
+ syn_data_abort(same_el, 0, 0, 0, is_write == 1, 0x21),
+ target_el);
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
{
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 5d22879..12dbfac 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -926,13 +926,13 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
#define DO_GEN_LD(SUFF, OPC) \
static inline void gen_aa32_ld##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
{ \
- tcg_gen_qemu_ld_i32(val, addr, index, OPC); \
+ tcg_gen_qemu_ld_i32(val, addr, index, (OPC)); \
}
#define DO_GEN_ST(SUFF, OPC) \
static inline void gen_aa32_st##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
{ \
- tcg_gen_qemu_st_i32(val, addr, index, OPC); \
+ tcg_gen_qemu_st_i32(val, addr, index, (OPC)); \
}
static inline void gen_aa32_ld64(TCGv_i64 val, TCGv_i32 addr, int index)
@@ -988,6 +988,9 @@ DO_GEN_LD(8u, MO_UB)
DO_GEN_LD(16s, MO_TESW)
DO_GEN_LD(16u, MO_TEUW)
DO_GEN_LD(32u, MO_TEUL)
+/* 'a' variants include an alignment check */
+DO_GEN_LD(16ua, MO_TEUW | MO_ALIGN)
+DO_GEN_LD(32ua, MO_TEUL | MO_ALIGN)
DO_GEN_ST(8, MO_UB)
DO_GEN_ST(16, MO_TEUW)
DO_GEN_ST(32, MO_TEUL)
@@ -7435,11 +7438,11 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
break;
case 1:
- gen_aa32_ld16u(tmp, addr, get_mem_index(s));
+ gen_aa32_ld16ua(tmp, addr, get_mem_index(s));
break;
case 2:
case 3:
- gen_aa32_ld32u(tmp, addr, get_mem_index(s));
+ gen_aa32_ld32ua(tmp, addr, get_mem_index(s));
break;
default:
abort();
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 05/25] target-arm: Fix and improve AA32 singlestep translation completion code
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2015-12-17 11:49 ` [Qemu-devel] [PULL 04/25] target-arm: raise exception on misaligned LDREX operands Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 06/25] acpi: support serialized method Peter Maydell
` (20 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Sergey Fedorov <serge.fdrv@gmail.com>
The AArch32 translation completion code for singlestep enabled/active
case was a way more confusing and too repetitive then it needs to be.
Probably that was the cause for a bug to be introduced into it at some
point. The bug was that SWI/HVC/SMC exception would be generated in
condition-failed instruction code path whereas it shouldn't.
This patch rewrites the code in a way similar to the non-singlestep
case.
In the condition-passed/unconditional instruction code path we need to:
- Write the condexec bits back to the CPU state
- Advance the singlestep state machine and generate a corresponding
exception in case of SWI/HVC/SMC
- Write the PC back to the CPU state if it hasn't already been written
and generate an appropriate singlestep exception otherwise
In the condition-failed instruction code path we need to:
- Set a TCG label to jump to it if the condition is failed
- Write the condexec bits back to the CPU state
- Write the PC back to the CPU state since it hasn't been written in
this case
- Generate an appropriate singlestep exception
Signed-off-by: Sergey Fedorov <serge.fdrv@gmail.com>
Message-id: 1448474560-22475-1-git-send-email-serge.fdrv@gmail.com
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/translate.c | 65 ++++++++++++++++++++++++--------------------------
1 file changed, 31 insertions(+), 34 deletions(-)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 12dbfac..d485e7d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -11483,48 +11483,45 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
instruction was a conditional branch or trap, and the PC has
already been written. */
if (unlikely(cs->singlestep_enabled || dc->ss_active)) {
- /* Make sure the pc is updated, and raise a debug exception. */
- if (dc->condjmp) {
- gen_set_condexec(dc);
- if (dc->is_jmp == DISAS_SWI) {
- gen_ss_advance(dc);
- gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
- default_exception_el(dc));
- } else if (dc->is_jmp == DISAS_HVC) {
- gen_ss_advance(dc);
- gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
- } else if (dc->is_jmp == DISAS_SMC) {
- gen_ss_advance(dc);
- gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
- } else if (dc->ss_active) {
- gen_step_complete_exception(dc);
- } else {
- gen_exception_internal(EXCP_DEBUG);
- }
- gen_set_label(dc->condlabel);
- }
- if (dc->condjmp || dc->is_jmp == DISAS_NEXT ||
- dc->is_jmp == DISAS_UPDATE) {
- gen_set_pc_im(dc, dc->pc);
- dc->condjmp = 0;
- }
+ /* Unconditional and "condition passed" instruction codepath. */
gen_set_condexec(dc);
- if (dc->is_jmp == DISAS_SWI && !dc->condjmp) {
+ switch (dc->is_jmp) {
+ case DISAS_SWI:
gen_ss_advance(dc);
gen_exception(EXCP_SWI, syn_aa32_svc(dc->svc_imm, dc->thumb),
default_exception_el(dc));
- } else if (dc->is_jmp == DISAS_HVC && !dc->condjmp) {
+ break;
+ case DISAS_HVC:
gen_ss_advance(dc);
gen_exception(EXCP_HVC, syn_aa32_hvc(dc->svc_imm), 2);
- } else if (dc->is_jmp == DISAS_SMC && !dc->condjmp) {
+ break;
+ case DISAS_SMC:
gen_ss_advance(dc);
gen_exception(EXCP_SMC, syn_aa32_smc(), 3);
- } else if (dc->ss_active) {
- gen_step_complete_exception(dc);
- } else {
- /* FIXME: Single stepping a WFI insn will not halt
- the CPU. */
- gen_exception_internal(EXCP_DEBUG);
+ break;
+ case DISAS_NEXT:
+ case DISAS_UPDATE:
+ gen_set_pc_im(dc, dc->pc);
+ /* fall through */
+ default:
+ if (dc->ss_active) {
+ gen_step_complete_exception(dc);
+ } else {
+ /* FIXME: Single stepping a WFI insn will not halt
+ the CPU. */
+ gen_exception_internal(EXCP_DEBUG);
+ }
+ }
+ if (dc->condjmp) {
+ /* "Condition failed" instruction codepath. */
+ gen_set_label(dc->condlabel);
+ gen_set_condexec(dc);
+ gen_set_pc_im(dc, dc->pc);
+ if (dc->ss_active) {
+ gen_step_complete_exception(dc);
+ } else {
+ gen_exception_internal(EXCP_DEBUG);
+ }
}
} else {
/* While branches must always occur at the end of an IT block,
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 06/25] acpi: support serialized method
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 05/25] target-arm: Fix and improve AA32 singlestep translation completion code Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 07/25] acpi: extend aml_interrupt() to support multiple irqs Peter Maydell
` (19 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Xiao Guangrong <guangrong.xiao@linux.intel.com>
Add serialized method support so that explicit Mutex can be
avoided
Signed-off-by: Xiao Guangrong <guangrong.xiao@linux.intel.com>
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1449804086-3464-2-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/acpi/aml-build.c | 17 +++++++++++++++--
hw/arm/virt-acpi-build.c | 10 +++++-----
hw/i386/acpi-build.c | 41 +++++++++++++++++++++--------------------
include/hw/acpi/aml-build.h | 8 +++++++-
4 files changed, 48 insertions(+), 28 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index a00a0ab..411c0e5 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -696,11 +696,24 @@ Aml *aml_while(Aml *predicate)
}
/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: DefMethod */
-Aml *aml_method(const char *name, int arg_count)
+Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag)
{
Aml *var = aml_bundle(0x14 /* MethodOp */, AML_PACKAGE);
+ int methodflags;
+
+ /*
+ * MethodFlags:
+ * bit 0-2: ArgCount (0-7)
+ * bit 3: SerializeFlag
+ * 0: NotSerialized
+ * 1: Serialized
+ * bit 4-7: reserved (must be 0)
+ */
+ assert(arg_count < 8);
+ methodflags = arg_count | (sflag << 3);
+
build_append_namestring(var->buf, "%s", name);
- build_append_byte(var->buf, arg_count); /* MethodFlags: ArgCount */
+ build_append_byte(var->buf, methodflags); /* MethodFlags: ArgCount */
return var;
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 3c2c5d6..38ab844 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -212,16 +212,16 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, irq + i));
aml_append(dev_gsi, aml_name_decl("_CRS", crs));
- method = aml_method("_SRS", 1);
+ method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
aml_append(dev_gsi, method);
aml_append(dev, dev_gsi);
}
- method = aml_method("_CBA", 0);
+ method = aml_method("_CBA", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(base_ecam)));
aml_append(dev, method);
- method = aml_method("_CRS", 0);
+ method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
Aml *rbuf = aml_resource_template();
aml_append(rbuf,
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
@@ -254,7 +254,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
/* Declare an _OSC (OS Control Handoff) method */
aml_append(dev, aml_name_decl("SUPP", aml_int(0)));
aml_append(dev, aml_name_decl("CTRL", aml_int(0)));
- method = aml_method("_OSC", 4);
+ method = aml_method("_OSC", 4, AML_NOTSERIALIZED);
aml_append(method,
aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1"));
@@ -296,7 +296,7 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
aml_append(method, elsectx);
aml_append(dev, method);
- method = aml_method("_DSM", 4);
+ method = aml_method("_DSM", 4, AML_NOTSERIALIZED);
/* PCI Firmware Specification 3.0
* 4.6.1. _DSM for PCI Express Slot Information
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 95e0c65..5856329 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -487,7 +487,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
int64_t bsel_val = qint_get_int(qobject_to_qint(bsel));
aml_append(parent_scope, aml_name_decl("BSEL", aml_int(bsel_val)));
- notify_method = aml_method("DVNT", 2);
+ notify_method = aml_method("DVNT", 2, AML_NOTSERIALIZED);
}
for (i = 0; i < ARRAY_SIZE(bus->devices); i += PCI_FUNC_MAX) {
@@ -503,7 +503,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
dev = aml_device("S%.02X", PCI_DEVFN(slot, 0));
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
aml_append(dev, aml_name_decl("_ADR", aml_int(slot << 16)));
- method = aml_method("_EJ0", 1);
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
@@ -546,22 +546,22 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
s3d = 0;
}
- method = aml_method("_S1D", 0);
+ method = aml_method("_S1D", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(0)));
aml_append(dev, method);
- method = aml_method("_S2D", 0);
+ method = aml_method("_S2D", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(0)));
aml_append(dev, method);
- method = aml_method("_S3D", 0);
+ method = aml_method("_S3D", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_int(s3d)));
aml_append(dev, method);
} else if (hotplug_enabled_dev) {
/* add _SUN/_EJ0 to make slot hotpluggable */
aml_append(dev, aml_name_decl("_SUN", aml_int(slot)));
- method = aml_method("_EJ0", 1);
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_call2("PCEJ", aml_name("BSEL"), aml_name("_SUN"))
);
@@ -590,7 +590,7 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
/* Append PCNT method to notify about events on local and child buses.
* Add unconditionally for root since DSDT expects it.
*/
- method = aml_method("PCNT", 0);
+ method = aml_method("PCNT", 0, AML_NOTSERIALIZED);
/* If bus supports hotplug select it and notify about local events */
if (bsel) {
@@ -651,7 +651,7 @@ static Aml *build_prt(void)
{
Aml *method, *while_ctx, *pin, *res;
- method = aml_method("_PRT", 0);
+ method = aml_method("_PRT", 0, AML_NOTSERIALIZED);
res = aml_local(0);
pin = aml_local(1);
aml_append(method, aml_store(aml_package(128), res));
@@ -1112,12 +1112,12 @@ build_ssdt(GArray *table_data, GArray *linker,
/* device present, functioning, decoding, shown in UI */
aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
- method = aml_method("RDPT", 0);
+ method = aml_method("RDPT", 0, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_name("PEPT"), aml_local(0)));
aml_append(method, aml_return(aml_local(0)));
aml_append(dev, method);
- method = aml_method("WRPT", 1);
+ method = aml_method("WRPT", 1, AML_NOTSERIALIZED);
aml_append(method, aml_store(aml_arg(0), aml_name("PEPT")));
aml_append(dev, method);
@@ -1153,15 +1153,15 @@ build_ssdt(GArray *table_data, GArray *linker,
for (i = 0; i < acpi_cpus; i++) {
dev = aml_processor(i, 0, 0, "CP%.02X", i);
- method = aml_method("_MAT", 0);
+ method = aml_method("_MAT", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_call1("CPMA", aml_int(i))));
aml_append(dev, method);
- method = aml_method("_STA", 0);
+ method = aml_method("_STA", 0, AML_NOTSERIALIZED);
aml_append(method, aml_return(aml_call1("CPST", aml_int(i))));
aml_append(dev, method);
- method = aml_method("_EJ0", 1);
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
aml_append(method,
aml_return(aml_call2("CPEJ", aml_int(i), aml_arg(0)))
);
@@ -1174,7 +1174,7 @@ build_ssdt(GArray *table_data, GArray *linker,
* Method(NTFY, 2) {If (LEqual(Arg0, 0x00)) {Notify(CP00, Arg1)} ...}
*/
/* Arg0 = Processor ID = APIC ID */
- method = aml_method("NTFY", 2);
+ method = aml_method("NTFY", 2, AML_NOTSERIALIZED);
for (i = 0; i < acpi_cpus; i++) {
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
aml_append(ifctx,
@@ -1269,29 +1269,29 @@ build_ssdt(GArray *table_data, GArray *linker,
aml_append(dev, aml_name_decl("_UID", aml_string("0x%02X", i)));
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C80")));
- method = aml_method("_CRS", 0);
+ method = aml_method("_CRS", 0, AML_NOTSERIALIZED);
s = BASEPATH stringify(MEMORY_SLOT_CRS_METHOD);
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
aml_append(dev, method);
- method = aml_method("_STA", 0);
+ method = aml_method("_STA", 0, AML_NOTSERIALIZED);
s = BASEPATH stringify(MEMORY_SLOT_STATUS_METHOD);
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
aml_append(dev, method);
- method = aml_method("_PXM", 0);
+ method = aml_method("_PXM", 0, AML_NOTSERIALIZED);
s = BASEPATH stringify(MEMORY_SLOT_PROXIMITY_METHOD);
aml_append(method, aml_return(aml_call1(s, aml_name("_UID"))));
aml_append(dev, method);
- method = aml_method("_OST", 3);
+ method = aml_method("_OST", 3, AML_NOTSERIALIZED);
s = BASEPATH stringify(MEMORY_SLOT_OST_METHOD);
aml_append(method, aml_return(aml_call4(
s, aml_name("_UID"), aml_arg(0), aml_arg(1), aml_arg(2)
)));
aml_append(dev, method);
- method = aml_method("_EJ0", 1);
+ method = aml_method("_EJ0", 1, AML_NOTSERIALIZED);
s = BASEPATH stringify(MEMORY_SLOT_EJECT_METHOD);
aml_append(method, aml_return(aml_call2(
s, aml_name("_UID"), aml_arg(0))));
@@ -1303,7 +1303,8 @@ build_ssdt(GArray *table_data, GArray *linker,
/* build Method(MEMORY_SLOT_NOTIFY_METHOD, 2) {
* If (LEqual(Arg0, 0x00)) {Notify(MP00, Arg1)} ... }
*/
- method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2);
+ method = aml_method(stringify(MEMORY_SLOT_NOTIFY_METHOD), 2,
+ AML_NOTSERIALIZED);
for (i = 0; i < nr_mem; i++) {
ifctx = aml_if(aml_equal(aml_arg(0), aml_int(i)));
aml_append(ifctx,
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 1b632dc..a3580e1 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -148,6 +148,12 @@ typedef enum {
AML_SHARED_AND_WAKE = 3,
} AmlShared;
+/* ACPI 1.0b: 16.2.5.2 Named Objects Encoding: MethodFlags */
+typedef enum {
+ AML_NOTSERIALIZED = 0,
+ AML_SERIALIZED = 1,
+} AmlSerializeFlag;
+
typedef
struct AcpiBuildTables {
GArray *table_data;
@@ -262,7 +268,7 @@ Aml *aml_qword_memory(AmlDecode dec, AmlMinFixed min_fixed,
/* Block AML object primitives */
Aml *aml_scope(const char *name_format, ...) GCC_FMT_ATTR(1, 2);
Aml *aml_device(const char *name_format, ...) GCC_FMT_ATTR(1, 2);
-Aml *aml_method(const char *name, int arg_count);
+Aml *aml_method(const char *name, int arg_count, AmlSerializeFlag sflag);
Aml *aml_if(Aml *predicate);
Aml *aml_else(void);
Aml *aml_while(Aml *predicate);
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 07/25] acpi: extend aml_interrupt() to support multiple irqs
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 06/25] acpi: support serialized method Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 08/25] ARM: Virt: Add a GPIO controller Peter Maydell
` (18 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Igor Mammedov <imammedo@redhat.com>
ASL Interrupt() macro translates to Extended Interrupt Descriptor
which supports variable number of IRQs. It will be used for
conversion of ASL code for pc/q35 machines that use it for
returning several IRQs in _PSR object.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1449804086-3464-3-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/acpi/aml-build.c | 22 +++++++++++++---------
hw/arm/virt-acpi-build.c | 23 ++++++++++++-----------
include/hw/acpi/aml-build.h | 2 +-
3 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 411c0e5..cd25d06 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -598,23 +598,27 @@ Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
AmlLevelAndEdge level_and_edge,
AmlActiveHighAndLow high_and_low, AmlShared shared,
- uint32_t irq)
+ uint32_t *irq_list, uint8_t irq_count)
{
+ int i;
Aml *var = aml_alloc();
uint8_t irq_flags = con_and_pro | (level_and_edge << 1)
| (high_and_low << 2) | (shared << 3);
+ const int header_bytes_in_len = 2;
+ uint16_t len = header_bytes_in_len + irq_count * sizeof(uint32_t);
+
+ assert(irq_count > 0);
build_append_byte(var->buf, 0x89); /* Extended irq descriptor */
- build_append_byte(var->buf, 6); /* Length, bits[7:0] minimum value = 6 */
- build_append_byte(var->buf, 0); /* Length, bits[15:8] minimum value = 0 */
+ build_append_byte(var->buf, len & 0xFF); /* Length, bits[7:0] */
+ build_append_byte(var->buf, len >> 8); /* Length, bits[15:8] */
build_append_byte(var->buf, irq_flags); /* Interrupt Vector Information. */
- build_append_byte(var->buf, 0x01); /* Interrupt table length = 1 */
+ build_append_byte(var->buf, irq_count); /* Interrupt table length */
- /* Interrupt Number */
- build_append_byte(var->buf, extract32(irq, 0, 8)); /* bits[7:0] */
- build_append_byte(var->buf, extract32(irq, 8, 8)); /* bits[15:8] */
- build_append_byte(var->buf, extract32(irq, 16, 8)); /* bits[23:16] */
- build_append_byte(var->buf, extract32(irq, 24, 8)); /* bits[31:24] */
+ /* Interrupt Number List */
+ for (i = 0; i < irq_count; i++) {
+ build_append_int_noprefix(var->buf, irq_list[i], 4);
+ }
return var;
}
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 38ab844..1deebfe 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -71,7 +71,7 @@ static void acpi_dsdt_add_cpus(Aml *scope, int smp_cpus)
}
static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
- int uart_irq)
+ uint32_t uart_irq)
{
Aml *dev = aml_device("COM0");
aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0011")));
@@ -82,7 +82,7 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
uart_memmap->size, AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, uart_irq));
+ AML_EXCLUSIVE, &uart_irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
/* The _ADR entry is used to link this device to the UART described
@@ -94,7 +94,7 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap,
}
static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
- int rtc_irq)
+ uint32_t rtc_irq)
{
Aml *dev = aml_device("RTC0");
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0013")));
@@ -105,7 +105,7 @@ static void acpi_dsdt_add_rtc(Aml *scope, const MemMapEntry *rtc_memmap,
rtc_memmap->size, AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, rtc_irq));
+ AML_EXCLUSIVE, &rtc_irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
}
@@ -136,14 +136,14 @@ static void acpi_dsdt_add_flash(Aml *scope, const MemMapEntry *flash_memmap)
static void acpi_dsdt_add_virtio(Aml *scope,
const MemMapEntry *virtio_mmio_memmap,
- int mmio_irq, int num)
+ uint32_t mmio_irq, int num)
{
hwaddr base = virtio_mmio_memmap->base;
hwaddr size = virtio_mmio_memmap->size;
- int irq = mmio_irq;
int i;
for (i = 0; i < num; i++) {
+ uint32_t irq = mmio_irq + i;
Aml *dev = aml_device("VR%02u", i);
aml_append(dev, aml_name_decl("_HID", aml_string("LNRO0005")));
aml_append(dev, aml_name_decl("_UID", aml_int(i)));
@@ -152,15 +152,15 @@ static void acpi_dsdt_add_virtio(Aml *scope,
aml_append(crs, aml_memory32_fixed(base, size, AML_READ_WRITE));
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, irq + i));
+ AML_EXCLUSIVE, &irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
base += size;
}
}
-static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
- bool use_highmem)
+static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
+ uint32_t irq, bool use_highmem)
{
Aml *method, *crs, *ifctx, *UUID, *ifctx1, *elsectx, *buf;
int i, bus_no;
@@ -199,18 +199,19 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap, int irq,
/* Create GSI link device */
for (i = 0; i < PCI_NUM_PINS; i++) {
+ uint32_t irqs = irq + i;
Aml *dev_gsi = aml_device("GSI%d", i);
aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F")));
aml_append(dev_gsi, aml_name_decl("_UID", aml_int(0)));
crs = aml_resource_template();
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, irq + i));
+ AML_EXCLUSIVE, &irqs, 1));
aml_append(dev_gsi, aml_name_decl("_PRS", crs));
crs = aml_resource_template();
aml_append(crs,
aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
- AML_EXCLUSIVE, irq + i));
+ AML_EXCLUSIVE, &irqs, 1));
aml_append(dev_gsi, aml_name_decl("_CRS", crs));
method = aml_method("_SRS", 1, AML_NOTSERIALIZED);
aml_append(dev_gsi, method);
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index a3580e1..c2c0be3 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -223,7 +223,7 @@ Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
AmlLevelAndEdge level_and_edge,
AmlActiveHighAndLow high_and_low, AmlShared shared,
- uint32_t irq);
+ uint32_t *irq_list, uint8_t irq_count);
Aml *aml_io(AmlIODecode dec, uint16_t min_base, uint16_t max_base,
uint8_t aln, uint8_t len);
Aml *aml_operation_region(const char *name, AmlRegionSpace rs,
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 08/25] ARM: Virt: Add a GPIO controller
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 07/25] acpi: extend aml_interrupt() to support multiple irqs Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 09/25] ARM: ACPI: Add GPIO controller in ACPI DSDT table Peter Maydell
` (17 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
ACPI 5.0 supports GPIO-signaled ACPI Events. This can be used for
powerdown, hotplug evnets. Add a GPIO controller in machine virt,
to support powerdown, maybe can be used for cpu hotplug. And
here we use pl061.
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Wei Huang <wei@redhat.com>
Tested-by: Wei Huang <wei@redhat.com>
Message-id: 1449804086-3464-4-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt.c | 30 ++++++++++++++++++++++++++++++
include/hw/arm/virt.h | 1 +
2 files changed, 31 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 9c6792c..7977e3c 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -120,6 +120,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
+ [VIRT_GPIO] = { 0x09030000, 0x00001000 },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@@ -135,6 +136,7 @@ static const int a15irqmap[] = {
[VIRT_UART] = 1,
[VIRT_RTC] = 2,
[VIRT_PCIE] = 3, /* ... to 6 */
+ [VIRT_GPIO] = 7,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
@@ -538,6 +540,32 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
g_free(nodename);
}
+static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
+{
+ char *nodename;
+ hwaddr base = vbi->memmap[VIRT_GPIO].base;
+ hwaddr size = vbi->memmap[VIRT_GPIO].size;
+ int irq = vbi->irqmap[VIRT_GPIO];
+ const char compat[] = "arm,pl061\0arm,primecell";
+
+ sysbus_create_simple("pl061", base, pic[irq]);
+
+ nodename = g_strdup_printf("/pl061@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base, 2, size);
+ qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "#gpio-cells", 2);
+ qemu_fdt_setprop(vbi->fdt, nodename, "gpio-controller", NULL, 0);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
+ qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
+
+ g_free(nodename);
+}
+
static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
{
int i;
@@ -1041,6 +1069,8 @@ static void machvirt_init(MachineState *machine)
create_pcie(vbi, pic, vms->highmem);
+ create_gpio(vbi, pic);
+
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index f464586..925faa7 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -59,6 +59,7 @@ enum {
VIRT_PCIE_ECAM,
VIRT_PLATFORM_BUS,
VIRT_PCIE_MMIO_HIGH,
+ VIRT_GPIO,
};
typedef struct MemMapEntry {
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 09/25] ARM: ACPI: Add GPIO controller in ACPI DSDT table
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 08/25] ARM: Virt: Add a GPIO controller Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 10/25] ARM: ACPI: Add power button device " Peter Maydell
` (16 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Add GPIO controller in ACPI DSDT table. It can be used for gpio event.
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Wei Huang <wei@redhat.com>
Message-id: 1449804086-3464-5-git-send-email-zhaoshenglong@huawei.com
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt-acpi-build.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 1deebfe..fcc08f7 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -324,6 +324,23 @@ static void acpi_dsdt_add_pci(Aml *scope, const MemMapEntry *memmap,
aml_append(scope, dev);
}
+static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
+ uint32_t gpio_irq)
+{
+ Aml *dev = aml_device("GPO0");
+ aml_append(dev, aml_name_decl("_HID", aml_string("ARMH0061")));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+
+ Aml *crs = aml_resource_template();
+ aml_append(crs, aml_memory32_fixed(gpio_memmap->base, gpio_memmap->size,
+ AML_READ_WRITE));
+ aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, &gpio_irq, 1));
+ aml_append(dev, aml_name_decl("_CRS", crs));
+ aml_append(scope, dev);
+}
+
/* RSDP */
static GArray *
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
@@ -540,6 +557,8 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
(irqmap[VIRT_MMIO] + ARM_SPI_BASE), NUM_VIRTIO_TRANSPORTS);
acpi_dsdt_add_pci(scope, memmap, (irqmap[VIRT_PCIE] + ARM_SPI_BASE),
guest_info->use_highmem);
+ acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
+ (irqmap[VIRT_GPIO] + ARM_SPI_BASE));
aml_append(dsdt, scope);
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 10/25] ARM: ACPI: Add power button device in ACPI DSDT table
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 09/25] ARM: ACPI: Add GPIO controller in ACPI DSDT table Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 11/25] ACPI: Add GPIO Connection Descriptor Peter Maydell
` (15 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Add power button device in ACPI DSDT table.
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Wei Huang <wei@redhat.com>
Tested-by: Wei Huang <wei@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-id: 1449804086-3464-6-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt-acpi-build.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index fcc08f7..e5dc2d5 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -43,6 +43,7 @@
#include "hw/pci/pci.h"
#define ARM_SPI_BASE 32
+#define ACPI_POWER_BUTTON_DEVICE "PWRB"
typedef struct VirtAcpiCpuInfo {
DECLARE_BITMAP(found_cpus, VIRT_ACPI_CPU_ID_LIMIT);
@@ -341,6 +342,15 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
aml_append(scope, dev);
}
+static void acpi_dsdt_add_power_button(Aml *scope)
+{
+ Aml *dev = aml_device(ACPI_POWER_BUTTON_DEVICE);
+ aml_append(dev, aml_name_decl("_HID", aml_string("PNP0C0C")));
+ aml_append(dev, aml_name_decl("_ADR", aml_int(0)));
+ aml_append(dev, aml_name_decl("_UID", aml_int(0)));
+ aml_append(scope, dev);
+}
+
/* RSDP */
static GArray *
build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
@@ -559,6 +569,7 @@ build_dsdt(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info)
guest_info->use_highmem);
acpi_dsdt_add_gpio(scope, &memmap[VIRT_GPIO],
(irqmap[VIRT_GPIO] + ARM_SPI_BASE));
+ acpi_dsdt_add_power_button(scope);
aml_append(dsdt, scope);
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 11/25] ACPI: Add GPIO Connection Descriptor
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 10/25] ARM: ACPI: Add power button device " Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 12/25] ACPI: Add aml_gpio_int() wrapper for GPIO Interrupt Connection Peter Maydell
` (14 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Wei Huang <wei@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-id: 1449804086-3464-7-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/acpi/aml-build.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
include/hw/acpi/aml-build.h | 20 +++++++++++++
2 files changed, 88 insertions(+)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index cd25d06..d8c33a2 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -565,6 +565,74 @@ Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4)
}
/*
+ * ACPI 5.0: 6.4.3.8.1 GPIO Connection Descriptor
+ * Type 1, Large Item Name 0xC
+ */
+
+static Aml *aml_gpio_connection(AmlGpioConnectionType type,
+ AmlConsumerAndProducer con_and_pro,
+ uint8_t flags, AmlPinConfig pin_config,
+ uint16_t output_drive,
+ uint16_t debounce_timeout,
+ const uint32_t pin_list[], uint32_t pin_count,
+ const char *resource_source_name,
+ const uint8_t *vendor_data,
+ uint16_t vendor_data_len)
+{
+ Aml *var = aml_alloc();
+ const uint16_t min_desc_len = 0x16;
+ uint16_t resource_source_name_len, length;
+ uint16_t pin_table_offset, resource_source_name_offset, vendor_data_offset;
+ uint32_t i;
+
+ assert(resource_source_name);
+ resource_source_name_len = strlen(resource_source_name) + 1;
+ length = min_desc_len + resource_source_name_len + vendor_data_len;
+ pin_table_offset = min_desc_len + 1;
+ resource_source_name_offset = pin_table_offset + pin_count * 2;
+ vendor_data_offset = resource_source_name_offset + resource_source_name_len;
+
+ build_append_byte(var->buf, 0x8C); /* GPIO Connection Descriptor */
+ build_append_int_noprefix(var->buf, length, 2); /* Length */
+ build_append_byte(var->buf, 1); /* Revision ID */
+ build_append_byte(var->buf, type); /* GPIO Connection Type */
+ /* General Flags (2 bytes) */
+ build_append_int_noprefix(var->buf, con_and_pro, 2);
+ /* Interrupt and IO Flags (2 bytes) */
+ build_append_int_noprefix(var->buf, flags, 2);
+ /* Pin Configuration 0 = Default 1 = Pull-up 2 = Pull-down 3 = No Pull */
+ build_append_byte(var->buf, pin_config);
+ /* Output Drive Strength (2 bytes) */
+ build_append_int_noprefix(var->buf, output_drive, 2);
+ /* Debounce Timeout (2 bytes) */
+ build_append_int_noprefix(var->buf, debounce_timeout, 2);
+ /* Pin Table Offset (2 bytes) */
+ build_append_int_noprefix(var->buf, pin_table_offset, 2);
+ build_append_byte(var->buf, 0); /* Resource Source Index */
+ /* Resource Source Name Offset (2 bytes) */
+ build_append_int_noprefix(var->buf, resource_source_name_offset, 2);
+ /* Vendor Data Offset (2 bytes) */
+ build_append_int_noprefix(var->buf, vendor_data_offset, 2);
+ /* Vendor Data Length (2 bytes) */
+ build_append_int_noprefix(var->buf, vendor_data_len, 2);
+ /* Pin Number (2n bytes)*/
+ for (i = 0; i < pin_count; i++) {
+ build_append_int_noprefix(var->buf, pin_list[i], 2);
+ }
+
+ /* Resource Source Name */
+ build_append_namestring(var->buf, "%s", resource_source_name);
+ build_append_byte(var->buf, '\0');
+
+ /* Vendor-defined Data */
+ if (vendor_data != NULL) {
+ g_array_append_vals(var->buf, vendor_data, vendor_data_len);
+ }
+
+ return var;
+}
+
+/*
* ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
* (Type 1, Large Item Name 0x6)
*/
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index c2c0be3..f1817e4 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -154,6 +154,26 @@ typedef enum {
AML_SERIALIZED = 1,
} AmlSerializeFlag;
+/*
+ * ACPI 5.0: Table 6-189 GPIO Connection Descriptor Definition
+ * GPIO Connection Type
+ */
+typedef enum {
+ AML_INTERRUPT_CONNECTION = 0,
+ AML_IO_CONNECTION = 1,
+} AmlGpioConnectionType;
+
+/*
+ * ACPI 5.0: Table 6-189 GPIO Connection Descriptor Definition
+ * _PPI field definition
+ */
+typedef enum {
+ AML_PULL_DEFAULT = 0,
+ AML_PULL_UP = 1,
+ AML_PULL_DOWN = 2,
+ AML_PULL_NONE = 3,
+} AmlPinConfig;
+
typedef
struct AcpiBuildTables {
GArray *table_data;
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 12/25] ACPI: Add aml_gpio_int() wrapper for GPIO Interrupt Connection
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 11/25] ACPI: Add GPIO Connection Descriptor Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 13/25] ARM: ACPI: Add _E03 for Power Button Peter Maydell
` (13 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Wei Huang <wei@redhat.com>
Reviewed-by: Igor Mammedov <imammedo@redhat.com>
Message-id: 1449804086-3464-8-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/acpi/aml-build.c | 20 ++++++++++++++++++++
include/hw/acpi/aml-build.h | 7 +++++++
2 files changed, 27 insertions(+)
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index d8c33a2..302cf01 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -633,6 +633,26 @@ static Aml *aml_gpio_connection(AmlGpioConnectionType type,
}
/*
+ * ACPI 5.0: 19.5.53
+ * GpioInt(GPIO Interrupt Connection Resource Descriptor Macro)
+ */
+Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
+ AmlLevelAndEdge edge_level,
+ AmlActiveHighAndLow active_level, AmlShared shared,
+ AmlPinConfig pin_config, uint16_t debounce_timeout,
+ const uint32_t pin_list[], uint32_t pin_count,
+ const char *resource_source_name,
+ const uint8_t *vendor_data, uint16_t vendor_data_len)
+{
+ uint8_t flags = edge_level | (active_level << 1) | (shared << 3);
+
+ return aml_gpio_connection(AML_INTERRUPT_CONNECTION, con_and_pro, flags,
+ pin_config, 0, debounce_timeout, pin_list,
+ pin_count, resource_source_name, vendor_data,
+ vendor_data_len);
+}
+
+/*
* ACPI 1.0b: 6.4.3.4 32-Bit Fixed Location Memory Range Descriptor
* (Type 1, Large Item Name 0x6)
*/
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index f1817e4..0d36453 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -238,6 +238,13 @@ Aml *aml_call1(const char *method, Aml *arg1);
Aml *aml_call2(const char *method, Aml *arg1, Aml *arg2);
Aml *aml_call3(const char *method, Aml *arg1, Aml *arg2, Aml *arg3);
Aml *aml_call4(const char *method, Aml *arg1, Aml *arg2, Aml *arg3, Aml *arg4);
+Aml *aml_gpio_int(AmlConsumerAndProducer con_and_pro,
+ AmlLevelAndEdge edge_level,
+ AmlActiveHighAndLow active_level, AmlShared shared,
+ AmlPinConfig pin_config, uint16_t debounce_timeout,
+ const uint32_t pin_list[], uint32_t pin_count,
+ const char *resource_source_name,
+ const uint8_t *vendor_data, uint16_t vendor_data_len);
Aml *aml_memory32_fixed(uint32_t addr, uint32_t size,
AmlReadAndWrite read_and_write);
Aml *aml_interrupt(AmlConsumerAndProducer con_and_pro,
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 13/25] ARM: ACPI: Add _E03 for Power Button
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 12/25] ACPI: Add aml_gpio_int() wrapper for GPIO Interrupt Connection Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 14/25] ARM: Virt: Add QEMU powerdown notifier and hook it to GPIO Pin 3 Peter Maydell
` (12 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Here GPIO pin 3 is used for Power Button, add _E03 in ACPI DSDT table.
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Wei Huang <wei@redhat.com>
Message-id: 1449804086-3464-9-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt-acpi-build.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index e5dc2d5..1ffff62 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -339,6 +339,20 @@ static void acpi_dsdt_add_gpio(Aml *scope, const MemMapEntry *gpio_memmap,
aml_append(crs, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH,
AML_EXCLUSIVE, &gpio_irq, 1));
aml_append(dev, aml_name_decl("_CRS", crs));
+
+ Aml *aei = aml_resource_template();
+ /* Pin 3 for power button */
+ const uint32_t pin_list[1] = {3};
+ aml_append(aei, aml_gpio_int(AML_CONSUMER, AML_EDGE, AML_ACTIVE_HIGH,
+ AML_EXCLUSIVE, AML_PULL_UP, 0, pin_list, 1,
+ "GPO0", NULL, 0));
+ aml_append(dev, aml_name_decl("_AEI", aei));
+
+ /* _E03 is handle for power button */
+ Aml *method = aml_method("_E03", 0, AML_NOTSERIALIZED);
+ aml_append(method, aml_notify(aml_name(ACPI_POWER_BUTTON_DEVICE),
+ aml_int(0x80)));
+ aml_append(dev, method);
aml_append(scope, dev);
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 14/25] ARM: Virt: Add QEMU powerdown notifier and hook it to GPIO Pin 3
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 13/25] ARM: ACPI: Add _E03 for Power Button Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 15/25] ARM: Virt: Add gpio-keys node for Poweroff using DT Peter Maydell
` (11 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Currently mach-virt model doesn't support powerdown request. Guest VM
doesn't react to system_powerdown from monitor console (or QMP) because
there is no communication mechanism for such requests. This patch registers
GPIO Pin 3 with powerdown notification. So guest VM can receive notification
when such powerdown request is triggered.
Signed-off-by: Wei Huang <wei@redhat.com>
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Reviewed-by: Wei Huang <wei@redhat.com>
Tested-by: Wei Huang <wei@redhat.com>
Message-id: 1449804086-3464-10-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 7977e3c..cb1d45b 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -540,6 +540,17 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
g_free(nodename);
}
+static DeviceState *pl061_dev;
+static void virt_powerdown_req(Notifier *n, void *opaque)
+{
+ /* use gpio Pin 3 for power button event */
+ qemu_set_irq(qdev_get_gpio_in(pl061_dev, 3), 1);
+}
+
+static Notifier virt_system_powerdown_notifier = {
+ .notify = virt_powerdown_req
+};
+
static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
{
char *nodename;
@@ -548,7 +559,7 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
int irq = vbi->irqmap[VIRT_GPIO];
const char compat[] = "arm,pl061\0arm,primecell";
- sysbus_create_simple("pl061", base, pic[irq]);
+ pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
qemu_fdt_add_subnode(vbi->fdt, nodename);
@@ -563,6 +574,9 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
+ /* connect powerdown request */
+ qemu_register_powerdown_notifier(&virt_system_powerdown_notifier);
+
g_free(nodename);
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 15/25] ARM: Virt: Add gpio-keys node for Poweroff using DT
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 14/25] ARM: Virt: Add QEMU powerdown notifier and hook it to GPIO Pin 3 Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 16/25] target-arm: kvm64 - introduce kvm_arm_init_debug() Peter Maydell
` (10 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Shannon Zhao <shannon.zhao@linaro.org>
Add a gpio-keys node. This is used for Poweroff for the systems which
use DT not ACPI.
Signed-off-by: Shannon Zhao <zhaoshenglong@huawei.com>
Signed-off-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Wei Huang <wei@redhat.com>
Message-id: 1449804086-3464-11-git-send-email-zhaoshenglong@huawei.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/virt.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index cb1d45b..bd6781bd 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -52,6 +52,7 @@
#include "kvm_arm.h"
#include "hw/smbios/smbios.h"
#include "qapi/visitor.h"
+#include <linux/input.h>
/* Number of external interrupt lines to configure the GIC with */
#define NUM_IRQS 256
@@ -561,6 +562,7 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
pl061_dev = sysbus_create_simple("pl061", base, pic[irq]);
+ uint32_t phandle = qemu_fdt_alloc_phandle(vbi->fdt);
nodename = g_strdup_printf("/pl061@%" PRIx64, base);
qemu_fdt_add_subnode(vbi->fdt, nodename);
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
@@ -573,6 +575,20 @@ static void create_gpio(const VirtBoardInfo *vbi, qemu_irq *pic)
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop_cell(vbi->fdt, nodename, "clocks", vbi->clock_phandle);
qemu_fdt_setprop_string(vbi->fdt, nodename, "clock-names", "apb_pclk");
+ qemu_fdt_setprop_cell(vbi->fdt, nodename, "phandle", phandle);
+
+ qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys");
+ qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys", "compatible", "gpio-keys");
+ qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#size-cells", 0);
+ qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys", "#address-cells", 1);
+
+ qemu_fdt_add_subnode(vbi->fdt, "/gpio-keys/poweroff");
+ qemu_fdt_setprop_string(vbi->fdt, "/gpio-keys/poweroff",
+ "label", "GPIO Key Poweroff");
+ qemu_fdt_setprop_cell(vbi->fdt, "/gpio-keys/poweroff", "linux,code",
+ KEY_POWER);
+ qemu_fdt_setprop_cells(vbi->fdt, "/gpio-keys/poweroff",
+ "gpios", phandle, 3, 0);
/* connect powerdown request */
qemu_register_powerdown_notifier(&virt_system_powerdown_notifier);
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 16/25] target-arm: kvm64 - introduce kvm_arm_init_debug()
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 15/25] ARM: Virt: Add gpio-keys node for Poweroff using DT Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 17/25] target-arm: kvm - implement software breakpoints Peter Maydell
` (9 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
As we haven't always had guest debug support we need to probe for it.
Additionally we don't do this in the start-up capability code so we
don't fall over on old kernels.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-2-git-send-email-alex.bennee@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/kvm64.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index ceebfeb..d087794 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -25,6 +25,22 @@
#include "internals.h"
#include "hw/arm/arm.h"
+static bool have_guest_debug;
+
+/**
+ * kvm_arm_init_debug()
+ * @cs: CPUState
+ *
+ * Check for guest debug capabilities.
+ *
+ */
+static void kvm_arm_init_debug(CPUState *cs)
+{
+ have_guest_debug = kvm_check_extension(cs->kvm_state,
+ KVM_CAP_SET_GUEST_DEBUG);
+ return;
+}
+
static inline void set_feature(uint64_t *features, int feature)
{
*features |= 1ULL << feature;
@@ -121,6 +137,8 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
cpu->mp_affinity = mpidr & ARM64_AFFINITY_MASK;
+ kvm_arm_init_debug(cs);
+
return kvm_arm_init_cpreg_list(cpu);
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 17/25] target-arm: kvm - implement software breakpoints
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 16/25] target-arm: kvm64 - introduce kvm_arm_init_debug() Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 18/25] target-arm: kvm - support for single step Peter Maydell
` (8 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
These don't involve messing around with debug registers, just setting
the breakpoint instruction in memory. GDB will not use this mechanism if
it can't access the memory to write the breakpoint.
All the kernel has to do is ensure the hypervisor traps the breakpoint
exceptions and returns to userspace.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-3-git-send-email-alex.bennee@linaro.org
[PMM: Fixed typo in comment]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/kvm.c | 39 +++++++++++++++++-----------
target-arm/kvm32.c | 18 +++++++++++++
target-arm/kvm64.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++
target-arm/kvm_arm.h | 9 +++++++
4 files changed, 123 insertions(+), 15 deletions(-)
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 79ef4c6..7f44e22 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -17,6 +17,7 @@
#include "qemu-common.h"
#include "qemu/timer.h"
+#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
@@ -516,9 +517,23 @@ MemTxAttrs kvm_arch_post_run(CPUState *cs, struct kvm_run *run)
return MEMTXATTRS_UNSPECIFIED;
}
+
int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
{
- return 0;
+ int ret = 0;
+
+ switch (run->exit_reason) {
+ case KVM_EXIT_DEBUG:
+ if (kvm_arm_handle_debug(cs, &run->debug.arch)) {
+ ret = EXCP_DEBUG;
+ } /* otherwise return to guest */
+ break;
+ default:
+ qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n",
+ __func__, run->exit_reason);
+ break;
+ }
+ return ret;
}
bool kvm_arch_stop_on_emulation_error(CPUState *cs)
@@ -541,16 +556,16 @@ int kvm_arch_on_sigbus(int code, void *addr)
return 1;
}
+/* The #ifdef protections are until 32bit headers are imported and can
+ * be removed once both 32 and 64 bit reach feature parity.
+ */
void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
-}
-
-int kvm_arch_insert_sw_breakpoint(CPUState *cs,
- struct kvm_sw_breakpoint *bp)
-{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
- return -EINVAL;
+#ifdef KVM_GUESTDBG_USE_SW_BP
+ if (kvm_sw_breakpoints_active(cs)) {
+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
+ }
+#endif
}
int kvm_arch_insert_hw_breakpoint(target_ulong addr,
@@ -567,12 +582,6 @@ int kvm_arch_remove_hw_breakpoint(target_ulong addr,
return -EINVAL;
}
-int kvm_arch_remove_sw_breakpoint(CPUState *cs,
- struct kvm_sw_breakpoint *bp)
-{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
- return -EINVAL;
-}
void kvm_arch_remove_all_hw_breakpoints(void)
{
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index df1e2b0..5ce969f 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -475,3 +475,21 @@ int kvm_arch_get_registers(CPUState *cs)
return 0;
}
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: guest debug not yet implemented\n", __func__);
+ return -EINVAL;
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: guest debug not yet implemented\n", __func__);
+ return -EINVAL;
+}
+
+bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: guest debug not yet implemented\n", __func__);
+ return false;
+}
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index d087794..3b3929d 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -18,6 +18,7 @@
#include "config-host.h"
#include "qemu-common.h"
#include "qemu/timer.h"
+#include "qemu/error-report.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
@@ -481,3 +482,74 @@ int kvm_arch_get_registers(CPUState *cs)
/* TODO: other registers */
return ret;
}
+
+/* C6.6.29 BRK instruction */
+static const uint32_t brk_insn = 0xd4200000;
+
+int kvm_arch_insert_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+ if (have_guest_debug) {
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 0) ||
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk_insn, 4, 1)) {
+ return -EINVAL;
+ }
+ return 0;
+ } else {
+ error_report("guest debug not supported on this kernel");
+ return -EINVAL;
+ }
+}
+
+int kvm_arch_remove_sw_breakpoint(CPUState *cs, struct kvm_sw_breakpoint *bp)
+{
+ static uint32_t brk;
+
+ if (have_guest_debug) {
+ if (cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&brk, 4, 0) ||
+ brk != brk_insn ||
+ cpu_memory_rw_debug(cs, bp->pc, (uint8_t *)&bp->saved_insn, 4, 1)) {
+ return -EINVAL;
+ }
+ return 0;
+ } else {
+ error_report("guest debug not supported on this kernel");
+ return -EINVAL;
+ }
+}
+
+/* See v8 ARM ARM D7.2.27 ESR_ELx, Exception Syndrome Register
+ *
+ * To minimise translating between kernel and user-space the kernel
+ * ABI just provides user-space with the full exception syndrome
+ * register value to be decoded in QEMU.
+ */
+
+bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
+{
+ int hsr_ec = debug_exit->hsr >> ARM_EL_EC_SHIFT;
+ ARMCPU *cpu = ARM_CPU(cs);
+ CPUARMState *env = &cpu->env;
+
+ /* Ensure PC is synchronised */
+ kvm_cpu_synchronize_state(cs);
+
+ switch (hsr_ec) {
+ case EC_AA64_BKPT:
+ if (kvm_find_sw_breakpoint(cs, env->pc)) {
+ return true;
+ }
+ break;
+ default:
+ error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
+ __func__, debug_exit->hsr, env->pc);
+ }
+
+ /* If we don't handle this it could be it really is for the
+ guest to handle */
+ qemu_log_mask(LOG_UNIMP,
+ "%s: re-injecting exception not yet implemented"
+ " (0x%"PRIx32", %"PRIx64")\n",
+ __func__, hsr_ec, env->pc);
+
+ return false;
+}
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
index b516041..fde5d30 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -215,4 +215,13 @@ static inline const char *gic_class_name(void)
*/
const char *gicv3_class_name(void);
+/**
+ * kvm_arm_handle_debug:
+ * @cs: CPUState
+ * @debug_exit: debug part of the KVM exit structure
+ *
+ * Returns: TRUE if the debug exception was handled.
+ */
+bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit);
+
#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 18/25] target-arm: kvm - support for single step
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 17/25] target-arm: kvm - implement software breakpoints Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 19/25] target-arm: kvm - add support for HW assisted debug Peter Maydell
` (7 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
This adds support for single-step. There isn't much to do on the QEMU
side as after we set-up the request for single step via the debug ioctl
it is all handled within the kernel.
The actual setting of the KVM_GUESTDBG_SINGLESTEP flag is already in the
common code. If the kernel doesn't support guest debug the ioctl will
simply error.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-4-git-send-email-alex.bennee@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/kvm64.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 3b3929d..5f96cde 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -534,6 +534,13 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
kvm_cpu_synchronize_state(cs);
switch (hsr_ec) {
+ case EC_SOFTWARESTEP:
+ if (cs->singlestep_enabled) {
+ return true;
+ } else {
+ error_report("Came out of SINGLE STEP when not enabled");
+ }
+ break;
case EC_AA64_BKPT:
if (kvm_find_sw_breakpoint(cs, env->pc)) {
return true;
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 19/25] target-arm: kvm - add support for HW assisted debug
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 18/25] target-arm: kvm - support for single step Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 20/25] target-arm: kvm - re-inject guest debug exceptions Peter Maydell
` (6 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
This adds basic support for HW assisted debug. The ioctl interface to
KVM allows us to pass an implementation defined number of break and
watch point registers. When KVM_GUESTDBG_USE_HW is specified these
debug registers will be installed in place on the world switch into the
guest.
The hardware is actually capable of more advanced matching but it is
unclear if this expressiveness is available via the gdbstub protocol.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-5-git-send-email-alex.bennee@linaro.org
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/kvm.c | 26 +---
target-arm/kvm32.c | 29 +++++
target-arm/kvm64.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++-
target-arm/kvm_arm.h | 21 +++
4 files changed, 415 insertions(+), 22 deletions(-)
diff --git a/target-arm/kvm.c b/target-arm/kvm.c
index 7f44e22..84974bb 100644
--- a/target-arm/kvm.c
+++ b/target-arm/kvm.c
@@ -566,26 +566,12 @@ void kvm_arch_update_guest_debug(CPUState *cs, struct kvm_guest_debug *dbg)
dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP;
}
#endif
-}
-
-int kvm_arch_insert_hw_breakpoint(target_ulong addr,
- target_ulong len, int type)
-{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
- return -EINVAL;
-}
-
-int kvm_arch_remove_hw_breakpoint(target_ulong addr,
- target_ulong len, int type)
-{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
- return -EINVAL;
-}
-
-
-void kvm_arch_remove_all_hw_breakpoints(void)
-{
- qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+#ifdef KVM_GUESTDBG_USE_HW
+ if (kvm_arm_hw_debug_active(cs)) {
+ dbg->control |= KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_HW;
+ kvm_arm_copy_hw_debug_data(&dbg->arch);
+ }
+#endif
}
void kvm_arch_init_irq_routing(KVMState *s)
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index 5ce969f..ff83ce6 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -493,3 +493,32 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
qemu_log_mask(LOG_UNIMP, "%s: guest debug not yet implemented\n", __func__);
return false;
}
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+ return -EINVAL;
+}
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+}
+
+void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr)
+{
+ qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+}
+
+bool kvm_arm_hw_debug_active(CPUState *cs)
+{
+ return false;
+}
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 5f96cde..771ecdb 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -2,6 +2,7 @@
* ARM implementation of KVM hooks, 64 bit specific code
*
* Copyright Mian-M. Hamayun 2013, Virtual Open Systems
+ * Copyright Alex Bennée 2014, Linaro
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -12,13 +13,17 @@
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <linux/elf.h>
#include <linux/kvm.h>
#include "config-host.h"
#include "qemu-common.h"
#include "qemu/timer.h"
#include "qemu/error-report.h"
+#include "qemu/host-utils.h"
+#include "exec/gdbstub.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
#include "kvm_arm.h"
@@ -28,20 +33,358 @@
static bool have_guest_debug;
+/*
+ * Although the ARM implementation of hardware assisted debugging
+ * allows for different breakpoints per-core, the current GDB
+ * interface treats them as a global pool of registers (which seems to
+ * be the case for x86, ppc and s390). As a result we store one copy
+ * of registers which is used for all active cores.
+ *
+ * Write access is serialised by virtue of the GDB protocol which
+ * updates things. Read access (i.e. when the values are copied to the
+ * vCPU) is also gated by GDB's run control.
+ *
+ * This is not unreasonable as most of the time debugging kernels you
+ * never know which core will eventually execute your function.
+ */
+
+typedef struct {
+ uint64_t bcr;
+ uint64_t bvr;
+} HWBreakpoint;
+
+/* The watchpoint registers can cover more area than the requested
+ * watchpoint so we need to store the additional information
+ * somewhere. We also need to supply a CPUWatchpoint to the GDB stub
+ * when the watchpoint is hit.
+ */
+typedef struct {
+ uint64_t wcr;
+ uint64_t wvr;
+ CPUWatchpoint details;
+} HWWatchpoint;
+
+/* Maximum and current break/watch point counts */
+int max_hw_bps, max_hw_wps;
+GArray *hw_breakpoints, *hw_watchpoints;
+
+#define cur_hw_wps (hw_watchpoints->len)
+#define cur_hw_bps (hw_breakpoints->len)
+#define get_hw_bp(i) (&g_array_index(hw_breakpoints, HWBreakpoint, i))
+#define get_hw_wp(i) (&g_array_index(hw_watchpoints, HWWatchpoint, i))
+
/**
- * kvm_arm_init_debug()
+ * kvm_arm_init_debug() - check for guest debug capabilities
* @cs: CPUState
*
- * Check for guest debug capabilities.
+ * kvm_check_extension returns the number of debug registers we have
+ * or 0 if we have none.
*
*/
static void kvm_arm_init_debug(CPUState *cs)
{
have_guest_debug = kvm_check_extension(cs->kvm_state,
KVM_CAP_SET_GUEST_DEBUG);
+
+ max_hw_wps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_WPS);
+ hw_watchpoints = g_array_sized_new(true, true,
+ sizeof(HWWatchpoint), max_hw_wps);
+
+ max_hw_bps = kvm_check_extension(cs->kvm_state, KVM_CAP_GUEST_DEBUG_HW_BPS);
+ hw_breakpoints = g_array_sized_new(true, true,
+ sizeof(HWBreakpoint), max_hw_bps);
return;
}
+/**
+ * insert_hw_breakpoint()
+ * @addr: address of breakpoint
+ *
+ * See ARM ARM D2.9.1 for details but here we are only going to create
+ * simple un-linked breakpoints (i.e. we don't chain breakpoints
+ * together to match address and context or vmid). The hardware is
+ * capable of fancier matching but that will require exposing that
+ * fanciness to GDB's interface
+ *
+ * D7.3.2 DBGBCR<n>_EL1, Debug Breakpoint Control Registers
+ *
+ * 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ * | RES0 | BT | LBN | SSC | HMC| RES0 | BAS | RES0 | PMC | E |
+ * +------+------+-------+-----+----+------+-----+------+-----+---+
+ *
+ * BT: Breakpoint type (0 = unlinked address match)
+ * LBN: Linked BP number (0 = unused)
+ * SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
+ * BAS: Byte Address Select (RES1 for AArch64)
+ * E: Enable bit
+ */
+static int insert_hw_breakpoint(target_ulong addr)
+{
+ HWBreakpoint brk = {
+ .bcr = 0x1, /* BCR E=1, enable */
+ .bvr = addr
+ };
+
+ if (cur_hw_bps >= max_hw_bps) {
+ return -ENOBUFS;
+ }
+
+ brk.bcr = deposit32(brk.bcr, 1, 2, 0x3); /* PMC = 11 */
+ brk.bcr = deposit32(brk.bcr, 5, 4, 0xf); /* BAS = RES1 */
+
+ g_array_append_val(hw_breakpoints, brk);
+
+ return 0;
+}
+
+/**
+ * delete_hw_breakpoint()
+ * @pc: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_breakpoint(target_ulong pc)
+{
+ int i;
+ for (i = 0; i < hw_breakpoints->len; i++) {
+ HWBreakpoint *brk = get_hw_bp(i);
+ if (brk->bvr == pc) {
+ g_array_remove_index(hw_breakpoints, i);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * insert_hw_watchpoint()
+ * @addr: address of watch point
+ * @len: size of area
+ * @type: type of watch point
+ *
+ * See ARM ARM D2.10. As with the breakpoints we can do some advanced
+ * stuff if we want to. The watch points can be linked with the break
+ * points above to make them context aware. However for simplicity
+ * currently we only deal with simple read/write watch points.
+ *
+ * D7.3.11 DBGWCR<n>_EL1, Debug Watchpoint Control Registers
+ *
+ * 31 29 28 24 23 21 20 19 16 15 14 13 12 5 4 3 2 1 0
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ * | RES0 | MASK | RES0 | WT | LBN | SSC | HMC | BAS | LSC | PAC | E |
+ * +------+-------+------+----+-----+-----+-----+-----+-----+-----+---+
+ *
+ * MASK: num bits addr mask (0=none,01/10=res,11=3 bits (8 bytes))
+ * WT: 0 - unlinked, 1 - linked (not currently used)
+ * LBN: Linked BP number (not currently used)
+ * SSC/HMC/PAC: Security, Higher and Priv access control (Table D2-11)
+ * BAS: Byte Address Select
+ * LSC: Load/Store control (01: load, 10: store, 11: both)
+ * E: Enable
+ *
+ * The bottom 2 bits of the value register are masked. Therefore to
+ * break on any sizes smaller than an unaligned word you need to set
+ * MASK=0, BAS=bit per byte in question. For larger regions (^2) you
+ * need to ensure you mask the address as required and set BAS=0xff
+ */
+
+static int insert_hw_watchpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ HWWatchpoint wp = {
+ .wcr = 1, /* E=1, enable */
+ .wvr = addr & (~0x7ULL),
+ .details = { .vaddr = addr, .len = len }
+ };
+
+ if (cur_hw_wps >= max_hw_wps) {
+ return -ENOBUFS;
+ }
+
+ /*
+ * HMC=0 SSC=0 PAC=3 will hit EL0 or EL1, any security state,
+ * valid whether EL3 is implemented or not
+ */
+ wp.wcr = deposit32(wp.wcr, 1, 2, 3);
+
+ switch (type) {
+ case GDB_WATCHPOINT_READ:
+ wp.wcr = deposit32(wp.wcr, 3, 2, 1);
+ wp.details.flags = BP_MEM_READ;
+ break;
+ case GDB_WATCHPOINT_WRITE:
+ wp.wcr = deposit32(wp.wcr, 3, 2, 2);
+ wp.details.flags = BP_MEM_WRITE;
+ break;
+ case GDB_WATCHPOINT_ACCESS:
+ wp.wcr = deposit32(wp.wcr, 3, 2, 3);
+ wp.details.flags = BP_MEM_ACCESS;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ if (len <= 8) {
+ /* we align the address and set the bits in BAS */
+ int off = addr & 0x7;
+ int bas = (1 << len) - 1;
+
+ wp.wcr = deposit32(wp.wcr, 5 + off, 8 - off, bas);
+ } else {
+ /* For ranges above 8 bytes we need to be a power of 2 */
+ if (is_power_of_2(len)) {
+ int bits = ctz64(len);
+
+ wp.wvr &= ~((1 << bits) - 1);
+ wp.wcr = deposit32(wp.wcr, 24, 4, bits);
+ wp.wcr = deposit32(wp.wcr, 5, 8, 0xff);
+ } else {
+ return -ENOBUFS;
+ }
+ }
+
+ g_array_append_val(hw_watchpoints, wp);
+ return 0;
+}
+
+
+static bool check_watchpoint_in_range(int i, target_ulong addr)
+{
+ HWWatchpoint *wp = get_hw_wp(i);
+ uint64_t addr_top, addr_bottom = wp->wvr;
+ int bas = extract32(wp->wcr, 5, 8);
+ int mask = extract32(wp->wcr, 24, 4);
+
+ if (mask) {
+ addr_top = addr_bottom + (1 << mask);
+ } else {
+ /* BAS must be contiguous but can offset against the base
+ * address in DBGWVR */
+ addr_bottom = addr_bottom + ctz32(bas);
+ addr_top = addr_bottom + clo32(bas);
+ }
+
+ if (addr >= addr_bottom && addr <= addr_top) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * delete_hw_watchpoint()
+ * @addr: address of breakpoint
+ *
+ * Delete a breakpoint and shuffle any above down
+ */
+
+static int delete_hw_watchpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ int i;
+ for (i = 0; i < cur_hw_wps; i++) {
+ if (check_watchpoint_in_range(i, addr)) {
+ g_array_remove_index(hw_watchpoints, i);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+
+int kvm_arch_insert_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ switch (type) {
+ case GDB_BREAKPOINT_HW:
+ return insert_hw_breakpoint(addr);
+ break;
+ case GDB_WATCHPOINT_READ:
+ case GDB_WATCHPOINT_WRITE:
+ case GDB_WATCHPOINT_ACCESS:
+ return insert_hw_watchpoint(addr, len, type);
+ default:
+ return -ENOSYS;
+ }
+}
+
+int kvm_arch_remove_hw_breakpoint(target_ulong addr,
+ target_ulong len, int type)
+{
+ switch (type) {
+ case GDB_BREAKPOINT_HW:
+ return delete_hw_breakpoint(addr);
+ break;
+ case GDB_WATCHPOINT_READ:
+ case GDB_WATCHPOINT_WRITE:
+ case GDB_WATCHPOINT_ACCESS:
+ return delete_hw_watchpoint(addr, len, type);
+ default:
+ return -ENOSYS;
+ }
+}
+
+
+void kvm_arch_remove_all_hw_breakpoints(void)
+{
+ if (cur_hw_wps > 0) {
+ g_array_remove_range(hw_watchpoints, 0, cur_hw_wps);
+ }
+ if (cur_hw_bps > 0) {
+ g_array_remove_range(hw_breakpoints, 0, cur_hw_bps);
+ }
+}
+
+void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr)
+{
+ int i;
+ memset(ptr, 0, sizeof(struct kvm_guest_debug_arch));
+
+ for (i = 0; i < max_hw_wps; i++) {
+ HWWatchpoint *wp = get_hw_wp(i);
+ ptr->dbg_wcr[i] = wp->wcr;
+ ptr->dbg_wvr[i] = wp->wvr;
+ }
+ for (i = 0; i < max_hw_bps; i++) {
+ HWBreakpoint *bp = get_hw_bp(i);
+ ptr->dbg_bcr[i] = bp->bcr;
+ ptr->dbg_bvr[i] = bp->bvr;
+ }
+}
+
+bool kvm_arm_hw_debug_active(CPUState *cs)
+{
+ return ((cur_hw_wps > 0) || (cur_hw_bps > 0));
+}
+
+static bool find_hw_breakpoint(CPUState *cpu, target_ulong pc)
+{
+ int i;
+
+ for (i = 0; i < cur_hw_bps; i++) {
+ HWBreakpoint *bp = get_hw_bp(i);
+ if (bp->bvr == pc) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
+{
+ int i;
+
+ for (i = 0; i < cur_hw_wps; i++) {
+ if (check_watchpoint_in_range(i, addr)) {
+ return &get_hw_wp(i)->details;
+ }
+ }
+ return NULL;
+}
+
+
static inline void set_feature(uint64_t *features, int feature)
{
*features |= 1ULL << feature;
@@ -546,6 +889,20 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
return true;
}
break;
+ case EC_BREAKPOINT:
+ if (find_hw_breakpoint(cs, env->pc)) {
+ return true;
+ }
+ break;
+ case EC_WATCHPOINT:
+ {
+ CPUWatchpoint *wp = find_hw_watchpoint(cs, debug_exit->far);
+ if (wp) {
+ cs->watchpoint_hit = wp;
+ return true;
+ }
+ break;
+ }
default:
error_report("%s: unhandled debug exit (%"PRIx32", %"PRIx64")\n",
__func__, debug_exit->hsr, env->pc);
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
index fde5d30..07f0c72 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -224,4 +224,25 @@ const char *gicv3_class_name(void);
*/
bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit);
+/**
+ * kvm_arm_hw_debug_active:
+ * @cs: CPU State
+ *
+ * Return: TRUE if any hardware breakpoints in use.
+ */
+
+bool kvm_arm_hw_debug_active(CPUState *cs);
+
+/**
+ * kvm_arm_copy_hw_debug_data:
+ *
+ * @ptr: kvm_guest_debug_arch structure
+ *
+ * Copy the architecture specific debug registers into the
+ * kvm_guest_debug ioctl structure.
+ */
+struct kvm_guest_debug_arch;
+
+void kvm_arm_copy_hw_debug_data(struct kvm_guest_debug_arch *ptr);
+
#endif
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 20/25] target-arm: kvm - re-inject guest debug exceptions
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 19/25] target-arm: kvm - add support for HW assisted debug Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 21/25] tests/guest-debug: introduce basic gdbstub tests Peter Maydell
` (5 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
If we can't find details for the debug exception in our debug state
then we can assume the exception is due to debugging inside the guest.
To inject the exception into the guest state we re-use the TCG exception
code (do_interrupt).
However while guest debugging is in effect we currently can't handle the
guest using single step as we will keep trapping to back to userspace.
GDB makes heavy use of single-step behind the scenes which effectively
means the guest's ability to debug itself is disabled while it is being
debugged.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-6-git-send-email-alex.bennee@linaro.org
[PMM: Fixed a few typos in comments and commit message]
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
target-arm/helper-a64.c | 12 ++++++++++--
target-arm/kvm64.c | 24 +++++++++++++++++-------
2 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index deb8dbe..fc3ccdf 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -25,6 +25,7 @@
#include "qemu/bitops.h"
#include "internals.h"
#include "qemu/crc32c.h"
+#include "sysemu/kvm.h"
#include <zlib.h> /* For crc32 */
/* C2.4.7 Multiply and divide */
@@ -469,7 +470,8 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
- qemu_log_mask(CPU_LOG_INT, "...with ESR 0x%" PRIx32 "\n",
+ qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
+ env->exception.syndrome >> ARM_EL_EC_SHIFT,
env->exception.syndrome);
}
@@ -535,6 +537,12 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
aarch64_restore_sp(env, new_el);
env->pc = addr;
- cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+
+ qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
+ new_el, env->pc, pstate_read(env));
+
+ if (!kvm_enabled()) {
+ cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
+ }
}
#endif
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 771ecdb..bb9531f 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -871,6 +871,7 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
{
int hsr_ec = debug_exit->hsr >> ARM_EL_EC_SHIFT;
ARMCPU *cpu = ARM_CPU(cs);
+ CPUClass *cc = CPU_GET_CLASS(cs);
CPUARMState *env = &cpu->env;
/* Ensure PC is synchronised */
@@ -881,7 +882,14 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
if (cs->singlestep_enabled) {
return true;
} else {
- error_report("Came out of SINGLE STEP when not enabled");
+ /*
+ * The kernel should have suppressed the guest's ability to
+ * single step at this point so something has gone wrong.
+ */
+ error_report("%s: guest single-step while debugging unsupported"
+ " (%"PRIx64", %"PRIx32")\n",
+ __func__, env->pc, debug_exit->hsr);
+ return false;
}
break;
case EC_AA64_BKPT:
@@ -908,12 +916,14 @@ bool kvm_arm_handle_debug(CPUState *cs, struct kvm_debug_exit_arch *debug_exit)
__func__, debug_exit->hsr, env->pc);
}
- /* If we don't handle this it could be it really is for the
- guest to handle */
- qemu_log_mask(LOG_UNIMP,
- "%s: re-injecting exception not yet implemented"
- " (0x%"PRIx32", %"PRIx64")\n",
- __func__, hsr_ec, env->pc);
+ /* If we are not handling the debug exception it must belong to
+ * the guest. Let's re-use the existing TCG interrupt code to set
+ * everything up properly.
+ */
+ cs->exception_index = EXCP_BKPT;
+ env->exception.syndrome = debug_exit->hsr;
+ env->exception.vaddress = debug_exit->far;
+ cc->do_interrupt(cs);
return false;
}
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 21/25] tests/guest-debug: introduce basic gdbstub tests
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 20/25] target-arm: kvm - re-inject guest debug exceptions Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 22/25] i.MX: Fix i.MX31 default/reset configuration Peter Maydell
` (4 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Alex Bennée <alex.bennee@linaro.org>
The aim of these tests is to combine with an appropriate kernel
image (with symbol-file vmlinux) and check it behaves as it should.
Given a kernel it checks:
- single step
- software breakpoint
- hardware breakpoint
- access, read and write watchpoints
On success it returns 0 to the calling process.
I've not plumbed this into the "make check" logic though as we need a
solution for providing non-host binaries to the tests. However the test
is structured to work with pretty much any Linux kernel image as it
uses the basic kernel_init code which is common across architectures.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 1449599553-24713-7-git-send-email-alex.bennee@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
tests/guest-debug/test-gdbstub.py | 176 ++++++++++++++++++++++++++++++++++++++
1 file changed, 176 insertions(+)
create mode 100644 tests/guest-debug/test-gdbstub.py
diff --git a/tests/guest-debug/test-gdbstub.py b/tests/guest-debug/test-gdbstub.py
new file mode 100644
index 0000000..31ba6c9
--- /dev/null
+++ b/tests/guest-debug/test-gdbstub.py
@@ -0,0 +1,176 @@
+#
+# This script needs to be run on startup
+# qemu -kernel ${KERNEL} -s -S
+# and then:
+# gdb ${KERNEL}.vmlinux -x ${QEMU_SRC}/tests/guest-debug/test-gdbstub.py
+
+import gdb
+
+failcount = 0
+
+
+def report(cond, msg):
+ "Report success/fail of test"
+ if cond:
+ print ("PASS: %s" % (msg))
+ else:
+ print ("FAIL: %s" % (msg))
+ failcount += 1
+
+
+def check_step():
+ "Step an instruction, check it moved."
+ start_pc = gdb.parse_and_eval('$pc')
+ gdb.execute("si")
+ end_pc = gdb.parse_and_eval('$pc')
+
+ return not (start_pc == end_pc)
+
+
+def check_break(sym_name):
+ "Setup breakpoint, continue and check we stopped."
+ sym, ok = gdb.lookup_symbol(sym_name)
+ bp = gdb.Breakpoint(sym_name)
+
+ gdb.execute("c")
+
+ # hopefully we came back
+ end_pc = gdb.parse_and_eval('$pc')
+ print ("%s == %s %d" % (end_pc, sym.value(), bp.hit_count))
+ bp.delete()
+
+ # can we test we hit bp?
+ return end_pc == sym.value()
+
+
+# We need to do hbreak manually as the python interface doesn't export it
+def check_hbreak(sym_name):
+ "Setup hardware breakpoint, continue and check we stopped."
+ sym, ok = gdb.lookup_symbol(sym_name)
+ gdb.execute("hbreak %s" % (sym_name))
+ gdb.execute("c")
+
+ # hopefully we came back
+ end_pc = gdb.parse_and_eval('$pc')
+ print ("%s == %s" % (end_pc, sym.value()))
+
+ if end_pc == sym.value():
+ gdb.execute("d 1")
+ return True
+ else:
+ return False
+
+
+class WatchPoint(gdb.Breakpoint):
+
+ def get_wpstr(self, sym_name):
+ "Setup sym and wp_str for given symbol."
+ self.sym, ok = gdb.lookup_symbol(sym_name)
+ wp_addr = gdb.parse_and_eval(sym_name).address
+ self.wp_str = '*(%(type)s)(&%(address)s)' % dict(
+ type = wp_addr.type, address = sym_name)
+
+ return(self.wp_str)
+
+ def __init__(self, sym_name, type):
+ wp_str = self.get_wpstr(sym_name)
+ super(WatchPoint, self).__init__(wp_str, gdb.BP_WATCHPOINT, type)
+
+ def stop(self):
+ end_pc = gdb.parse_and_eval('$pc')
+ print ("HIT WP @ %s" % (end_pc))
+ return True
+
+
+def do_one_watch(sym, wtype, text):
+
+ wp = WatchPoint(sym, wtype)
+ gdb.execute("c")
+ report_str = "%s for %s (%s)" % (text, sym, wp.sym.value())
+
+ if wp.hit_count > 0:
+ report(True, report_str)
+ wp.delete()
+ else:
+ report(False, report_str)
+
+
+def check_watches(sym_name):
+ "Watch a symbol for any access."
+
+ # Should hit for any read
+ do_one_watch(sym_name, gdb.WP_ACCESS, "awatch")
+
+ # Again should hit for reads
+ do_one_watch(sym_name, gdb.WP_READ, "rwatch")
+
+ # Finally when it is written
+ do_one_watch(sym_name, gdb.WP_WRITE, "watch")
+
+
+class CatchBreakpoint(gdb.Breakpoint):
+ def __init__(self, sym_name):
+ super(CatchBreakpoint, self).__init__(sym_name)
+ self.sym, ok = gdb.lookup_symbol(sym_name)
+
+ def stop(self):
+ end_pc = gdb.parse_and_eval('$pc')
+ print ("CB: %s == %s" % (end_pc, self.sym.value()))
+ if end_pc == self.sym.value():
+ report(False, "Hit final catchpoint")
+
+
+def run_test():
+ "Run throught the tests one by one"
+
+ print ("Checking we can step the first few instructions")
+ step_ok = 0
+ for i in range(3):
+ if check_step():
+ step_ok += 1
+
+ report(step_ok == 3, "single step in boot code")
+
+ print ("Checking HW breakpoint works")
+ break_ok = check_hbreak("kernel_init")
+ report(break_ok, "hbreak @ kernel_init")
+
+ # Can't set this up until we are in the kernel proper
+ # if we make it to run_init_process we've over-run and
+ # one of the tests failed
+ print ("Setup catch-all for run_init_process")
+ cbp = CatchBreakpoint("run_init_process")
+ cpb2 = CatchBreakpoint("try_to_run_init_process")
+
+ print ("Checking Normal breakpoint works")
+ break_ok = check_break("wait_for_completion")
+ report(break_ok, "break @ wait_for_completion")
+
+ print ("Checking watchpoint works")
+ check_watches("system_state")
+
+#
+# This runs as the script it sourced (via -x)
+#
+
+try:
+ print ("Connecting to remote")
+ gdb.execute("target remote localhost:1234")
+
+ # These are not very useful in scripts
+ gdb.execute("set pagination off")
+ gdb.execute("set confirm off")
+
+ # Run the actual tests
+ run_test()
+
+except:
+ print ("GDB Exception: %s" % (sys.exc_info()[0]))
+ failcount += 1
+ import code
+ code.InteractiveConsole(locals=globals()).interact()
+ raise
+
+# Finally kill the inferior and exit gdb with a count of failures
+gdb.execute("kill")
+exit(failcount)
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 22/25] i.MX: Fix i.MX31 default/reset configuration
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 21/25] tests/guest-debug: introduce basic gdbstub tests Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 23/25] i.MX: rename i.MX CCM get_clock() function and CLK ID enum names Peter Maydell
` (3 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Jean-Christophe Dubois <jcd@tribudubois.net>
Linux on i.MX31/KZM is expecting the CCM to use the CKIH ref clock
instead of the CKIL plus the FPM multiplier.
We change the CCMR reg reset value to match linux expected config.
This allows the CCM to provide a 39MHz clk (as expected by linux)
instead of the actual 50MHz.
With this change the "sleep 60" command on linux is time accurate
with "real world time".
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Message-id: 6dc5bc4e0a450b20cecdb2991112e7281b653345.1449528242.git.jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/misc/imx_ccm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
index 4cc2bbc..500dda5 100644
--- a/hw/misc/imx_ccm.c
+++ b/hw/misc/imx_ccm.c
@@ -123,7 +123,7 @@ static void imx_ccm_reset(DeviceState *dev)
{
IMXCCMState *s = IMX_CCM(dev);
- s->ccmr = 0x074b0b7b;
+ s->ccmr = 0x074b0b7d;
s->pdr0 = 0xff870b48;
s->pdr1 = 0x49fcfe7f;
s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 23/25] i.MX: rename i.MX CCM get_clock() function and CLK ID enum names
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (21 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 22/25] i.MX: Fix i.MX31 default/reset configuration Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 24/25] i.MX: Split the CCM class into an abstract base class and a concrete class Peter Maydell
` (2 subsequent siblings)
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Jean-Christophe Dubois <jcd@tribudubois.net>
This is to prepare for CCM code refactoring.
This is just a bit of function and enum values renaming.
We also remove some useless intermediate variables.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Message-id: 53c4d9b9611988a5f56f178f285e04490747925e.1449528242.git.jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/misc/imx_ccm.c | 8 ++++----
hw/timer/imx_epit.c | 20 +++++++++-----------
hw/timer/imx_gpt.c | 16 ++++++++--------
include/hw/misc/imx_ccm.h | 8 ++++----
4 files changed, 25 insertions(+), 27 deletions(-)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
index 500dda5..1ac697a 100644
--- a/hw/misc/imx_ccm.c
+++ b/hw/misc/imx_ccm.c
@@ -49,18 +49,18 @@ static const VMStateDescription vmstate_imx_ccm = {
.post_load = imx_ccm_post_load,
};
-uint32_t imx_clock_frequency(DeviceState *dev, IMXClk clock)
+uint32_t imx_ccm_get_clock_frequency(DeviceState *dev, IMXClk clock)
{
IMXCCMState *s = IMX_CCM(dev);
switch (clock) {
case NOCLK:
return 0;
- case MCU:
+ case CLK_MCU:
return s->mcu_clk_freq;
- case HSP:
+ case CLK_HSP:
return s->hsp_clk_freq;
- case IPG:
+ case CLK_IPG:
return s->ipg_clk_freq;
case CLK_32k:
return CKIL_FREQ;
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index 967be4a..50bf83c 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -51,9 +51,9 @@ static char const *imx_epit_reg_name(uint32_t reg)
* These are typical.
*/
static const IMXClk imx_epit_clocks[] = {
- 0, /* 00 disabled */
- IPG, /* 01 ipg_clk, ~532MHz */
- IPG, /* 10 ipg_clk_highfreq */
+ NOCLK, /* 00 disabled */
+ CLK_IPG, /* 01 ipg_clk, ~532MHz */
+ CLK_IPG, /* 10 ipg_clk_highfreq */
CLK_32k, /* 11 ipg_clk_32k -- ~32kHz */
};
@@ -73,20 +73,18 @@ static void imx_epit_set_freq(IMXEPITState *s)
{
uint32_t clksrc;
uint32_t prescaler;
- uint32_t freq;
clksrc = extract32(s->cr, CR_CLKSRC_SHIFT, 2);
prescaler = 1 + extract32(s->cr, CR_PRESCALE_SHIFT, 12);
- freq = imx_clock_frequency(s->ccm, imx_epit_clocks[clksrc]) / prescaler;
+ s->freq = imx_ccm_get_clock_frequency(s->ccm,
+ imx_epit_clocks[clksrc]) / prescaler;
- s->freq = freq;
+ DPRINTF("Setting ptimer frequency to %u\n", s->freq);
- DPRINTF("Setting ptimer frequency to %u\n", freq);
-
- if (freq) {
- ptimer_set_freq(s->timer_reload, freq);
- ptimer_set_freq(s->timer_cmp, freq);
+ if (s->freq) {
+ ptimer_set_freq(s->timer_reload, s->freq);
+ ptimer_set_freq(s->timer_cmp, s->freq);
}
}
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 7257f42..b1893b8 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -81,8 +81,8 @@ static const VMStateDescription vmstate_imx_timer_gpt = {
static const IMXClk imx_gpt_clocks[] = {
NOCLK, /* 000 No clock source */
- IPG, /* 001 ipg_clk, 532MHz*/
- IPG, /* 010 ipg_clk_highfreq */
+ CLK_IPG, /* 001 ipg_clk, 532MHz*/
+ CLK_IPG, /* 010 ipg_clk_highfreq */
NOCLK, /* 011 not defined */
CLK_32k, /* 100 ipg_clk_32k */
NOCLK, /* 101 not defined */
@@ -93,14 +93,14 @@ static const IMXClk imx_gpt_clocks[] = {
static void imx_gpt_set_freq(IMXGPTState *s)
{
uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3);
- uint32_t freq = imx_clock_frequency(s->ccm, imx_gpt_clocks[clksrc])
- / (1 + s->pr);
- s->freq = freq;
- DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, freq);
+ s->freq = imx_ccm_get_clock_frequency(s->ccm,
+ imx_gpt_clocks[clksrc]) / (1 + s->pr);
- if (freq) {
- ptimer_set_freq(s->timer, freq);
+ DPRINTF("Setting clksrc %d to frequency %d\n", clksrc, s->freq);
+
+ if (s->freq) {
+ ptimer_set_freq(s->timer, s->freq);
}
}
diff --git a/include/hw/misc/imx_ccm.h b/include/hw/misc/imx_ccm.h
index 0f2e469..09f6248 100644
--- a/include/hw/misc/imx_ccm.h
+++ b/include/hw/misc/imx_ccm.h
@@ -80,12 +80,12 @@ typedef struct IMXCCMState {
typedef enum {
NOCLK,
- MCU,
- HSP,
- IPG,
+ CLK_MCU,
+ CLK_HSP,
+ CLK_IPG,
CLK_32k
} IMXClk;
-uint32_t imx_clock_frequency(DeviceState *s, IMXClk clock);
+uint32_t imx_ccm_get_clock_frequency(DeviceState *s, IMXClk clock);
#endif /* IMX_CCM_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 24/25] i.MX: Split the CCM class into an abstract base class and a concrete class
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (22 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 23/25] i.MX: rename i.MX CCM get_clock() function and CLK ID enum names Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 11:50 ` [Qemu-devel] [PULL 25/25] i.MX: Add an i.MX25 specific CCM class/instance Peter Maydell
2015-12-17 13:40 ` [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Jean-Christophe Dubois <jcd@tribudubois.net>
The IMX_CCM class is now the base abstract class that is used by EPIT
and GPT timer implementation.
IMX31_CCM class is the concrete class implementing CCM for i.MX31 SOC.
For now the i.MX25 continues to use the i.MX31 CCM implementation.
An i.MX25 specific CCM will be introduced in a later patch.
We also rework initialization to stop using deprecated sysbus device init.
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Reviewed-by: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Message-id: fd3c7f87b50f5ebc99ec91f01413db35017f116d.1449528242.git.jcd@tribudubois.net
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/fsl-imx25.c | 6 +-
hw/arm/fsl-imx31.c | 6 +-
hw/misc/Makefile.objs | 1 +
hw/misc/imx31_ccm.c | 392 ++++++++++++++++++++++++++++++++++++++++++++
hw/misc/imx_ccm.c | 231 +++-----------------------
include/hw/arm/fsl-imx25.h | 4 +-
include/hw/arm/fsl-imx31.h | 4 +-
include/hw/misc/imx31_ccm.h | 66 ++++++++
include/hw/misc/imx_ccm.h | 69 +++-----
include/hw/timer/imx_epit.h | 5 +-
include/hw/timer/imx_gpt.h | 5 +-
11 files changed, 521 insertions(+), 268 deletions(-)
create mode 100644 hw/misc/imx31_ccm.c
create mode 100644 include/hw/misc/imx31_ccm.h
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index e1cadac..9f302ed 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -38,7 +38,7 @@ static void fsl_imx25_init(Object *obj)
object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
- object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
@@ -150,7 +150,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
{ FSL_IMX25_GPT4_ADDR, FSL_IMX25_GPT4_IRQ }
};
- s->gpt[i].ccm = DEVICE(&s->ccm);
+ s->gpt[i].ccm = IMX_CCM(&s->ccm);
object_property_set_bool(OBJECT(&s->gpt[i]), true, "realized", &err);
if (err) {
@@ -173,7 +173,7 @@ static void fsl_imx25_realize(DeviceState *dev, Error **errp)
{ FSL_IMX25_EPIT2_ADDR, FSL_IMX25_EPIT2_IRQ }
};
- s->epit[i].ccm = DEVICE(&s->ccm);
+ s->epit[i].ccm = IMX_CCM(&s->ccm);
object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
if (err) {
diff --git a/hw/arm/fsl-imx31.c b/hw/arm/fsl-imx31.c
index 53d4473..abdea06 100644
--- a/hw/arm/fsl-imx31.c
+++ b/hw/arm/fsl-imx31.c
@@ -35,7 +35,7 @@ static void fsl_imx31_init(Object *obj)
object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
- object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX_CCM);
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
for (i = 0; i < FSL_IMX31_NUM_UARTS; i++) {
@@ -128,7 +128,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
serial_table[i].irq));
}
- s->gpt.ccm = DEVICE(&s->ccm);
+ s->gpt.ccm = IMX_CCM(&s->ccm);
object_property_set_bool(OBJECT(&s->gpt), true, "realized", &err);
if (err) {
@@ -150,7 +150,7 @@ static void fsl_imx31_realize(DeviceState *dev, Error **errp)
{ FSL_IMX31_EPIT2_ADDR, FSL_IMX31_EPIT2_IRQ },
};
- s->epit[i].ccm = DEVICE(&s->ccm);
+ s->epit[i].ccm = IMX_CCM(&s->ccm);
object_property_set_bool(OBJECT(&s->epit[i]), true, "realized", &err);
if (err) {
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index aeb6b7d..c77f3e3 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -26,6 +26,7 @@ obj-$(CONFIG_NSERIES) += cbus.o
obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
obj-$(CONFIG_IMX) += imx_ccm.o
+obj-$(CONFIG_IMX) += imx31_ccm.o
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/imx31_ccm.c b/hw/misc/imx31_ccm.c
new file mode 100644
index 0000000..b92d2e0
--- /dev/null
+++ b/hw/misc/imx31_ccm.c
@@ -0,0 +1,392 @@
+/*
+ * IMX31 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * To get the timer frequencies right, we need to emulate at least part of
+ * the i.MX31 CCM.
+ */
+
+#include "hw/misc/imx31_ccm.h"
+
+#define CKIH_FREQ 26000000 /* 26MHz crystal input */
+
+#ifndef DEBUG_IMX31_CCM
+#define DEBUG_IMX31_CCM 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX31_CCM) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX31_CCM, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+static char const *imx31_ccm_reg_name(uint32_t reg)
+{
+ switch (reg) {
+ case 0:
+ return "CCMR";
+ case 1:
+ return "PDR0";
+ case 2:
+ return "PDR1";
+ case 3:
+ return "RCSR";
+ case 4:
+ return "MPCTL";
+ case 5:
+ return "UPCTL";
+ case 6:
+ return "SPCTL";
+ case 7:
+ return "COSR";
+ case 8:
+ return "CGR0";
+ case 9:
+ return "CGR1";
+ case 10:
+ return "CGR2";
+ case 11:
+ return "WIMR";
+ case 12:
+ return "LDC";
+ case 13:
+ return "DCVR0";
+ case 14:
+ return "DCVR1";
+ case 15:
+ return "DCVR2";
+ case 16:
+ return "DCVR3";
+ case 17:
+ return "LTR0";
+ case 18:
+ return "LTR1";
+ case 19:
+ return "LTR2";
+ case 20:
+ return "LTR3";
+ case 21:
+ return "LTBR0";
+ case 22:
+ return "LTBR1";
+ case 23:
+ return "PMCR0";
+ case 24:
+ return "PMCR1";
+ case 25:
+ return "PDR2";
+ default:
+ return "???";
+ }
+}
+
+static const VMStateDescription vmstate_imx31_ccm = {
+ .name = TYPE_IMX31_CCM,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(ccmr, IMX31CCMState),
+ VMSTATE_UINT32(pdr0, IMX31CCMState),
+ VMSTATE_UINT32(pdr1, IMX31CCMState),
+ VMSTATE_UINT32(mpctl, IMX31CCMState),
+ VMSTATE_UINT32(spctl, IMX31CCMState),
+ VMSTATE_UINT32_ARRAY(cgr, IMX31CCMState, 3),
+ VMSTATE_UINT32(pmcr0, IMX31CCMState),
+ VMSTATE_UINT32(pmcr1, IMX31CCMState),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t imx31_ccm_get_pll_ref_clk(IMXCCMState *dev)
+{
+ uint32_t freq = 0;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ if ((s->ccmr & CCMR_PRCS) == 2) {
+ if (s->ccmr & CCMR_FPME) {
+ freq = CKIL_FREQ;
+ if (s->ccmr & CCMR_FPMF) {
+ freq *= 1024;
+ }
+ }
+ } else {
+ freq = CKIH_FREQ;
+ }
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_mpll_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ freq = imx_ccm_calc_pll(s->mpctl, imx31_ccm_get_pll_ref_clk(dev));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_mcu_main_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
+ freq = imx31_ccm_get_pll_ref_clk(dev);
+ } else {
+ freq = imx31_ccm_get_mpll_clk(dev);
+ }
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_mcu_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, MCU));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_hsp_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, HSP));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_hclk_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ freq = imx31_ccm_get_mcu_main_clk(dev) / (1 + EXTRACT(s->pdr0, MAX));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_ipg_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ freq = imx31_ccm_get_hclk_clk(dev) / (1 + EXTRACT(s->pdr0, IPG));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx31_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
+{
+ uint32_t freq = 0;
+
+ switch (clock) {
+ case NOCLK:
+ break;
+ case CLK_MCU:
+ freq = imx31_ccm_get_mcu_clk(dev);
+ break;
+ case CLK_HSP:
+ freq = imx31_ccm_get_hsp_clk(dev);
+ break;
+ case CLK_IPG:
+ freq = imx31_ccm_get_ipg_clk(dev);
+ break;
+ case CLK_32k:
+ freq = CKIL_FREQ;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
+ TYPE_IMX31_CCM, __func__, clock);
+ break;
+ }
+
+ DPRINTF("Clock = %d) = %d\n", clock, freq);
+
+ return freq;
+}
+
+static void imx31_ccm_reset(DeviceState *dev)
+{
+ IMX31CCMState *s = IMX31_CCM(dev);
+
+ DPRINTF("()\n");
+
+ s->ccmr = 0x074b0b7d;
+ s->pdr0 = 0xff870b48;
+ s->pdr1 = 0x49fcfe7f;
+ s->mpctl = 0x04001800;
+ s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
+ s->spctl = 0x04043001;
+ s->pmcr0 = 0x80209828;
+ s->pmcr1 = 0x00aa0000;
+}
+
+static uint64_t imx31_ccm_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32 value = 0;
+ IMX31CCMState *s = (IMX31CCMState *)opaque;
+
+ switch (offset >> 2) {
+ case 0: /* CCMR */
+ value = s->ccmr;
+ break;
+ case 1:
+ value = s->pdr0;
+ break;
+ case 2:
+ value = s->pdr1;
+ break;
+ case 4:
+ value = s->mpctl;
+ break;
+ case 6:
+ value = s->spctl;
+ break;
+ case 8:
+ value = s->cgr[0];
+ break;
+ case 9:
+ value = s->cgr[1];
+ break;
+ case 10:
+ value = s->cgr[2];
+ break;
+ case 18: /* LTR1 */
+ value = 0x00004040;
+ break;
+ case 23:
+ value = s->pmcr0;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
+ break;
+ }
+
+ DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
+ value);
+
+ return (uint64_t)value;
+}
+
+static void imx31_ccm_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMX31CCMState *s = (IMX31CCMState *)opaque;
+
+ DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx31_ccm_reg_name(offset >> 2),
+ (uint32_t)value);
+
+ switch (offset >> 2) {
+ case 0:
+ s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
+ break;
+ case 1:
+ s->pdr0 = value & 0xff9f3fff;
+ break;
+ case 2:
+ s->pdr1 = value;
+ break;
+ case 4:
+ s->mpctl = value & 0xbfff3fff;
+ break;
+ case 6:
+ s->spctl = value & 0xbfff3fff;
+ break;
+ case 8:
+ s->cgr[0] = value;
+ break;
+ case 9:
+ s->cgr[1] = value;
+ break;
+ case 10:
+ s->cgr[2] = value;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX31_CCM, __func__, offset);
+ break;
+ }
+}
+
+static const struct MemoryRegionOps imx31_ccm_ops = {
+ .read = imx31_ccm_read,
+ .write = imx31_ccm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ /*
+ * Our device would not work correctly if the guest was doing
+ * unaligned access. This might not be a limitation on the real
+ * device but in practice there is no reason for a guest to access
+ * this device unaligned.
+ */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+
+};
+
+static void imx31_ccm_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+ IMX31CCMState *s = IMX31_CCM(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx31_ccm_ops, s,
+ TYPE_IMX31_CCM, 0x1000);
+ sysbus_init_mmio(sd, &s->iomem);
+}
+
+static void imx31_ccm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
+
+ dc->reset = imx31_ccm_reset;
+ dc->vmsd = &vmstate_imx31_ccm;
+ dc->desc = "i.MX31 Clock Control Module";
+
+ ccm->get_clock_frequency = imx31_ccm_get_clock_frequency;
+}
+
+static const TypeInfo imx31_ccm_info = {
+ .name = TYPE_IMX31_CCM,
+ .parent = TYPE_IMX_CCM,
+ .instance_size = sizeof(IMX31CCMState),
+ .instance_init = imx31_ccm_init,
+ .class_init = imx31_ccm_class_init,
+};
+
+static void imx31_ccm_register_types(void)
+{
+ type_register_static(&imx31_ccm_info);
+}
+
+type_init(imx31_ccm_register_types)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
index 1ac697a..0c9740b 100644
--- a/hw/misc/imx_ccm.c
+++ b/hw/misc/imx_ccm.c
@@ -7,15 +7,12 @@
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
- * To get the timer frequencies right, we need to emulate at least part of
- * the CCM.
+ * This is an abstract base class used to get a common interface to
+ * retrieve the CCM frequencies from the various i.MX SOC.
*/
#include "hw/misc/imx_ccm.h"
-#define CKIH_FREQ 26000000 /* 26MHz crystal input */
-#define CKIL_FREQ 32768 /* nominal 32khz clock */
-
#ifndef DEBUG_IMX_CCM
#define DEBUG_IMX_CCM 0
#endif
@@ -28,51 +25,27 @@
} \
} while (0)
-static int imx_ccm_post_load(void *opaque, int version_id);
-
-static const VMStateDescription vmstate_imx_ccm = {
- .name = TYPE_IMX_CCM,
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(ccmr, IMXCCMState),
- VMSTATE_UINT32(pdr0, IMXCCMState),
- VMSTATE_UINT32(pdr1, IMXCCMState),
- VMSTATE_UINT32(mpctl, IMXCCMState),
- VMSTATE_UINT32(spctl, IMXCCMState),
- VMSTATE_UINT32_ARRAY(cgr, IMXCCMState, 3),
- VMSTATE_UINT32(pmcr0, IMXCCMState),
- VMSTATE_UINT32(pmcr1, IMXCCMState),
- VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
- VMSTATE_END_OF_LIST()
- },
- .post_load = imx_ccm_post_load,
-};
-uint32_t imx_ccm_get_clock_frequency(DeviceState *dev, IMXClk clock)
+uint32_t imx_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
{
- IMXCCMState *s = IMX_CCM(dev);
+ uint32_t freq = 0;
+ IMXCCMClass *klass = IMX_GET_CLASS(dev);
- switch (clock) {
- case NOCLK:
- return 0;
- case CLK_MCU:
- return s->mcu_clk_freq;
- case CLK_HSP:
- return s->hsp_clk_freq;
- case CLK_IPG:
- return s->ipg_clk_freq;
- case CLK_32k:
- return CKIL_FREQ;
+ if (klass->get_clock_frequency) {
+ freq = klass->get_clock_frequency(dev, clock);
}
- return 0;
+
+ DPRINTF("(clock = %d) = %d\n", clock, freq);
+
+ return freq;
}
/*
* Calculate PLL output frequency
*/
-static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
+uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq)
{
+ int32_t freq;
int32_t mfn = MFN(pllreg); /* Numerator */
uint32_t mfi = MFI(pllreg); /* Integer part */
uint32_t mfd = 1 + MFD(pllreg); /* Denominator */
@@ -81,186 +54,26 @@ static uint32_t calc_pll(uint32_t pllreg, uint32_t base_freq)
if (mfi < 5) {
mfi = 5;
}
+
/* mfn is 10-bit signed twos-complement */
mfn <<= 32 - 10;
mfn >>= 32 - 10;
- return ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
+ freq = ((2 * (base_freq >> 10) * (mfi * mfd + mfn)) /
(mfd * pd)) << 10;
-}
-
-static void update_clocks(IMXCCMState *s)
-{
- /*
- * If we ever emulate more clocks, this should switch to a data-driven
- * approach
- */
-
- if ((s->ccmr & CCMR_PRCS) == 2) {
- s->pll_refclk_freq = CKIL_FREQ * 1024;
- } else {
- s->pll_refclk_freq = CKIH_FREQ;
- }
-
- /* ipg_clk_arm aka MCU clock */
- if ((s->ccmr & CCMR_MDS) || !(s->ccmr & CCMR_MPE)) {
- s->mcu_clk_freq = s->pll_refclk_freq;
- } else {
- s->mcu_clk_freq = calc_pll(s->mpctl, s->pll_refclk_freq);
- }
-
- /* High-speed clock */
- s->hsp_clk_freq = s->mcu_clk_freq / (1 + EXTRACT(s->pdr0, HSP));
- s->ipg_clk_freq = s->hsp_clk_freq / (1 + EXTRACT(s->pdr0, IPG));
-
- DPRINTF("mcu %uMHz, HSP %uMHz, IPG %uHz\n",
- s->mcu_clk_freq / 1000000,
- s->hsp_clk_freq / 1000000,
- s->ipg_clk_freq);
-}
-
-static void imx_ccm_reset(DeviceState *dev)
-{
- IMXCCMState *s = IMX_CCM(dev);
-
- s->ccmr = 0x074b0b7d;
- s->pdr0 = 0xff870b48;
- s->pdr1 = 0x49fcfe7f;
- s->mpctl = PLL_PD(1) | PLL_MFD(0) | PLL_MFI(6) | PLL_MFN(0);
- s->cgr[0] = s->cgr[1] = s->cgr[2] = 0xffffffff;
- s->spctl = PLL_PD(1) | PLL_MFD(4) | PLL_MFI(0xc) | PLL_MFN(1);
- s->pmcr0 = 0x80209828;
-
- update_clocks(s);
-}
-
-static uint64_t imx_ccm_read(void *opaque, hwaddr offset,
- unsigned size)
-{
- IMXCCMState *s = (IMXCCMState *)opaque;
- DPRINTF("(offset=0x%" HWADDR_PRIx ")\n", offset);
-
- switch (offset >> 2) {
- case 0: /* CCMR */
- DPRINTF(" ccmr = 0x%x\n", s->ccmr);
- return s->ccmr;
- case 1:
- DPRINTF(" pdr0 = 0x%x\n", s->pdr0);
- return s->pdr0;
- case 2:
- DPRINTF(" pdr1 = 0x%x\n", s->pdr1);
- return s->pdr1;
- case 4:
- DPRINTF(" mpctl = 0x%x\n", s->mpctl);
- return s->mpctl;
- case 6:
- DPRINTF(" spctl = 0x%x\n", s->spctl);
- return s->spctl;
- case 8:
- DPRINTF(" cgr0 = 0x%x\n", s->cgr[0]);
- return s->cgr[0];
- case 9:
- DPRINTF(" cgr1 = 0x%x\n", s->cgr[1]);
- return s->cgr[1];
- case 10:
- DPRINTF(" cgr2 = 0x%x\n", s->cgr[2]);
- return s->cgr[2];
- case 18: /* LTR1 */
- return 0x00004040;
- case 23:
- DPRINTF(" pcmr0 = 0x%x\n", s->pmcr0);
- return s->pmcr0;
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
- return 0;
- }
-}
-
-static void imx_ccm_write(void *opaque, hwaddr offset,
- uint64_t value, unsigned size)
-{
- IMXCCMState *s = (IMXCCMState *)opaque;
-
- DPRINTF("(offset=0x%" HWADDR_PRIx ", value = 0x%x)\n",
- offset, (unsigned int)value);
-
- switch (offset >> 2) {
- case 0:
- s->ccmr = CCMR_FPMF | (value & 0x3b6fdfff);
- break;
- case 1:
- s->pdr0 = value & 0xff9f3fff;
- break;
- case 2:
- s->pdr1 = value;
- break;
- case 4:
- s->mpctl = value & 0xbfff3fff;
- break;
- case 6:
- s->spctl = value & 0xbfff3fff;
- break;
- case 8:
- s->cgr[0] = value;
- return;
- case 9:
- s->cgr[1] = value;
- return;
- case 10:
- s->cgr[2] = value;
- return;
-
- default:
- qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
- HWADDR_PRIx "\n", TYPE_IMX_CCM, __func__, offset);
- return;
- }
- update_clocks(s);
-}
-
-static const struct MemoryRegionOps imx_ccm_ops = {
- .read = imx_ccm_read,
- .write = imx_ccm_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int imx_ccm_init(SysBusDevice *dev)
-{
- IMXCCMState *s = IMX_CCM(dev);
-
- memory_region_init_io(&s->iomem, OBJECT(dev), &imx_ccm_ops, s,
- TYPE_IMX_CCM, 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static int imx_ccm_post_load(void *opaque, int version_id)
-{
- IMXCCMState *s = (IMXCCMState *)opaque;
-
- update_clocks(s);
- return 0;
-}
-
-static void imx_ccm_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *sbc = SYS_BUS_DEVICE_CLASS(klass);
+ DPRINTF("(pllreg = 0x%08x, base_freq = %d) = %d\n", pllreg, base_freq,
+ freq);
- sbc->init = imx_ccm_init;
- dc->reset = imx_ccm_reset;
- dc->vmsd = &vmstate_imx_ccm;
- dc->desc = "i.MX Clock Control Module";
+ return freq;
}
static const TypeInfo imx_ccm_info = {
- .name = TYPE_IMX_CCM,
- .parent = TYPE_SYS_BUS_DEVICE,
+ .name = TYPE_IMX_CCM,
+ .parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IMXCCMState),
- .class_init = imx_ccm_class_init,
+ .class_size = sizeof(IMXCCMClass),
+ .abstract = true,
};
static void imx_ccm_register_types(void)
diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h
index 73f50c6..5c62fde 100644
--- a/include/hw/arm/fsl-imx25.h
+++ b/include/hw/arm/fsl-imx25.h
@@ -19,7 +19,7 @@
#include "hw/arm/arm.h"
#include "hw/intc/imx_avic.h"
-#include "hw/misc/imx_ccm.h"
+#include "hw/misc/imx31_ccm.h"
#include "hw/char/imx_serial.h"
#include "hw/timer/imx_gpt.h"
#include "hw/timer/imx_epit.h"
@@ -44,7 +44,7 @@ typedef struct FslIMX25State {
/*< public >*/
ARMCPU cpu;
IMXAVICState avic;
- IMXCCMState ccm;
+ IMX31CCMState ccm;
IMXSerialState uart[FSL_IMX25_NUM_UARTS];
IMXGPTState gpt[FSL_IMX25_NUM_GPTS];
IMXEPITState epit[FSL_IMX25_NUM_EPITS];
diff --git a/include/hw/arm/fsl-imx31.h b/include/hw/arm/fsl-imx31.h
index 5e8f795..d408abb 100644
--- a/include/hw/arm/fsl-imx31.h
+++ b/include/hw/arm/fsl-imx31.h
@@ -19,7 +19,7 @@
#include "hw/arm/arm.h"
#include "hw/intc/imx_avic.h"
-#include "hw/misc/imx_ccm.h"
+#include "hw/misc/imx31_ccm.h"
#include "hw/char/imx_serial.h"
#include "hw/timer/imx_gpt.h"
#include "hw/timer/imx_epit.h"
@@ -42,7 +42,7 @@ typedef struct FslIMX31State {
/*< public >*/
ARMCPU cpu;
IMXAVICState avic;
- IMXCCMState ccm;
+ IMX31CCMState ccm;
IMXSerialState uart[FSL_IMX31_NUM_UARTS];
IMXGPTState gpt;
IMXEPITState epit[FSL_IMX31_NUM_EPITS];
diff --git a/include/hw/misc/imx31_ccm.h b/include/hw/misc/imx31_ccm.h
new file mode 100644
index 0000000..fcae36d
--- /dev/null
+++ b/include/hw/misc/imx31_ccm.h
@@ -0,0 +1,66 @@
+/*
+ * IMX31 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef IMX31_CCM_H
+#define IMX31_CCM_H
+
+#include "hw/misc/imx_ccm.h"
+
+/* CCMR */
+#define CCMR_FPME (1<<0)
+#define CCMR_MPE (1<<3)
+#define CCMR_MDS (1<<7)
+#define CCMR_FPMF (1<<26)
+#define CCMR_PRCS (3<<1)
+
+#define PMCR0_DFSUP1 (1<<31)
+
+/* PDR0 */
+#define PDR0_MCU_PODF_SHIFT (0)
+#define PDR0_MCU_PODF_MASK (0x7)
+#define PDR0_MAX_PODF_SHIFT (3)
+#define PDR0_MAX_PODF_MASK (0x7)
+#define PDR0_IPG_PODF_SHIFT (6)
+#define PDR0_IPG_PODF_MASK (0x3)
+#define PDR0_NFC_PODF_SHIFT (8)
+#define PDR0_NFC_PODF_MASK (0x7)
+#define PDR0_HSP_PODF_SHIFT (11)
+#define PDR0_HSP_PODF_MASK (0x7)
+#define PDR0_PER_PODF_SHIFT (16)
+#define PDR0_PER_PODF_MASK (0x1f)
+#define PDR0_CSI_PODF_SHIFT (23)
+#define PDR0_CSI_PODF_MASK (0x1ff)
+
+#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
+ & PDR0_##name##_PODF_MASK)
+#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
+ PDR0_##name##_PODF_SHIFT)
+
+#define TYPE_IMX31_CCM "imx31.ccm"
+#define IMX31_CCM(obj) OBJECT_CHECK(IMX31CCMState, (obj), TYPE_IMX31_CCM)
+
+typedef struct IMX31CCMState {
+ /* <private> */
+ IMXCCMState parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+
+ uint32_t ccmr;
+ uint32_t pdr0;
+ uint32_t pdr1;
+ uint32_t mpctl;
+ uint32_t spctl;
+ uint32_t cgr[3];
+ uint32_t pmcr0;
+ uint32_t pmcr1;
+} IMX31CCMState;
+
+#endif /* IMX31_CCM_H */
diff --git a/include/hw/misc/imx_ccm.h b/include/hw/misc/imx_ccm.h
index 09f6248..5c4b795 100644
--- a/include/hw/misc/imx_ccm.h
+++ b/include/hw/misc/imx_ccm.h
@@ -1,5 +1,5 @@
/*
- * IMX31 Clock Control Module
+ * IMX Clock Control Module base class
*
* Copyright (C) 2012 NICTA
* Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
@@ -13,33 +13,7 @@
#include "hw/sysbus.h"
-/* CCMR */
-#define CCMR_FPME (1<<0)
-#define CCMR_MPE (1<<3)
-#define CCMR_MDS (1<<7)
-#define CCMR_FPMF (1<<26)
-#define CCMR_PRCS (3<<1)
-
-/* PDR0 */
-#define PDR0_MCU_PODF_SHIFT (0)
-#define PDR0_MCU_PODF_MASK (0x7)
-#define PDR0_MAX_PODF_SHIFT (3)
-#define PDR0_MAX_PODF_MASK (0x7)
-#define PDR0_IPG_PODF_SHIFT (6)
-#define PDR0_IPG_PODF_MASK (0x3)
-#define PDR0_NFC_PODF_SHIFT (8)
-#define PDR0_NFC_PODF_MASK (0x7)
-#define PDR0_HSP_PODF_SHIFT (11)
-#define PDR0_HSP_PODF_MASK (0x7)
-#define PDR0_PER_PODF_SHIFT (16)
-#define PDR0_PER_PODF_MASK (0x1f)
-#define PDR0_CSI_PODF_SHIFT (23)
-#define PDR0_CSI_PODF_MASK (0x1ff)
-
-#define EXTRACT(value, name) (((value) >> PDR0_##name##_PODF_SHIFT) \
- & PDR0_##name##_PODF_MASK)
-#define INSERT(value, name) (((value) & PDR0_##name##_PODF_MASK) << \
- PDR0_##name##_PODF_SHIFT)
+#define CKIL_FREQ 32768 /* nominal 32khz clock */
/* PLL control registers */
#define PD(v) (((v) >> 26) & 0xf)
@@ -53,39 +27,44 @@
#define PLL_MFN(x) (((x) & 0x3ff) << 0)
#define TYPE_IMX_CCM "imx.ccm"
-#define IMX_CCM(obj) OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
+#define IMX_CCM(obj) \
+ OBJECT_CHECK(IMXCCMState, (obj), TYPE_IMX_CCM)
+#define IMX_CCM_CLASS(klass) \
+ OBJECT_CLASS_CHECK(IMXCCMClass, (klass), TYPE_IMX_CCM)
+#define IMX_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(IMXCCMClass, (obj), TYPE_IMX_CCM)
typedef struct IMXCCMState {
/* <private> */
SysBusDevice parent_obj;
/* <public> */
- MemoryRegion iomem;
- uint32_t ccmr;
- uint32_t pdr0;
- uint32_t pdr1;
- uint32_t mpctl;
- uint32_t spctl;
- uint32_t cgr[3];
- uint32_t pmcr0;
- uint32_t pmcr1;
-
- /* Frequencies precalculated on register changes */
- uint32_t pll_refclk_freq;
- uint32_t mcu_clk_freq;
- uint32_t hsp_clk_freq;
- uint32_t ipg_clk_freq;
} IMXCCMState;
typedef enum {
NOCLK,
+ CLK_MPLL,
+ CLK_UPLL,
CLK_MCU,
CLK_HSP,
+ CLK_MAX,
+ CLK_AHB,
CLK_IPG,
+ CLK_PER,
CLK_32k
} IMXClk;
-uint32_t imx_ccm_get_clock_frequency(DeviceState *s, IMXClk clock);
+typedef struct IMXCCMClass {
+ /* <private> */
+ SysBusDeviceClass parent_class;
+
+ /* <public> */
+ uint32_t (*get_clock_frequency)(IMXCCMState *s, IMXClk clk);
+} IMXCCMClass;
+
+uint32_t imx_ccm_calc_pll(uint32_t pllreg, uint32_t base_freq);
+
+uint32_t imx_ccm_get_clock_frequency(IMXCCMState *s, IMXClk clock);
#endif /* IMX_CCM_H */
diff --git a/include/hw/timer/imx_epit.h b/include/hw/timer/imx_epit.h
index c5328ae..0730ac3 100644
--- a/include/hw/timer/imx_epit.h
+++ b/include/hw/timer/imx_epit.h
@@ -31,6 +31,7 @@
#include "hw/sysbus.h"
#include "hw/ptimer.h"
+#include "hw/misc/imx_ccm.h"
/*
* EPIT: Enhanced periodic interrupt timer
@@ -63,8 +64,8 @@ typedef struct IMXEPITState{
/*< public >*/
ptimer_state *timer_reload;
ptimer_state *timer_cmp;
- MemoryRegion iomem;
- DeviceState *ccm;
+ MemoryRegion iomem;
+ IMXCCMState *ccm;
uint32_t cr;
uint32_t sr;
diff --git a/include/hw/timer/imx_gpt.h b/include/hw/timer/imx_gpt.h
index 3f02d3b..461adbe 100644
--- a/include/hw/timer/imx_gpt.h
+++ b/include/hw/timer/imx_gpt.h
@@ -31,6 +31,7 @@
#include "hw/sysbus.h"
#include "hw/ptimer.h"
+#include "hw/misc/imx_ccm.h"
/*
* GPT : General purpose timer
@@ -82,8 +83,8 @@ typedef struct IMXGPTState{
/*< public >*/
ptimer_state *timer;
- MemoryRegion iomem;
- DeviceState *ccm;
+ MemoryRegion iomem;
+ IMXCCMState *ccm;
uint32_t cr;
uint32_t pr;
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* [Qemu-devel] [PULL 25/25] i.MX: Add an i.MX25 specific CCM class/instance
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (23 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 24/25] i.MX: Split the CCM class into an abstract base class and a concrete class Peter Maydell
@ 2015-12-17 11:50 ` Peter Maydell
2015-12-17 13:40 ` [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
25 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 11:50 UTC (permalink / raw)
To: qemu-devel
From: Jean-Christophe Dubois <jcd@tribudubois.net>
With this CCM, i.MX25 timer is accurate with "real world time".
Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net>
Message-id: 2c0cf90be767bfc8520661eca891ab22c61f18fe.1449528242.git.jcd@tribudubois.net
Reviewed-by Peter Crosthwaite <crosthwaite.peter@gmail.com>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/arm/fsl-imx25.c | 2 +-
hw/misc/Makefile.objs | 1 +
hw/misc/imx25_ccm.c | 341 ++++++++++++++++++++++++++++++++++++++++++++
include/hw/arm/fsl-imx25.h | 4 +-
include/hw/misc/imx25_ccm.h | 79 ++++++++++
5 files changed, 424 insertions(+), 3 deletions(-)
create mode 100644 hw/misc/imx25_ccm.c
create mode 100644 include/hw/misc/imx25_ccm.h
diff --git a/hw/arm/fsl-imx25.c b/hw/arm/fsl-imx25.c
index 9f302ed..36818ee 100644
--- a/hw/arm/fsl-imx25.c
+++ b/hw/arm/fsl-imx25.c
@@ -38,7 +38,7 @@ static void fsl_imx25_init(Object *obj)
object_initialize(&s->avic, sizeof(s->avic), TYPE_IMX_AVIC);
qdev_set_parent_bus(DEVICE(&s->avic), sysbus_get_default());
- object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX31_CCM);
+ object_initialize(&s->ccm, sizeof(s->ccm), TYPE_IMX25_CCM);
qdev_set_parent_bus(DEVICE(&s->ccm), sysbus_get_default());
for (i = 0; i < FSL_IMX25_NUM_UARTS; i++) {
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index c77f3e3..8a235df 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -27,6 +27,7 @@ obj-$(CONFIG_ECCMEMCTL) += eccmemctl.o
obj-$(CONFIG_EXYNOS4) += exynos4210_pmu.o
obj-$(CONFIG_IMX) += imx_ccm.o
obj-$(CONFIG_IMX) += imx31_ccm.o
+obj-$(CONFIG_IMX) += imx25_ccm.o
obj-$(CONFIG_MILKYMIST) += milkymist-hpdmc.o
obj-$(CONFIG_MILKYMIST) += milkymist-pfpu.o
obj-$(CONFIG_MAINSTONE) += mst_fpga.o
diff --git a/hw/misc/imx25_ccm.c b/hw/misc/imx25_ccm.c
new file mode 100644
index 0000000..23759ca
--- /dev/null
+++ b/hw/misc/imx25_ccm.c
@@ -0,0 +1,341 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * To get the timer frequencies right, we need to emulate at least part of
+ * the CCM.
+ */
+
+#include "hw/misc/imx25_ccm.h"
+
+#ifndef DEBUG_IMX25_CCM
+#define DEBUG_IMX25_CCM 0
+#endif
+
+#define DPRINTF(fmt, args...) \
+ do { \
+ if (DEBUG_IMX25_CCM) { \
+ fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
+ __func__, ##args); \
+ } \
+ } while (0)
+
+static char const *imx25_ccm_reg_name(uint32_t reg)
+{
+ static char unknown[20];
+
+ switch (reg) {
+ case IMX25_CCM_MPCTL_REG:
+ return "mpctl";
+ case IMX25_CCM_UPCTL_REG:
+ return "upctl";
+ case IMX25_CCM_CCTL_REG:
+ return "cctl";
+ case IMX25_CCM_CGCR0_REG:
+ return "cgcr0";
+ case IMX25_CCM_CGCR1_REG:
+ return "cgcr1";
+ case IMX25_CCM_CGCR2_REG:
+ return "cgcr2";
+ case IMX25_CCM_PCDR0_REG:
+ return "pcdr0";
+ case IMX25_CCM_PCDR1_REG:
+ return "pcdr1";
+ case IMX25_CCM_PCDR2_REG:
+ return "pcdr2";
+ case IMX25_CCM_PCDR3_REG:
+ return "pcdr3";
+ case IMX25_CCM_RCSR_REG:
+ return "rcsr";
+ case IMX25_CCM_CRDR_REG:
+ return "crdr";
+ case IMX25_CCM_DCVR0_REG:
+ return "dcvr0";
+ case IMX25_CCM_DCVR1_REG:
+ return "dcvr1";
+ case IMX25_CCM_DCVR2_REG:
+ return "dcvr2";
+ case IMX25_CCM_DCVR3_REG:
+ return "dcvr3";
+ case IMX25_CCM_LTR0_REG:
+ return "ltr0";
+ case IMX25_CCM_LTR1_REG:
+ return "ltr1";
+ case IMX25_CCM_LTR2_REG:
+ return "ltr2";
+ case IMX25_CCM_LTR3_REG:
+ return "ltr3";
+ case IMX25_CCM_LTBR0_REG:
+ return "ltbr0";
+ case IMX25_CCM_LTBR1_REG:
+ return "ltbr1";
+ case IMX25_CCM_PMCR0_REG:
+ return "pmcr0";
+ case IMX25_CCM_PMCR1_REG:
+ return "pmcr1";
+ case IMX25_CCM_PMCR2_REG:
+ return "pmcr2";
+ case IMX25_CCM_MCR_REG:
+ return "mcr";
+ case IMX25_CCM_LPIMR0_REG:
+ return "lpimr0";
+ case IMX25_CCM_LPIMR1_REG:
+ return "lpimr1";
+ default:
+ sprintf(unknown, "[%d ?]", reg);
+ return unknown;
+ }
+}
+#define CKIH_FREQ 24000000 /* 24MHz crystal input */
+
+static const VMStateDescription vmstate_imx25_ccm = {
+ .name = TYPE_IMX25_CCM,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
+ VMSTATE_END_OF_LIST()
+ },
+};
+
+static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX25CCMState *s = IMX25_CCM(dev);
+
+ if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
+ freq = CKIH_FREQ;
+ } else {
+ freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
+ }
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx25_ccm_get_upll_clk(IMXCCMState *dev)
+{
+ uint32_t freq = 0;
+ IMX25CCMState *s = IMX25_CCM(dev);
+
+ if (!EXTRACT(s->reg[IMX25_CCM_CCTL_REG], UPLL_DIS)) {
+ freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_UPCTL_REG], CKIH_FREQ);
+ }
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX25CCMState *s = IMX25_CCM(dev);
+
+ freq = imx25_ccm_get_mpll_clk(dev);
+
+ if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
+ freq = (freq * 3 / 4);
+ }
+
+ freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+ IMX25CCMState *s = IMX25_CCM(dev);
+
+ freq = imx25_ccm_get_mcu_clk(dev)
+ / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
+{
+ uint32_t freq;
+
+ freq = imx25_ccm_get_ahb_clk(dev) / 2;
+
+ DPRINTF("freq = %d\n", freq);
+
+ return freq;
+}
+
+static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
+{
+ uint32_t freq = 0;
+ DPRINTF("Clock = %d)\n", clock);
+
+ switch (clock) {
+ case NOCLK:
+ break;
+ case CLK_MPLL:
+ freq = imx25_ccm_get_mpll_clk(dev);
+ break;
+ case CLK_UPLL:
+ freq = imx25_ccm_get_upll_clk(dev);
+ break;
+ case CLK_MCU:
+ freq = imx25_ccm_get_mcu_clk(dev);
+ break;
+ case CLK_AHB:
+ freq = imx25_ccm_get_ahb_clk(dev);
+ break;
+ case CLK_IPG:
+ freq = imx25_ccm_get_ipg_clk(dev);
+ break;
+ case CLK_32k:
+ freq = CKIL_FREQ;
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
+ TYPE_IMX25_CCM, __func__, clock);
+ break;
+ }
+
+ DPRINTF("Clock = %d) = %d\n", clock, freq);
+
+ return freq;
+}
+
+static void imx25_ccm_reset(DeviceState *dev)
+{
+ IMX25CCMState *s = IMX25_CCM(dev);
+
+ DPRINTF("\n");
+
+ memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
+ s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
+ s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
+ /*
+ * The value below gives:
+ * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz.
+ */
+ s->reg[IMX25_CCM_CCTL_REG] = 0xd0030000;
+ s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
+ s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
+ s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
+ s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
+ s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
+ s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
+ s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
+ s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
+ s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
+ s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
+ s->reg[IMX25_CCM_MCR_REG] = 0x43000000;
+
+ /*
+ * default boot will change the reset values to allow:
+ * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz.
+ * For some reason, this doesn't work. With the value below, linux
+ * detects a 88 MHz IPG CLK instead of 66,5 MHz.
+ s->reg[IMX25_CCM_CCTL_REG] = 0x20032000;
+ */
+}
+
+static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
+{
+ uint32 value = 0;
+ IMX25CCMState *s = (IMX25CCMState *)opaque;
+
+ if (offset < 0x70) {
+ value = s->reg[offset >> 2];
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
+ }
+
+ DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
+ value);
+
+ return value;
+}
+
+static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
+ unsigned size)
+{
+ IMX25CCMState *s = (IMX25CCMState *)opaque;
+
+ DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
+ (uint32_t)value);
+
+ if (offset < 0x70) {
+ /*
+ * We will do a better implementation later. In particular some bits
+ * cannot be written to.
+ */
+ s->reg[offset >> 2] = value;
+ } else {
+ qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
+ HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
+ }
+}
+
+static const struct MemoryRegionOps imx25_ccm_ops = {
+ .read = imx25_ccm_read,
+ .write = imx25_ccm_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .valid = {
+ /*
+ * Our device would not work correctly if the guest was doing
+ * unaligned access. This might not be a limitation on the real
+ * device but in practice there is no reason for a guest to access
+ * this device unaligned.
+ */
+ .min_access_size = 4,
+ .max_access_size = 4,
+ .unaligned = false,
+ },
+};
+
+static void imx25_ccm_init(Object *obj)
+{
+ DeviceState *dev = DEVICE(obj);
+ SysBusDevice *sd = SYS_BUS_DEVICE(obj);
+ IMX25CCMState *s = IMX25_CCM(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
+ TYPE_IMX25_CCM, 0x1000);
+ sysbus_init_mmio(sd, &s->iomem);
+}
+
+static void imx25_ccm_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
+
+ dc->reset = imx25_ccm_reset;
+ dc->vmsd = &vmstate_imx25_ccm;
+ dc->desc = "i.MX25 Clock Control Module";
+
+ ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
+}
+
+static const TypeInfo imx25_ccm_info = {
+ .name = TYPE_IMX25_CCM,
+ .parent = TYPE_IMX_CCM,
+ .instance_size = sizeof(IMX25CCMState),
+ .instance_init = imx25_ccm_init,
+ .class_init = imx25_ccm_class_init,
+};
+
+static void imx25_ccm_register_types(void)
+{
+ type_register_static(&imx25_ccm_info);
+}
+
+type_init(imx25_ccm_register_types)
diff --git a/include/hw/arm/fsl-imx25.h b/include/hw/arm/fsl-imx25.h
index 5c62fde..d0e8e9d 100644
--- a/include/hw/arm/fsl-imx25.h
+++ b/include/hw/arm/fsl-imx25.h
@@ -19,7 +19,7 @@
#include "hw/arm/arm.h"
#include "hw/intc/imx_avic.h"
-#include "hw/misc/imx31_ccm.h"
+#include "hw/misc/imx25_ccm.h"
#include "hw/char/imx_serial.h"
#include "hw/timer/imx_gpt.h"
#include "hw/timer/imx_epit.h"
@@ -44,7 +44,7 @@ typedef struct FslIMX25State {
/*< public >*/
ARMCPU cpu;
IMXAVICState avic;
- IMX31CCMState ccm;
+ IMX25CCMState ccm;
IMXSerialState uart[FSL_IMX25_NUM_UARTS];
IMXGPTState gpt[FSL_IMX25_NUM_GPTS];
IMXEPITState epit[FSL_IMX25_NUM_EPITS];
diff --git a/include/hw/misc/imx25_ccm.h b/include/hw/misc/imx25_ccm.h
new file mode 100644
index 0000000..296321c
--- /dev/null
+++ b/include/hw/misc/imx25_ccm.h
@@ -0,0 +1,79 @@
+/*
+ * IMX25 Clock Control Module
+ *
+ * Copyright (C) 2012 NICTA
+ * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef IMX25_CCM_H
+#define IMX25_CCM_H
+
+#include "hw/misc/imx_ccm.h"
+
+#define IMX25_CCM_MPCTL_REG 0
+#define IMX25_CCM_UPCTL_REG 1
+#define IMX25_CCM_CCTL_REG 2
+#define IMX25_CCM_CGCR0_REG 3
+#define IMX25_CCM_CGCR1_REG 4
+#define IMX25_CCM_CGCR2_REG 5
+#define IMX25_CCM_PCDR0_REG 6
+#define IMX25_CCM_PCDR1_REG 7
+#define IMX25_CCM_PCDR2_REG 8
+#define IMX25_CCM_PCDR3_REG 9
+#define IMX25_CCM_RCSR_REG 10
+#define IMX25_CCM_CRDR_REG 11
+#define IMX25_CCM_DCVR0_REG 12
+#define IMX25_CCM_DCVR1_REG 13
+#define IMX25_CCM_DCVR2_REG 14
+#define IMX25_CCM_DCVR3_REG 15
+#define IMX25_CCM_LTR0_REG 16
+#define IMX25_CCM_LTR1_REG 17
+#define IMX25_CCM_LTR2_REG 18
+#define IMX25_CCM_LTR3_REG 19
+#define IMX25_CCM_LTBR0_REG 20
+#define IMX25_CCM_LTBR1_REG 21
+#define IMX25_CCM_PMCR0_REG 22
+#define IMX25_CCM_PMCR1_REG 23
+#define IMX25_CCM_PMCR2_REG 24
+#define IMX25_CCM_MCR_REG 25
+#define IMX25_CCM_LPIMR0_REG 26
+#define IMX25_CCM_LPIMR1_REG 27
+#define IMX25_CCM_MAX_REG 28
+
+/* CCTL */
+#define CCTL_ARM_CLK_DIV_SHIFT (30)
+#define CCTL_ARM_CLK_DIV_MASK (0x3)
+#define CCTL_AHB_CLK_DIV_SHIFT (28)
+#define CCTL_AHB_CLK_DIV_MASK (0x3)
+#define CCTL_MPLL_BYPASS_SHIFT (22)
+#define CCTL_MPLL_BYPASS_MASK (0x1)
+#define CCTL_USB_DIV_SHIFT (16)
+#define CCTL_USB_DIV_MASK (0x3F)
+#define CCTL_ARM_SRC_SHIFT (13)
+#define CCTL_ARM_SRC_MASK (0x1)
+#define CCTL_UPLL_DIS_SHIFT (23)
+#define CCTL_UPLL_DIS_MASK (0x1)
+
+#define EXTRACT(value, name) (((value) >> CCTL_##name##_SHIFT) \
+ & CCTL_##name##_MASK)
+#define INSERT(value, name) (((value) & CCTL_##name##_MASK) << \
+ CCTL_##name##_SHIFT)
+
+#define TYPE_IMX25_CCM "imx25.ccm"
+#define IMX25_CCM(obj) OBJECT_CHECK(IMX25CCMState, (obj), TYPE_IMX25_CCM)
+
+typedef struct IMX25CCMState {
+ /* <private> */
+ IMXCCMState parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+
+ uint32_t reg[IMX25_CCM_MAX_REG];
+
+} IMX25CCMState;
+
+#endif /* IMX25_CCM_H */
--
1.9.1
^ permalink raw reply related [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PULL 00/25] target-arm queue
2015-12-17 11:49 [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
` (24 preceding siblings ...)
2015-12-17 11:50 ` [Qemu-devel] [PULL 25/25] i.MX: Add an i.MX25 specific CCM class/instance Peter Maydell
@ 2015-12-17 13:40 ` Peter Maydell
2015-12-17 14:46 ` Peter Maydell
25 siblings, 1 reply; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 13:40 UTC (permalink / raw)
To: QEMU Developers
On 17 December 2015 at 11:49, Peter Maydell <peter.maydell@linaro.org> wrote:
> First target-arm pull for 2.6. I have a bunch more stuff in my
> to-review queue, but this is big enough for a pull already.
>
> -- PMM
>
> The following changes since commit fc77eb20d78e303ef11482288e185d856431f02f:
>
> Merge remote-tracking branch 'remotes/kraxel/tags/pull-audio-20151215-1' into staging (2015-12-17 11:10:03 +0000)
>
> are available in the git repository at:
>
>
> git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20151217
Updated:
git://git.linaro.org/people/pmaydell/qemu-arm.git
tags/pull-target-arm-20151217-1
to fix a build issue due to including a linux header directly
rather than the standard-includes/linux local version.
thanks
-- PMM
^ permalink raw reply [flat|nested] 28+ messages in thread
* Re: [Qemu-devel] [PULL 00/25] target-arm queue
2015-12-17 13:40 ` [Qemu-devel] [PULL 00/25] target-arm queue Peter Maydell
@ 2015-12-17 14:46 ` Peter Maydell
0 siblings, 0 replies; 28+ messages in thread
From: Peter Maydell @ 2015-12-17 14:46 UTC (permalink / raw)
To: QEMU Developers
On 17 December 2015 at 13:40, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 17 December 2015 at 11:49, Peter Maydell <peter.maydell@linaro.org> wrote:
>> First target-arm pull for 2.6. I have a bunch more stuff in my
>> to-review queue, but this is big enough for a pull already.
>>
>> -- PMM
>>
>> The following changes since commit fc77eb20d78e303ef11482288e185d856431f02f:
>>
>> Merge remote-tracking branch 'remotes/kraxel/tags/pull-audio-20151215-1' into staging (2015-12-17 11:10:03 +0000)
>>
>> are available in the git repository at:
>>
>>
>> git://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20151217
>
> Updated:
>
> git://git.linaro.org/people/pmaydell/qemu-arm.git
> tags/pull-target-arm-20151217-1
>
> to fix a build issue due to including a linux header directly
> rather than the standard-includes/linux local version.
Fixed version applied.
-- PMM
^ permalink raw reply [flat|nested] 28+ messages in thread