From fc1891c74ae122a9dc7854f38bae7db03cd911e6 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:07 +0100 Subject: [PATCH 01/28] target-arm: Handle "extended small page" descriptors correctly The old ARMv5-style page table format includes a kind of second level descriptor named the "extended small page" format, whose primary purpose is to allow specification of the TEX memory attribute bits on a 4K page. This exists on ARMv6 and also (as an implementation extension) on XScale CPUs; it's UNPREDICTABLE on v5. We were mishandling this in two ways: (1) we weren't implementing it for v6 (probably never noticed because Linux will use the new-style v6 page table format there) (2) we were not correctly setting the page_size, which is 4K, not 1K The latter bug went unnoticed for years because the only thing which the page_size affects is which TLB entries get flushed when the guest does a TLB invalidate on an address in the page, and prior to commit 2f0d8631b7 we were doing a full TLB flush very frequently due to Linux's habit of writing the SCTLR pointlessly a lot. (We can assume that after commit 2f0d8631b7 the bug went unnoticed for a year because nobody's actually using the Zaurus/XScale emulation...) Report the correct page size for these descriptors, and permit them on ARMv6 CPUs. This fixes a problem where a kernel image for Zaurus can boot the kernel OK but gets random segfaults when it tries to run userspace programs. Signed-off-by: Peter Maydell Message-id: 1432844085-16441-1-git-send-email-peter.maydell@linaro.org --- target-arm/helper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 3da0c0579c..3ed2fc3fa2 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5302,20 +5302,25 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, ap = (desc >> (4 + ((address >> 9) & 6))) & 3; *page_size = 0x1000; break; - case 3: /* 1k page. */ + case 3: /* 1k page, or ARMv6/XScale "extended small (4k) page" */ if (type == 1) { - if (arm_feature(env, ARM_FEATURE_XSCALE)) { + /* ARMv6/XScale extended small page format */ + if (arm_feature(env, ARM_FEATURE_XSCALE) + || arm_feature(env, ARM_FEATURE_V6)) { phys_addr = (desc & 0xfffff000) | (address & 0xfff); + *page_size = 0x1000; } else { - /* Page translation fault. */ + /* UNPREDICTABLE in ARMv5; we choose to take a + * page translation fault. + */ code = 7; goto do_fault; } } else { phys_addr = (desc & 0xfffffc00) | (address & 0x3ff); + *page_size = 0x400; } ap = (desc >> 4) & 3; - *page_size = 0x400; break; default: /* Never happens, but compiler isn't smart enough to tell. */ From 4e42a6ca37e39e56725518851f4388e46bd91129 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 15 Jun 2015 18:06:07 +0100 Subject: [PATCH 02/28] target-arm: use extended address bits from supersection short descriptor Since ARMv7 with LPAE support, a supersection short translation table descriptor has had extended base address fields which hold bits 39:32 of translated address. These fields are IMPDEF in ARMv6 and ARMv7 without LPAE support. Signed-off-by: Sergey Fedorov Message-id: 1433235718-30485-1-git-send-email-serge.fdrv@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target-arm/helper.c b/target-arm/helper.c index 3ed2fc3fa2..611b0e7cdc 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5397,6 +5397,8 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, if (desc & (1 << 18)) { /* Supersection. */ phys_addr = (desc & 0xff000000) | (address & 0x00ffffff); + phys_addr |= (uint64_t)extract32(desc, 20, 4) << 32; + phys_addr |= (uint64_t)extract32(desc, 5, 4) << 36; *page_size = 0x1000000; } else { /* Section. */ From 235069a380147e31236b94c31528fc5170c3a421 Mon Sep 17 00:00:00 2001 From: Johan Karlsson Date: Mon, 15 Jun 2015 18:06:07 +0100 Subject: [PATCH 03/28] arm_gic: gic_update should always update all cores This patch fixes so that gic_update always updates all the cores with new pending irq states. If the function returns early it is possible to get interrupts that has already been acknowledged. Signed-off-by: Johan Karlsson [PMM: rebased to apply to current master] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/intc/arm_gic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/intc/arm_gic.c b/hw/intc/arm_gic.c index c1d2e704ec..454bfd7df5 100644 --- a/hw/intc/arm_gic.c +++ b/hw/intc/arm_gic.c @@ -71,7 +71,7 @@ void gic_update(GICState *s) || !(s->cpu_ctlr[cpu] & (GICC_CTLR_EN_GRP0 | GICC_CTLR_EN_GRP1))) { qemu_irq_lower(s->parent_irq[cpu]); qemu_irq_lower(s->parent_fiq[cpu]); - return; + continue; } best_prio = 0x100; best_irq = 1023; From 644ead5be1a851abff16886240c5c6fc1c5137c0 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 04/28] hw/display/exynos4210_fimd: Fix bit-swapping code fimd_swap_data() includes code to reverse the bits in a 64-bit integer, but an off-by-one error meant that it would try to shift off the top of the integer. Correct the bug (spotted by Coverity). Signed-off-by: Peter Maydell Message-id: 1432912615-23107-1-git-send-email-peter.maydell@linaro.org --- hw/display/exynos4210_fimd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/display/exynos4210_fimd.c b/hw/display/exynos4210_fimd.c index 72b3a1d063..603ef50568 100644 --- a/hw/display/exynos4210_fimd.c +++ b/hw/display/exynos4210_fimd.c @@ -337,7 +337,7 @@ static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data) if (swap_ctl & FIMD_WINCON_SWAP_BITS) { res = 0; for (i = 0; i < 64; i++) { - if (x & (1ULL << (64 - i))) { + if (x & (1ULL << (63 - i))) { res |= (1ULL << i); } } From a79e0218e0ae27c9cdd2648bd46e5a916c903cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 05/28] target-arm/cpu.h: remove pending_exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This isn't used by any of the code. In fact it looks like it was never used as it came in with ARMv7 support. Signed-off-by: Alex Bennée Message-id: 1434020015-8868-1-git-send-email-alex.bennee@linaro.org Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.h | 1 - 1 file changed, 1 deletion(-) diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 21b5b8e538..7c1d95c815 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -384,7 +384,6 @@ typedef struct CPUARMState { uint32_t control; int current_sp; int exception; - int pending_exception; } v7m; /* Information associated with an exception about to be taken: From 7525465e6def0ef878741087b36e4657016dce80 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 06/28] target-arm/kvm64: Add cortex-a53 cpu support Since commit e353102(target-arm: cpu64: Add support for Cortex-A53) has added Cortex-A53 cpu support for target-arm, this patch just enables it for kvm-arm. Here adding XGENE_POTENZA just makes the enum continuous. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Message-id: 1433207452-4512-2-git-send-email-shannon.zhao@linaro.org [PMM: Don't add the CPU types to cpus_to_try[]; this array only lists old CPUs which were supported in pre-PREFERRED_TARGET kernels] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu64.c | 1 + target-arm/kvm-consts.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c index bf7dd685f8..dd6f9d86f9 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -159,6 +159,7 @@ static void aarch64_a53_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V8_SHA256); set_feature(&cpu->env, ARM_FEATURE_V8_PMULL); set_feature(&cpu->env, ARM_FEATURE_CRC); + cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; cpu->midr = 0x410fd034; cpu->reset_fpsid = 0x41034070; cpu->mvfr0 = 0x10110222; diff --git a/target-arm/kvm-consts.h b/target-arm/kvm-consts.h index aea12f1bc4..943bf8980a 100644 --- a/target-arm/kvm-consts.h +++ b/target-arm/kvm-consts.h @@ -127,6 +127,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED) #define QEMU_KVM_ARM_TARGET_AEM_V8 0 #define QEMU_KVM_ARM_TARGET_FOUNDATION_V8 1 #define QEMU_KVM_ARM_TARGET_CORTEX_A57 2 +#define QEMU_KVM_ARM_TARGET_XGENE_POTENZA 3 +#define QEMU_KVM_ARM_TARGET_CORTEX_A53 4 /* There's no kernel define for this: sentinel value which * matches no KVM target value for either 64 or 32 bit @@ -137,6 +139,8 @@ MISMATCH_CHECK(QEMU_PSCI_RET_DISABLED, PSCI_RET_DISABLED) MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_AEM_V8, KVM_ARM_TARGET_AEM_V8) MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_FOUNDATION_V8, KVM_ARM_TARGET_FOUNDATION_V8) MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A57, KVM_ARM_TARGET_CORTEX_A57) +MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_XGENE_POTENZA, KVM_ARM_TARGET_XGENE_POTENZA) +MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A53, KVM_ARM_TARGET_CORTEX_A53) #else MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A15, KVM_ARM_TARGET_CORTEX_A15) MISMATCH_CHECK(QEMU_KVM_ARM_TARGET_CORTEX_A7, KVM_ARM_TARGET_CORTEX_A7) From 8772de2c53b44c75f18140646aa928e6d77cb9d8 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 07/28] hw/arm/virt: Add cortex-a53 cpu support in machine virt Add cortex-a53 cpu support in machine virt, so it can be used for TCG and KVM. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Peter Maydell Message-id: 1433207452-4512-3-git-send-email-shannon.zhao@linaro.org Signed-off-by: Peter Maydell --- hw/arm/virt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 1b1cc716ad..dbe89c1087 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -144,6 +144,11 @@ static VirtBoardInfo machines[] = { .memmap = a15memmap, .irqmap = a15irqmap, }, + { + .cpu_model = "cortex-a53", + .memmap = a15memmap, + .irqmap = a15irqmap, + }, { .cpu_model = "cortex-a57", .memmap = a15memmap, From 13b72b2b9aa7ab7ee129e38e9587acd6a1b9a932 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 08/28] target-arm: Fix REVIDR reset value According to ARM Cortex-A53/A57 TRM, REVIDR reset value should be zero. So let REVIDR reset value be specified by CPU model and correct it for Cortex-A53/A57. Signed-off-by: Sergey Fedorov Message-id: 1433321048-23793-2-git-send-email-serge.fdrv@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 1 + target-arm/cpu64.c | 2 ++ target-arm/helper.c | 5 ++--- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index ed5a6441bb..c80381da89 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -127,6 +127,7 @@ typedef struct ARMCPU { * prefix means a constant register. */ uint32_t midr; + uint32_t revidr; uint32_t reset_fpsid; uint32_t mvfr0; uint32_t mvfr1; diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c index dd6f9d86f9..63c8b1cfa9 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -110,6 +110,7 @@ static void aarch64_a57_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CRC); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; cpu->midr = 0x411fd070; + cpu->revidr = 0x00000000; cpu->reset_fpsid = 0x41034070; cpu->mvfr0 = 0x10110222; cpu->mvfr1 = 0x12111111; @@ -161,6 +162,7 @@ static void aarch64_a53_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CRC); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; cpu->midr = 0x410fd034; + cpu->revidr = 0x00000000; cpu->reset_fpsid = 0x41034070; cpu->mvfr0 = 0x10110222; cpu->mvfr1 = 0x12111111; diff --git a/target-arm/helper.c b/target-arm/helper.c index 611b0e7cdc..8053ad598b 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3424,15 +3424,14 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; ARMCPRegInfo id_v8_midr_cp_reginfo[] = { /* v8 MIDR -- the wildcard isn't necessary, and nor is the - * variable-MIDR TI925 behaviour. Instead we have a single - * (strictly speaking IMPDEF) alias of the MIDR, REVIDR. + * variable-MIDR TI925 behaviour. */ { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr }, { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6, - .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr }, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, REGINFO_SENTINEL }; ARMCPRegInfo id_cp_reginfo[] = { From ac00c79ff6635ae9fd732ff357ada0d05e795500 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 09/28] target-arm: add AArch32 MIDR aliases in ARMv8 According to ARMv8 ARM, there are additional aliases to MIDR system register in AArch32 state. So add them to the list. Signed-off-by: Sergey Fedorov Message-id: 1433321048-23793-3-git-send-email-serge.fdrv@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 8053ad598b..16195b381e 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3423,12 +3423,16 @@ void register_cp_regs_for_features(ARMCPU *cpu) REGINFO_SENTINEL }; ARMCPRegInfo id_v8_midr_cp_reginfo[] = { - /* v8 MIDR -- the wildcard isn't necessary, and nor is the - * variable-MIDR TI925 behaviour. - */ { .name = "MIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 0, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->midr }, + /* crn = 0 op1 = 0 crm = 0 op2 = 4,7 : AArch32 aliases of MIDR */ + { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST, + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 4, + .access = PL1_R, .resetvalue = cpu->midr }, + { .name = "MIDR", .type = ARM_CP_ALIAS | ARM_CP_CONST, + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 7, + .access = PL1_R, .resetvalue = cpu->midr }, { .name = "REVIDR_EL1", .state = ARM_CP_STATE_BOTH, .opc0 = 3, .opc1 = 0, .crn = 0, .crm = 0, .opc2 = 6, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = cpu->revidr }, From 8f4d260e70aff7c3796d97c78ba0663696e2d503 Mon Sep 17 00:00:00 2001 From: Shannon Zhao Date: Mon, 15 Jun 2015 18:06:08 +0100 Subject: [PATCH 10/28] MAINTAINERS: Add myself as ARM ACPI Subsystem maintainer Add Shannon Zhao as the maintainer for the ARM ACPI Subsystem. Signed-off-by: Shannon Zhao Signed-off-by: Shannon Zhao Reviewed-by: Claudio Fontana Acked-by: Peter Maydell Message-id: 1433248318-6076-1-git-send-email-shannon.zhao@linaro.org Signed-off-by: Peter Maydell --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7ba2079c35..32c7ca4566 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -356,6 +356,13 @@ F: hw/misc/zynq_slcr.c F: hw/*/cadence_* F: hw/ssi/xilinx_spips.c +ARM ACPI Subsystem +M: Shannon Zhao +M: Shannon Zhao +S: Maintained +F: hw/arm/virt-acpi-build.c +F: include/hw/arm/virt-acpi-build.h + CRIS Machines ------------- Axis Dev88 From eb5e1d3c85dffe677da2550d211f9304a7d5ba3b Mon Sep 17 00:00:00 2001 From: Pavel Fedin Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 11/28] target-arm: Use the kernel's idea of MPIDR if we're using KVM When we're using KVM, the kernel's internal idea of the MPIDR affinity fields must match the values we tell it for the guest vcpu cluster configuration in the device tree. Since at the moment the kernel doesn't support letting userspace tell it the correct affinity fields to use, we must read the kernel's view and reflect that back in the device tree. Signed-off-by: Shlomo Pongratz Signed-off-by: Pavel Fedin Message-id: 02f601d0a1e6$90c7d630$b2578290$@samsung.com [PMM: Use a local #define rather than a global variable for the TCG ARM_CPUS_PER_CLUSTER setting. Tweak a comment. Update the commit message.] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/arm/virt.c | 2 +- target-arm/cpu-qom.h | 1 + target-arm/cpu.c | 12 ++++++++++++ target-arm/helper.c | 9 +++------ target-arm/kvm32.c | 15 +++++++++++++++ target-arm/kvm64.c | 15 +++++++++++++++ target-arm/psci.c | 19 +++++++++++++++++-- 7 files changed, 64 insertions(+), 9 deletions(-) diff --git a/hw/arm/virt.c b/hw/arm/virt.c index dbe89c1087..f1e85c8e92 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -311,7 +311,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi) "enable-method", "psci"); } - qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", cpu); + qemu_fdt_setprop_cell(vbi->fdt, nodename, "reg", armcpu->mp_affinity); g_free(nodename); } } diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index c80381da89..24a4cfb1ae 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -160,6 +160,7 @@ typedef struct ARMCPU { uint64_t id_aa64mmfr1; uint32_t dbgdidr; uint32_t clidr; + uint64_t mp_affinity; /* MP ID without feature bits */ /* The elements of this array are the CCSIDR values for each cache, * in the order L1DCache, L1ICache, L2DCache, L2ICache, etc. */ diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 4a888ab47a..34990acb82 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -383,17 +383,29 @@ static inline void unset_feature(CPUARMState *env, int feature) env->features &= ~(1ULL << feature); } +#define ARM_CPUS_PER_CLUSTER 8 + static void arm_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); ARMCPU *cpu = ARM_CPU(obj); static bool inited; + uint32_t Aff1, Aff0; cs->env_ptr = &cpu->env; cpu_exec_init(&cpu->env); cpu->cp_regs = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, g_free); + /* This cpu-id-to-MPIDR affinity is used only for TCG; KVM will override it. + * We don't support setting cluster ID ([16..23]) (known as Aff2 + * in later ARM ARM versions), or any of the higher affinity level fields, + * so these bits always RAZ. + */ + Aff1 = cs->cpu_index / ARM_CPUS_PER_CLUSTER; + Aff0 = cs->cpu_index % ARM_CPUS_PER_CLUSTER; + cpu->mp_affinity = (Aff1 << 8) | Aff0; + #ifndef CONFIG_USER_ONLY /* Our inbound IRQ and FIQ lines */ if (kvm_enabled()) { diff --git a/target-arm/helper.c b/target-arm/helper.c index 16195b381e..6a62d798c2 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2063,12 +2063,9 @@ static const ARMCPRegInfo strongarm_cp_reginfo[] = { static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri) { - CPUState *cs = CPU(arm_env_get_cpu(env)); - uint32_t mpidr = cs->cpu_index; - /* We don't support setting cluster ID ([8..11]) (known as Aff1 - * in later ARM ARM versions), or any of the higher affinity level fields, - * so these bits always RAZ. - */ + ARMCPU *cpu = ARM_CPU(arm_env_get_cpu(env)); + uint64_t mpidr = cpu->mp_affinity; + if (arm_feature(env, ARM_FEATURE_V7MP)) { mpidr |= (1U << 31); /* Cores which are uniprocessor (non-coherent) diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c index 49b6babc05..d7e7d6877f 100644 --- a/target-arm/kvm32.c +++ b/target-arm/kvm32.c @@ -153,10 +153,14 @@ bool kvm_arm_reg_syncs_via_cpreg_list(uint64_t regidx) } } +#define ARM_MPIDR_HWID_BITMASK 0xFFFFFF +#define ARM_CPU_ID_MPIDR 0, 0, 0, 5 + int kvm_arch_init_vcpu(CPUState *cs) { int ret; uint64_t v; + uint32_t mpidr; struct kvm_one_reg r; ARMCPU *cpu = ARM_CPU(cs); @@ -193,6 +197,17 @@ int kvm_arch_init_vcpu(CPUState *cs) return -EINVAL; } + /* + * When KVM is in use, PSCI is emulated in-kernel and not by qemu. + * Currently KVM has its own idea about MPIDR assignment, so we + * override our defaults with what we get from KVM. + */ + ret = kvm_get_one_reg(cs, ARM_CP15_REG32(ARM_CPU_ID_MPIDR), &mpidr); + if (ret) { + return ret; + } + cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK; + return kvm_arm_init_cpreg_list(cpu); } diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c index 93c1ca8b21..ac34f51498 100644 --- a/target-arm/kvm64.c +++ b/target-arm/kvm64.c @@ -77,9 +77,13 @@ bool kvm_arm_get_host_cpu_features(ARMHostCPUClass *ahcc) return true; } +#define ARM_MPIDR_HWID_BITMASK 0xFF00FFFFFFULL +#define ARM_CPU_ID_MPIDR 3, 0, 0, 0, 5 + int kvm_arch_init_vcpu(CPUState *cs) { int ret; + uint64_t mpidr; ARMCPU *cpu = ARM_CPU(cs); if (cpu->kvm_target == QEMU_KVM_ARM_TARGET_NONE || @@ -107,6 +111,17 @@ int kvm_arch_init_vcpu(CPUState *cs) return ret; } + /* + * When KVM is in use, PSCI is emulated in-kernel and not by qemu. + * Currently KVM has its own idea about MPIDR assignment, so we + * override our defaults with what we get from KVM. + */ + ret = kvm_get_one_reg(cs, ARM64_SYS_REG(ARM_CPU_ID_MPIDR), &mpidr); + if (ret) { + return ret; + } + cpu->mp_affinity = mpidr & ARM_MPIDR_HWID_BITMASK; + return kvm_arm_init_cpreg_list(cpu); } diff --git a/target-arm/psci.c b/target-arm/psci.c index d8fafab2fe..20e4cb6f9c 100644 --- a/target-arm/psci.c +++ b/target-arm/psci.c @@ -72,6 +72,21 @@ bool arm_is_psci_call(ARMCPU *cpu, int excp_type) } } +static CPUState *get_cpu_by_id(uint64_t id) +{ + CPUState *cpu; + + CPU_FOREACH(cpu) { + ARMCPU *armcpu = ARM_CPU(cpu); + + if (armcpu->mp_affinity == id) { + return cpu; + } + } + + return NULL; +} + void arm_handle_psci_call(ARMCPU *cpu) { /* @@ -121,7 +136,7 @@ void arm_handle_psci_call(ARMCPU *cpu) switch (param[2]) { case 0: - target_cpu_state = qemu_get_cpu(mpidr & 0xff); + target_cpu_state = get_cpu_by_id(mpidr); if (!target_cpu_state) { ret = QEMU_PSCI_RET_INVALID_PARAMS; break; @@ -153,7 +168,7 @@ void arm_handle_psci_call(ARMCPU *cpu) context_id = param[3]; /* change to the cpu we are powering up */ - target_cpu_state = qemu_get_cpu(mpidr & 0xff); + target_cpu_state = get_cpu_by_id(mpidr); if (!target_cpu_state) { ret = QEMU_PSCI_RET_INVALID_PARAMS; break; From 14c3032a7ebd5a354381465453c0c0690b7342d1 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 12/28] hw/arm/pxa2xx: Mark coprocessor registers as ARM_CP_IO The pxa2xx custom coprocessor registers in cp6 and cp14 do device accesses, so mark the non-constant regs as ARM_CP_IO so that icount works correctly and doesn't abort. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1434117989-7367-2-git-send-email-peter.maydell@linaro.org --- hw/arm/pxa2xx.c | 8 ++++---- hw/arm/pxa2xx_pic.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index f921a5680c..8123f05eed 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -334,10 +334,10 @@ static uint64_t pxa2xx_cpccnt_read(CPUARMState *env, const ARMCPRegInfo *ri) static const ARMCPRegInfo pxa_cp_reginfo[] = { /* cp14 crm==1: perf registers */ { .name = "CPPMNC", .cp = 14, .crn = 0, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_cppmnc_read, .writefn = pxa2xx_cppmnc_write }, { .name = "CPCCNT", .cp = 14, .crn = 1, .crm = 1, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_cpccnt_read, .writefn = arm_cp_write_ignore }, { .name = "CPINTEN", .cp = 14, .crn = 4, .crm = 1, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, @@ -356,11 +356,11 @@ static const ARMCPRegInfo pxa_cp_reginfo[] = { .access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, /* cp14 crn==6: CLKCFG */ { .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, /* cp14 crn==7: PWRMODE */ { .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, + .access = PL1_RW, .type = ARM_CP_IO, .readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, REGINFO_SENTINEL }; diff --git a/hw/arm/pxa2xx_pic.c b/hw/arm/pxa2xx_pic.c index 9cfc714874..d41ac93416 100644 --- a/hw/arm/pxa2xx_pic.c +++ b/hw/arm/pxa2xx_pic.c @@ -232,7 +232,7 @@ static void pxa2xx_pic_cp_write(CPUARMState *env, const ARMCPRegInfo *ri, #define REGINFO_FOR_PIC_CP(NAME, CRN) \ { .name = NAME, .cp = 6, .crn = CRN, .crm = 0, .opc1 = 0, .opc2 = 0, \ - .access = PL1_RW, \ + .access = PL1_RW, .type = ARM_CP_IO, \ .readfn = pxa2xx_pic_cp_read, .writefn = pxa2xx_pic_cp_write } static const ARMCPRegInfo pxa_pic_cp_reginfo[] = { From 1fd9f2df241554b68b3a19ad1c94c475c7bb85ea Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 13/28] hw/arm/pxa2xx: Convert pxa2xx-fir to QOM and VMState Convert the pxa2xx-fir device to QOM, including using a VMState for its migration info. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1434117989-7367-3-git-send-email-peter.maydell@linaro.org --- hw/arm/pxa2xx.c | 153 +++++++++++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 61 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 8123f05eed..a015c991fe 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -1759,24 +1759,33 @@ static PXA2xxI2SState *pxa2xx_i2s_init(MemoryRegion *sysmem, } /* PXA Fast Infra-red Communications Port */ +#define TYPE_PXA2XX_FIR "pxa2xx-fir" +#define PXA2XX_FIR(obj) OBJECT_CHECK(PXA2xxFIrState, (obj), TYPE_PXA2XX_FIR) + struct PXA2xxFIrState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + MemoryRegion iomem; qemu_irq irq; qemu_irq rx_dma; qemu_irq tx_dma; - int enable; + uint32_t enable; CharDriverState *chr; uint8_t control[3]; uint8_t status[2]; - int rx_len; - int rx_start; + uint32_t rx_len; + uint32_t rx_start; uint8_t rx_fifo[64]; }; -static void pxa2xx_fir_reset(PXA2xxFIrState *s) +static void pxa2xx_fir_reset(DeviceState *d) { + PXA2xxFIrState *s = PXA2XX_FIR(d); + s->control[0] = 0x00; s->control[1] = 0x00; s->control[2] = 0x00; @@ -1953,73 +1962,94 @@ static void pxa2xx_fir_event(void *opaque, int event) { } -static void pxa2xx_fir_save(QEMUFile *f, void *opaque) +static void pxa2xx_fir_instance_init(Object *obj) { - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; + PXA2xxFIrState *s = PXA2XX_FIR(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - qemu_put_be32(f, s->enable); - - qemu_put_8s(f, &s->control[0]); - qemu_put_8s(f, &s->control[1]); - qemu_put_8s(f, &s->control[2]); - qemu_put_8s(f, &s->status[0]); - qemu_put_8s(f, &s->status[1]); - - qemu_put_byte(f, s->rx_len); - for (i = 0; i < s->rx_len; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]); + memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, + "pxa2xx-fir", 0x1000); + sysbus_init_mmio(sbd, &s->iomem); + sysbus_init_irq(sbd, &s->irq); + sysbus_init_irq(sbd, &s->rx_dma); + sysbus_init_irq(sbd, &s->tx_dma); } -static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) +static void pxa2xx_fir_realize(DeviceState *dev, Error **errp) { - PXA2xxFIrState *s = (PXA2xxFIrState *) opaque; - int i; + PXA2xxFIrState *s = PXA2XX_FIR(dev); - s->enable = qemu_get_be32(f); - - qemu_get_8s(f, &s->control[0]); - qemu_get_8s(f, &s->control[1]); - qemu_get_8s(f, &s->control[2]); - qemu_get_8s(f, &s->status[0]); - qemu_get_8s(f, &s->status[1]); - - s->rx_len = qemu_get_byte(f); - s->rx_start = 0; - for (i = 0; i < s->rx_len; i ++) - s->rx_fifo[i] = qemu_get_byte(f); - - return 0; -} - -static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - hwaddr base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, - CharDriverState *chr) -{ - PXA2xxFIrState *s = (PXA2xxFIrState *) - g_malloc0(sizeof(PXA2xxFIrState)); - - s->irq = irq; - s->rx_dma = rx_dma; - s->tx_dma = tx_dma; - s->chr = chr; - - pxa2xx_fir_reset(s); - - memory_region_init_io(&s->iomem, NULL, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); - - if (chr) { - qemu_chr_fe_claim_no_fail(chr); - qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, + if (s->chr) { + qemu_chr_fe_claim_no_fail(s->chr); + qemu_chr_add_handlers(s->chr, pxa2xx_fir_is_empty, pxa2xx_fir_rx, pxa2xx_fir_event, s); } +} - register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, - pxa2xx_fir_load, s); +static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) +{ + PXA2xxFIrState *s = opaque; - return s; + return s->rx_start < sizeof(s->rx_fifo); +} + +static const VMStateDescription pxa2xx_fir_vmsd = { + .name = "pxa2xx-fir", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(enable, PXA2xxFIrState), + VMSTATE_UINT8_ARRAY(control, PXA2xxFIrState, 3), + VMSTATE_UINT8_ARRAY(status, PXA2xxFIrState, 2), + VMSTATE_UINT32(rx_len, PXA2xxFIrState), + VMSTATE_UINT32(rx_start, PXA2xxFIrState), + VMSTATE_VALIDATE("fifo is 64 bytes", pxa2xx_fir_vmstate_validate), + VMSTATE_UINT8_ARRAY(rx_fifo, PXA2xxFIrState, 64), + VMSTATE_END_OF_LIST() + } +}; + +static Property pxa2xx_fir_properties[] = { + DEFINE_PROP_CHR("chardev", PXA2xxFIrState, chr), + DEFINE_PROP_END_OF_LIST(), +}; + +static void pxa2xx_fir_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = pxa2xx_fir_realize; + dc->vmsd = &pxa2xx_fir_vmsd; + dc->props = pxa2xx_fir_properties; + dc->reset = pxa2xx_fir_reset; +} + +static const TypeInfo pxa2xx_fir_info = { + .name = TYPE_PXA2XX_FIR, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(PXA2xxFIrState), + .class_init = pxa2xx_fir_class_init, + .instance_init = pxa2xx_fir_instance_init, +}; + +static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + hwaddr base, + qemu_irq irq, qemu_irq rx_dma, + qemu_irq tx_dma, + CharDriverState *chr) +{ + DeviceState *dev; + SysBusDevice *sbd; + + dev = qdev_create(NULL, TYPE_PXA2XX_FIR); + qdev_prop_set_chr(dev, "chardev", chr); + qdev_init_nofail(dev); + sbd = SYS_BUS_DEVICE(dev); + sysbus_mmio_map(sbd, 0, base); + sysbus_connect_irq(sbd, 0, irq); + sysbus_connect_irq(sbd, 1, rx_dma); + sysbus_connect_irq(sbd, 2, tx_dma); + return PXA2XX_FIR(dev); } static void pxa2xx_reset(void *opaque, int line, int level) @@ -2323,6 +2353,7 @@ static void pxa2xx_register_types(void) type_register_static(&pxa2xx_ssp_info); type_register_static(&pxa2xx_i2c_info); type_register_static(&pxa2xx_rtc_sysbus_info); + type_register_static(&pxa2xx_fir_info); } type_init(pxa2xx_register_types) From ce3203464bee89d2ae958717222981326a37775e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 14/28] hw/arm/pxa2xx: Add reset method for pxa2xx_ssp The pxa2xx_ssp device was missing a reset method; add one. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1434117989-7367-4-git-send-email-peter.maydell@linaro.org --- hw/arm/pxa2xx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index a015c991fe..4ab24caff9 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -756,6 +756,22 @@ static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void pxa2xx_ssp_reset(DeviceState *d) +{ + PXA2xxSSPState *s = PXA2XX_SSP(d); + + s->enable = 0; + s->sscr[0] = s->sscr[1] = 0; + s->sspsp = 0; + s->ssto = 0; + s->ssitr = 0; + s->sssr = 0; + s->sstsa = 0; + s->ssrsa = 0; + s->ssacd = 0; + s->rx_start = s->rx_level = 0; +} + static int pxa2xx_ssp_init(SysBusDevice *sbd) { DeviceState *dev = DEVICE(sbd); @@ -2336,8 +2352,10 @@ PXA2xxState *pxa255_init(MemoryRegion *address_space, unsigned int sdram_size) static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) { SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); sdc->init = pxa2xx_ssp_init; + dc->reset = pxa2xx_ssp_reset; } static const TypeInfo pxa2xx_ssp_info = { From 8e079caf82c3658ee64bca37c91953b38296d427 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 15/28] hw/arm/pxa2xx: Convert pxa2xx-ssp to VMState The pxa2xx-ssp device is already a QOM device but is still using the old-style register_savevm(); convert to VMState. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1434117989-7367-5-git-send-email-peter.maydell@linaro.org --- hw/arm/pxa2xx.c | 91 ++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 57 deletions(-) diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c index 4ab24caff9..ec353f79c4 100644 --- a/hw/arm/pxa2xx.c +++ b/hw/arm/pxa2xx.c @@ -457,7 +457,7 @@ typedef struct { MemoryRegion iomem; qemu_irq irq; - int enable; + uint32_t enable; SSIBus *bus; uint32_t sscr[2]; @@ -470,10 +470,39 @@ typedef struct { uint8_t ssacd; uint32_t rx_fifo[16]; - int rx_level; - int rx_start; + uint32_t rx_level; + uint32_t rx_start; } PXA2xxSSPState; +static bool pxa2xx_ssp_vmstate_validate(void *opaque, int version_id) +{ + PXA2xxSSPState *s = opaque; + + return s->rx_start < sizeof(s->rx_fifo); +} + +static const VMStateDescription vmstate_pxa2xx_ssp = { + .name = "pxa2xx-ssp", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(enable, PXA2xxSSPState), + VMSTATE_UINT32_ARRAY(sscr, PXA2xxSSPState, 2), + VMSTATE_UINT32(sspsp, PXA2xxSSPState), + VMSTATE_UINT32(ssto, PXA2xxSSPState), + VMSTATE_UINT32(ssitr, PXA2xxSSPState), + VMSTATE_UINT32(sssr, PXA2xxSSPState), + VMSTATE_UINT8(sstsa, PXA2xxSSPState), + VMSTATE_UINT8(ssrsa, PXA2xxSSPState), + VMSTATE_UINT8(ssacd, PXA2xxSSPState), + VMSTATE_UINT32(rx_level, PXA2xxSSPState), + VMSTATE_UINT32(rx_start, PXA2xxSSPState), + VMSTATE_VALIDATE("fifo is 16 bytes", pxa2xx_ssp_vmstate_validate), + VMSTATE_UINT32_ARRAY(rx_fifo, PXA2xxSSPState, 16), + VMSTATE_END_OF_LIST() + } +}; + #define SSCR0 0x00 /* SSP Control register 0 */ #define SSCR1 0x04 /* SSP Control register 1 */ #define SSSR 0x08 /* SSP Status register */ @@ -705,57 +734,6 @@ static const MemoryRegionOps pxa2xx_ssp_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; -static void pxa2xx_ssp_save(QEMUFile *f, void *opaque) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i; - - qemu_put_be32(f, s->enable); - - qemu_put_be32s(f, &s->sscr[0]); - qemu_put_be32s(f, &s->sscr[1]); - qemu_put_be32s(f, &s->sspsp); - qemu_put_be32s(f, &s->ssto); - qemu_put_be32s(f, &s->ssitr); - qemu_put_be32s(f, &s->sssr); - qemu_put_8s(f, &s->sstsa); - qemu_put_8s(f, &s->ssrsa); - qemu_put_8s(f, &s->ssacd); - - qemu_put_byte(f, s->rx_level); - for (i = 0; i < s->rx_level; i ++) - qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]); -} - -static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id) -{ - PXA2xxSSPState *s = (PXA2xxSSPState *) opaque; - int i, v; - - s->enable = qemu_get_be32(f); - - qemu_get_be32s(f, &s->sscr[0]); - qemu_get_be32s(f, &s->sscr[1]); - qemu_get_be32s(f, &s->sspsp); - qemu_get_be32s(f, &s->ssto); - qemu_get_be32s(f, &s->ssitr); - qemu_get_be32s(f, &s->sssr); - qemu_get_8s(f, &s->sstsa); - qemu_get_8s(f, &s->ssrsa); - qemu_get_8s(f, &s->ssacd); - - v = qemu_get_byte(f); - if (v < 0 || v > ARRAY_SIZE(s->rx_fifo)) { - return -EINVAL; - } - s->rx_level = v; - s->rx_start = 0; - for (i = 0; i < s->rx_level; i ++) - s->rx_fifo[i] = qemu_get_byte(f); - - return 0; -} - static void pxa2xx_ssp_reset(DeviceState *d) { PXA2xxSSPState *s = PXA2XX_SSP(d); @@ -782,8 +760,6 @@ static int pxa2xx_ssp_init(SysBusDevice *sbd) memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_ssp_ops, s, "pxa2xx-ssp", 0x1000); sysbus_init_mmio(sbd, &s->iomem); - register_savevm(dev, "pxa2xx_ssp", -1, 0, - pxa2xx_ssp_save, pxa2xx_ssp_load, s); s->bus = ssi_create_bus(dev, "ssi"); return 0; @@ -2006,7 +1982,7 @@ static bool pxa2xx_fir_vmstate_validate(void *opaque, int version_id) { PXA2xxFIrState *s = opaque; - return s->rx_start < sizeof(s->rx_fifo); + return s->rx_start < ARRAY_SIZE(s->rx_fifo); } static const VMStateDescription pxa2xx_fir_vmsd = { @@ -2356,6 +2332,7 @@ static void pxa2xx_ssp_class_init(ObjectClass *klass, void *data) sdc->init = pxa2xx_ssp_init; dc->reset = pxa2xx_ssp_reset; + dc->vmsd = &vmstate_pxa2xx_ssp; } static const TypeInfo pxa2xx_ssp_info = { From 13e1e476b4bc111d36fffaea025f90d8db52b697 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 16/28] hw/sd/pxa2xx_mmci: Stop using old_mmio in MemoryRegionOps Update the pxa2xx_mmci device to stop using the old_mmio read and write callbacks in its MemoryRegionOps. This actually simplifies the code because the separate byte/halfword/word access functions were all calling into a single function to do the work anyway. Signed-off-by: Peter Maydell Reviewed-by: Peter Crosthwaite Message-id: 1434117989-7367-6-git-send-email-peter.maydell@linaro.org --- hw/sd/pxa2xx_mmci.c | 68 ++++++--------------------------------------- 1 file changed, 8 insertions(+), 60 deletions(-) diff --git a/hw/sd/pxa2xx_mmci.c b/hw/sd/pxa2xx_mmci.c index ac3ab39bea..d1fe6d58e8 100644 --- a/hw/sd/pxa2xx_mmci.c +++ b/hw/sd/pxa2xx_mmci.c @@ -48,7 +48,6 @@ struct PXA2xxMMCIState { int resp_len; int cmdreq; - int ac_width; }; #define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */ @@ -215,7 +214,7 @@ static void pxa2xx_mmci_wakequeues(PXA2xxMMCIState *s) pxa2xx_mmci_fifo_update(s); } -static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) +static uint64_t pxa2xx_mmci_read(void *opaque, hwaddr offset, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; uint32_t ret; @@ -257,8 +256,8 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) return 0; case MMC_RXFIFO: ret = 0; - while (s->ac_width -- && s->rx_len) { - ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3); + while (size-- && s->rx_len) { + ret |= s->rx_fifo[s->rx_start++] << (size << 3); s->rx_start &= 0x1f; s->rx_len --; } @@ -277,7 +276,7 @@ static uint32_t pxa2xx_mmci_read(void *opaque, hwaddr offset) } static void pxa2xx_mmci_write(void *opaque, - hwaddr offset, uint32_t value) + hwaddr offset, uint64_t value, unsigned size) { PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; @@ -370,9 +369,9 @@ static void pxa2xx_mmci_write(void *opaque, break; case MMC_TXFIFO: - while (s->ac_width -- && s->tx_len < 0x20) + while (size-- && s->tx_len < 0x20) s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] = - (value >> (s->ac_width << 3)) & 0xff; + (value >> (size << 3)) & 0xff; s->intreq &= ~INT_TXFIFO_REQ; pxa2xx_mmci_fifo_update(s); break; @@ -386,60 +385,9 @@ static void pxa2xx_mmci_write(void *opaque, } } -static uint32_t pxa2xx_mmci_readb(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 1; - return pxa2xx_mmci_read(opaque, offset); -} - -static uint32_t pxa2xx_mmci_readh(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 2; - return pxa2xx_mmci_read(opaque, offset); -} - -static uint32_t pxa2xx_mmci_readw(void *opaque, hwaddr offset) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 4; - return pxa2xx_mmci_read(opaque, offset); -} - -static void pxa2xx_mmci_writeb(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 1; - pxa2xx_mmci_write(opaque, offset, value); -} - -static void pxa2xx_mmci_writeh(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 2; - pxa2xx_mmci_write(opaque, offset, value); -} - -static void pxa2xx_mmci_writew(void *opaque, - hwaddr offset, uint32_t value) -{ - PXA2xxMMCIState *s = (PXA2xxMMCIState *) opaque; - s->ac_width = 4; - pxa2xx_mmci_write(opaque, offset, value); -} - static const MemoryRegionOps pxa2xx_mmci_ops = { - .old_mmio = { - .read = { pxa2xx_mmci_readb, - pxa2xx_mmci_readh, - pxa2xx_mmci_readw, }, - .write = { pxa2xx_mmci_writeb, - pxa2xx_mmci_writeh, - pxa2xx_mmci_writew, }, - }, + .read = pxa2xx_mmci_read, + .write = pxa2xx_mmci_write, .endianness = DEVICE_NATIVE_ENDIAN, }; From 62b44f059a84d1ac580a653fc4110dfabaef6b83 Mon Sep 17 00:00:00 2001 From: "Aurelio C. Remonda" Date: Mon, 15 Jun 2015 18:06:09 +0100 Subject: [PATCH 17/28] target-arm: Add the THUMB_DSP feature Create an ARM_FEATURE_THUMB_DSP controlling the Thumb encodings of the 85 DSP instructions (these are all Thumb2). This is enabled for all non-M-profile CPUs with Thumb2 support, as the instructions are mandatory for R and A profiles. On M profile they are optional and not present in the Cortex-M3 (though they are in the M4). The effect of this commit is that we will now treat the DSP encodings as illegal instructions on M3, when previously we incorrectly implemented them. Signed-off-by: Aurelio C. Remonda Message-id: 1434311355-26554-1-git-send-email-aurelioremonda@gmail.com [PMM: added clz/crc32/crc32c and default case to the early-decode switch; minor format/spacing fixups; reworded commit message a bit] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu.c | 4 ++ target-arm/cpu.h | 1 + target-arm/translate.c | 112 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 107 insertions(+), 10 deletions(-) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 34990acb82..6fa51f4446 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -545,6 +545,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) if (arm_feature(env, ARM_FEATURE_CBAR_RO)) { set_feature(env, ARM_FEATURE_CBAR); } + if (arm_feature(env, ARM_FEATURE_THUMB2) && + !arm_feature(env, ARM_FEATURE_M)) { + set_feature(env, ARM_FEATURE_THUMB_DSP); + } if (cpu->reset_hivecs) { cpu->reset_sctlr |= (1 << 13); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 7c1d95c815..c9d2330014 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -889,6 +889,7 @@ enum arm_features { ARM_FEATURE_V8_SHA1, /* implements SHA1 part of v8 Crypto Extensions */ ARM_FEATURE_V8_SHA256, /* implements SHA256 part of v8 Crypto Extensions */ ARM_FEATURE_V8_PMULL, /* implements PMULL part of v8 Crypto Extensions */ + ARM_FEATURE_THUMB_DSP, /* DSP insns supported in the Thumb encodings */ }; static inline int arm_feature(CPUARMState *env, int feature) diff --git a/target-arm/translate.c b/target-arm/translate.c index 39692d7a8e..125b6da165 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -9444,6 +9444,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw op = (insn >> 21) & 0xf; if (op == 6) { + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } /* Halfword pack. */ tmp = load_reg(s, rn); tmp2 = load_reg(s, rm); @@ -9508,6 +9511,27 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw store_reg_bx(s, rd, tmp); break; case 1: /* Sign/zero extend. */ + op = (insn >> 20) & 7; + switch (op) { + case 0: /* SXTAH, SXTH */ + case 1: /* UXTAH, UXTH */ + case 4: /* SXTAB, SXTB */ + case 5: /* UXTAB, UXTB */ + break; + case 2: /* SXTAB16, SXTB16 */ + case 3: /* UXTAB16, UXTB16 */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } + break; + default: + goto illegal_op; + } + if (rn != 15) { + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } + } tmp = load_reg(s, rm); shift = (insn >> 4) & 3; /* ??? In many cases it's not necessary to do a @@ -9522,7 +9546,8 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw case 3: gen_uxtb16(tmp); break; case 4: gen_sxtb(tmp); break; case 5: gen_uxtb(tmp); break; - default: goto illegal_op; + default: + g_assert_not_reached(); } if (rn != 15) { tmp2 = load_reg(s, rn); @@ -9536,6 +9561,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw store_reg(s, rd, tmp); break; case 2: /* SIMD add/subtract. */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } op = (insn >> 20) & 7; shift = (insn >> 4) & 7; if ((op & 3) == 3 || (shift & 3) == 3) @@ -9550,6 +9578,9 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw op = ((insn >> 17) & 0x38) | ((insn >> 4) & 7); if (op < 4) { /* Saturating add/subtract. */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } tmp = load_reg(s, rn); tmp2 = load_reg(s, rm); if (op & 1) @@ -9560,6 +9591,31 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2); tcg_temp_free_i32(tmp2); } else { + switch (op) { + case 0x0a: /* rbit */ + case 0x08: /* rev */ + case 0x09: /* rev16 */ + case 0x0b: /* revsh */ + case 0x18: /* clz */ + break; + case 0x10: /* sel */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } + break; + case 0x20: /* crc32/crc32c */ + case 0x21: + case 0x22: + case 0x28: + case 0x29: + case 0x2a: + if (!arm_dc_feature(s, ARM_FEATURE_CRC)) { + goto illegal_op; + } + break; + default: + goto illegal_op; + } tmp = load_reg(s, rn); switch (op) { case 0x0a: /* rbit */ @@ -9596,10 +9652,6 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw uint32_t sz = op & 0x3; uint32_t c = op & 0x8; - if (!arm_dc_feature(s, ARM_FEATURE_CRC)) { - goto illegal_op; - } - tmp2 = load_reg(s, rm); if (sz == 0) { tcg_gen_andi_i32(tmp2, tmp2, 0xff); @@ -9617,12 +9669,26 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw break; } default: - goto illegal_op; + g_assert_not_reached(); } } store_reg(s, rd, tmp); break; case 4: case 5: /* 32-bit multiply. Sum of absolute differences. */ + switch ((insn >> 20) & 7) { + case 0: /* 32 x 32 -> 32 */ + case 7: /* Unsigned sum of absolute differences. */ + break; + case 1: /* 16 x 16 -> 32 */ + case 2: /* Dual multiply add. */ + case 3: /* 32 * 16 -> 32msb */ + case 4: /* Dual multiply subtract. */ + case 5: case 6: /* 32 * 32 -> 32msb (SMMUL, SMMLA, SMMLS) */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + goto illegal_op; + } + break; + } op = (insn >> 4) & 0xf; tmp = load_reg(s, rn); tmp2 = load_reg(s, rm); @@ -9735,6 +9801,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw store_reg(s, rd, tmp); } else if ((op & 0xe) == 0xc) { /* Dual multiply accumulate long. */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(tmp2); + goto illegal_op; + } if (op & 1) gen_swap_half(tmp2); gen_smul_dual(tmp, tmp2); @@ -9758,6 +9829,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw } else { if (op & 8) { /* smlalxy */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + tcg_temp_free_i32(tmp2); + tcg_temp_free_i32(tmp); + goto illegal_op; + } gen_mulxy(tmp, tmp2, op & 2, op & 1); tcg_temp_free_i32(tmp2); tmp64 = tcg_temp_new_i64(); @@ -9770,6 +9846,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw } if (op & 4) { /* umaal */ + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + tcg_temp_free_i64(tmp64); + goto illegal_op; + } gen_addq_lo(s, tmp64, rs); gen_addq_lo(s, tmp64, rd); } else if (op & 0x40) { @@ -10034,16 +10114,28 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw tmp2 = tcg_const_i32(imm); if (op & 4) { /* Unsigned. */ - if ((op & 1) && shift == 0) + if ((op & 1) && shift == 0) { + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(tmp2); + goto illegal_op; + } gen_helper_usat16(tmp, cpu_env, tmp, tmp2); - else + } else { gen_helper_usat(tmp, cpu_env, tmp, tmp2); + } } else { /* Signed. */ - if ((op & 1) && shift == 0) + if ((op & 1) && shift == 0) { + if (!arm_dc_feature(s, ARM_FEATURE_THUMB_DSP)) { + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(tmp2); + goto illegal_op; + } gen_helper_ssat16(tmp, cpu_env, tmp, tmp2); - else + } else { gen_helper_ssat(tmp, cpu_env, tmp, tmp2); + } } tcg_temp_free_i32(tmp2); break; From 8085ce63c5967d200f1241b6c0a189371993c5df Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 18/28] arm: Do not define TLBTR in PMSA systems If doing a PMSA (MPU) system do not define the VMSA specific TLBTR CP. The def is done separately from VMSA registers group as it is affected by both the OMAP/STRONGARM RW errata and the MIDR backgrounding. Signed-off-by: Peter Crosthwaite Message-id: b03fea3840207edf633f5c9189400c3dd6a28d14.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 6a62d798c2..d46db91448 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3448,11 +3448,14 @@ void register_cp_regs_for_features(ARMCPU *cpu) { .name = "TCMTR", .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 2, .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, - { .name = "TLBTR", - .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3, - .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0 }, REGINFO_SENTINEL }; + /* TLBTR is specific to VMSA */ + ARMCPRegInfo id_tlbtr_reginfo = { + .name = "TLBTR", + .cp = 15, .crn = 0, .crm = 0, .opc1 = 0, .opc2 = 3, + .access = PL1_R, .type = ARM_CP_CONST, .resetvalue = 0, + }; ARMCPRegInfo crn0_wi_reginfo = { .name = "CRN0_WI", .cp = 15, .crn = 0, .crm = CP_ANY, .opc1 = CP_ANY, .opc2 = CP_ANY, .access = PL1_W, @@ -3474,6 +3477,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) for (r = id_cp_reginfo; r->type != ARM_CP_SENTINEL; r++) { r->access = PL1_RW; } + id_tlbtr_reginfo.access = PL1_RW; } if (arm_feature(env, ARM_FEATURE_V8)) { define_arm_cp_regs(cpu, id_v8_midr_cp_reginfo); @@ -3481,6 +3485,9 @@ void register_cp_regs_for_features(ARMCPU *cpu) define_arm_cp_regs(cpu, id_pre_v8_midr_cp_reginfo); } define_arm_cp_regs(cpu, id_cp_reginfo); + if (!arm_feature(env, ARM_FEATURE_MPU)) { + define_one_arm_cp_reg(cpu, &id_tlbtr_reginfo); + } } if (arm_feature(env, ARM_FEATURE_MPIDR)) { From 5e5cf9e35f25f9f932a6ce25107c11b67b426a43 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 19/28] arm: Don't add v7mp registers in MPU systems These registers are VMSA specific so they should be conditional on VMSA (i.e. !MPU). Signed-off-by: Peter Crosthwaite Message-id: 7bb8843e45f2635c6b7a583c5bb5da51ed4442a0.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index d46db91448..c8cb97089f 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -3193,7 +3193,8 @@ void register_cp_regs_for_features(ARMCPU *cpu) if (arm_feature(env, ARM_FEATURE_V6K)) { define_arm_cp_regs(cpu, v6k_cp_reginfo); } - if (arm_feature(env, ARM_FEATURE_V7MP)) { + if (arm_feature(env, ARM_FEATURE_V7MP) && + !arm_feature(env, ARM_FEATURE_MPU)) { define_arm_cp_regs(cpu, v7mp_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_V7)) { From 8e5d75c950a1241f6e1243c37f28cd58f68fedc9 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 20/28] arm: helper: Factor out CP regs common to [pv]msa V6+ PMSA and VMSA share some common registers that are currently in the VMSA definition block. Split them out into a new def that can be shared to PMSA. Signed-off-by: Peter Crosthwaite Message-id: 284db78a43c63c9bfbb60de539672c361bcb6af8.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index c8cb97089f..66ce9123ce 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -1846,7 +1846,7 @@ static void vmsa_ttbr_write(CPUARMState *env, const ARMCPRegInfo *ri, raw_write(env, ri, value); } -static const ARMCPRegInfo vmsa_cp_reginfo[] = { +static const ARMCPRegInfo vmsa_pmsa_cp_reginfo[] = { { .name = "DFSR", .cp = 15, .crn = 5, .crm = 0, .opc1 = 0, .opc2 = 0, .access = PL1_RW, .type = ARM_CP_ALIAS, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.dfsr_s), @@ -1856,6 +1856,18 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .access = PL1_RW, .resetvalue = 0, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.ifsr_s), offsetoflow32(CPUARMState, cp15.ifsr_ns) } }, + { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0, + .access = PL1_RW, .resetvalue = 0, + .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s), + offsetof(CPUARMState, cp15.dfar_ns) } }, + { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, + .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), + .resetvalue = 0, }, + REGINFO_SENTINEL +}; + +static const ARMCPRegInfo vmsa_cp_reginfo[] = { { .name = "ESR_EL1", .state = ARM_CP_STATE_AA64, .opc0 = 3, .crn = 5, .crm = 2, .opc1 = 0, .opc2 = 0, .access = PL1_RW, @@ -1880,14 +1892,6 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = { .resetfn = arm_cp_reset_ignore, .raw_writefn = vmsa_ttbcr_raw_write, .bank_fieldoffsets = { offsetoflow32(CPUARMState, cp15.tcr_el[3]), offsetoflow32(CPUARMState, cp15.tcr_el[1])} }, - { .name = "FAR_EL1", .state = ARM_CP_STATE_AA64, - .opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, - .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]), - .resetvalue = 0, }, - { .name = "DFAR", .cp = 15, .opc1 = 0, .crn = 6, .crm = 0, .opc2 = 0, - .access = PL1_RW, .resetvalue = 0, - .bank_fieldoffsets = { offsetof(CPUARMState, cp15.dfar_s), - offsetof(CPUARMState, cp15.dfar_ns) } }, REGINFO_SENTINEL }; @@ -3346,6 +3350,7 @@ void register_cp_regs_for_features(ARMCPU *cpu) assert(!arm_feature(env, ARM_FEATURE_V6)); define_arm_cp_regs(cpu, pmsav5_cp_reginfo); } else { + define_arm_cp_regs(cpu, vmsa_pmsa_cp_reginfo); define_arm_cp_regs(cpu, vmsa_cp_reginfo); } if (arm_feature(env, ARM_FEATURE_THUMB2EE)) { From b7cc4e82f04a1c5b218a657f677a2fdd1e1c2889 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 21/28] arm: Refactor get_phys_addr FSR return mechanism Currently, the return code for get_phys_addr is overloaded for both success/fail and FSR value return. This doesn't handle the case where there is an error with a 0 FSR. This case exists in PMSAv7. So rework get_phys_addr and friends to return a success/failure boolean return code and populate the FSR via a caller provided uint32_t pointer. Signed-off-by: Peter Crosthwaite Message-id: a209e3d8ae00cda55260c970891f520210e26bad.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/helper.c | 128 ++++++++++++++++++++++------------------- target-arm/internals.h | 3 +- target-arm/op_helper.c | 11 ++-- 3 files changed, 78 insertions(+), 64 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index 66ce9123ce..f51dece2fe 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -12,10 +12,10 @@ #include /* For crc32 */ #ifndef CONFIG_USER_ONLY -static inline int get_phys_addr(CPUARMState *env, target_ulong address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size); +static inline bool get_phys_addr(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, uint32_t *fsr); /* Definitions for the PMCCNTR and PMCR registers */ #define PMCRD 0x8 @@ -1495,19 +1495,20 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, hwaddr phys_addr; target_ulong page_size; int prot; - int ret; + uint32_t fsr; + bool ret; uint64_t par64; MemTxAttrs attrs = {}; ret = get_phys_addr(env, value, access_type, mmu_idx, - &phys_addr, &attrs, &prot, &page_size); + &phys_addr, &attrs, &prot, &page_size, &fsr); if (extended_addresses_enabled(env)) { - /* ret is a DFSR/IFSR value for the long descriptor + /* fsr is a DFSR/IFSR value for the long descriptor * translation table format, but with WnR always clear. * Convert it to a 64-bit PAR. */ par64 = (1 << 11); /* LPAE bit always set */ - if (ret == 0) { + if (!ret) { par64 |= phys_addr & ~0xfffULL; if (!attrs.secure) { par64 |= (1 << 9); /* NS */ @@ -1515,18 +1516,18 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, /* We don't set the ATTR or SH fields in the PAR. */ } else { par64 |= 1; /* F */ - par64 |= (ret & 0x3f) << 1; /* FS */ + par64 |= (fsr & 0x3f) << 1; /* FS */ /* Note that S2WLK and FSTAGE are always zero, because we don't * implement virtualization and therefore there can't be a stage 2 * fault. */ } } else { - /* ret is a DFSR/IFSR value for the short descriptor + /* fsr is a DFSR/IFSR value for the short descriptor * translation table format (with WnR always clear). * Convert it to a 32-bit PAR. */ - if (ret == 0) { + if (!ret) { /* We do not set any attribute bits in the PAR */ if (page_size == (1 << 24) && arm_feature(env, ARM_FEATURE_V7)) { @@ -1538,8 +1539,8 @@ static uint64_t do_ats_write(CPUARMState *env, uint64_t value, par64 |= (1 << 9); /* NS */ } } else { - par64 = ((ret & (1 << 10)) >> 5) | ((ret & (1 << 12)) >> 6) | - ((ret & 0xf) << 1) | 1; + par64 = ((fsr & (1 << 10)) >> 5) | ((fsr & (1 << 12)) >> 6) | + ((fsr & 0xf) << 1) | 1; } } return par64; @@ -5242,9 +5243,10 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure) return address_space_ldq(cs->as, addr, attrs, NULL); } -static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, - ARMMMUIdx mmu_idx, hwaddr *phys_ptr, - int *prot, target_ulong *page_size) +static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, + target_ulong *page_size, uint32_t *fsr) { CPUState *cs = CPU(arm_env_get_cpu(env)); int code; @@ -5348,15 +5350,16 @@ static int get_phys_addr_v5(CPUARMState *env, uint32_t address, int access_type, goto do_fault; } *phys_ptr = phys_addr; - return 0; + return false; do_fault: - return code | (domain << 4); + *fsr = code | (domain << 4); + return true; } -static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, - ARMMMUIdx mmu_idx, hwaddr *phys_ptr, - MemTxAttrs *attrs, - int *prot, target_ulong *page_size) +static bool get_phys_addr_v6(CPUARMState *env, uint32_t address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, uint32_t *fsr) { CPUState *cs = CPU(arm_env_get_cpu(env)); int code; @@ -5489,9 +5492,10 @@ static int get_phys_addr_v6(CPUARMState *env, uint32_t address, int access_type, attrs->secure = false; } *phys_ptr = phys_addr; - return 0; + return false; do_fault: - return code | (domain << 4); + *fsr = code | (domain << 4); + return true; } /* Fault type for long-descriptor MMU fault reporting; this corresponds @@ -5503,10 +5507,10 @@ typedef enum { permission_fault = 3, } MMUFaultType; -static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, - target_ulong *page_size_ptr) +static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *txattrs, int *prot, + target_ulong *page_size_ptr, uint32_t *fsr) { CPUState *cs = CPU(arm_env_get_cpu(env)); /* Read an LPAE long-descriptor translation table. */ @@ -5745,16 +5749,17 @@ static int get_phys_addr_lpae(CPUARMState *env, target_ulong address, } *phys_ptr = descaddr; *page_size_ptr = page_size; - return 0; + return false; do_fault: /* Long-descriptor format IFSR/DFSR value */ - return (1 << 9) | (fault_type << 2) | level; + *fsr = (1 << 9) | (fault_type << 2) | level; + return true; } -static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot) +static bool get_phys_addr_mpu(CPUARMState *env, uint32_t address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, uint32_t *fsr) { int n; uint32_t mask; @@ -5776,7 +5781,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, } } if (n < 0) { - return 2; + *fsr = 2; + return true; } if (access_type == 2) { @@ -5787,10 +5793,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, mask = (mask >> (n * 4)) & 0xf; switch (mask) { case 0: - return 1; + *fsr = 1; + return true; case 1: if (is_user) { - return 1; + *fsr = 1; + return true; } *prot = PAGE_READ | PAGE_WRITE; break; @@ -5805,7 +5813,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, break; case 5: if (is_user) { - return 1; + *fsr = 1; + return true; } *prot = PAGE_READ; break; @@ -5814,10 +5823,11 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, break; default: /* Bad permission. */ - return 1; + *fsr = 1; + return true; } *prot |= PAGE_EXEC; - return 0; + return false; } /* get_phys_addr - get the physical address for this virtual address @@ -5826,8 +5836,8 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, * by doing a translation table walk on MMU based systems or using the * MPU state on MPU based systems. * - * Returns 0 if the translation was successful. Otherwise, phys_ptr, attrs, - * prot and page_size may not be filled in, and the return value provides + * Returns false if the translation was successful. Otherwise, phys_ptr, attrs, + * prot and page_size may not be filled in, and the populated fsr value provides * information on why the translation aborted, in the format of a * DFSR/IFSR fault register, with the following caveats: * * we honour the short vs long DFSR format differences. @@ -5843,11 +5853,12 @@ static int get_phys_addr_mpu(CPUARMState *env, uint32_t address, * @attrs: set to the memory transaction attributes to use * @prot: set to the permissions for the page containing phys_ptr * @page_size: set to the size of the page containing phys_ptr + * @fsr: set to the DFSR/IFSR value on failure */ -static inline int get_phys_addr(CPUARMState *env, target_ulong address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, - target_ulong *page_size) +static inline bool get_phys_addr(CPUARMState *env, target_ulong address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, MemTxAttrs *attrs, int *prot, + target_ulong *page_size, uint32_t *fsr) { if (mmu_idx == ARMMMUIdx_S12NSE0 || mmu_idx == ARMMMUIdx_S12NSE1) { /* TODO: when we support EL2 we should here call ourselves recursively @@ -5890,27 +5901,27 @@ static inline int get_phys_addr(CPUARMState *env, target_ulong address, if (arm_feature(env, ARM_FEATURE_MPU)) { *page_size = TARGET_PAGE_SIZE; return get_phys_addr_mpu(env, address, access_type, mmu_idx, phys_ptr, - prot); + prot, fsr); } if (regime_using_lpae_format(env, mmu_idx)) { return get_phys_addr_lpae(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size); + attrs, prot, page_size, fsr); } else if (regime_sctlr(env, mmu_idx) & SCTLR_XP) { return get_phys_addr_v6(env, address, access_type, mmu_idx, phys_ptr, - attrs, prot, page_size); + attrs, prot, page_size, fsr); } else { return get_phys_addr_v5(env, address, access_type, mmu_idx, phys_ptr, - prot, page_size); + prot, page_size, fsr); } } /* Walk the page table and (if the mapping exists) add the page - * to the TLB. Return 0 on success, or an ARM DFSR/IFSR fault - * register format value on failure. + * to the TLB. Return false on success, or true on failure. Populate + * fsr with ARM DFSR/IFSR fault register format value on failure. */ -int arm_tlb_fill(CPUState *cs, vaddr address, - int access_type, int mmu_idx) +bool arm_tlb_fill(CPUState *cs, vaddr address, + int access_type, int mmu_idx, uint32_t *fsr) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -5921,8 +5932,8 @@ int arm_tlb_fill(CPUState *cs, vaddr address, MemTxAttrs attrs = {}; ret = get_phys_addr(env, address, access_type, mmu_idx, &phys_addr, - &attrs, &prot, &page_size); - if (ret == 0) { + &attrs, &prot, &page_size, fsr); + if (!ret) { /* Map a single [sub]page. */ phys_addr &= TARGET_PAGE_MASK; address &= TARGET_PAGE_MASK; @@ -5941,13 +5952,14 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) hwaddr phys_addr; target_ulong page_size; int prot; - int ret; + bool ret; + uint32_t fsr; MemTxAttrs attrs = {}; ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env), &phys_addr, - &attrs, &prot, &page_size); + &attrs, &prot, &page_size, &fsr); - if (ret != 0) { + if (ret) { return -1; } diff --git a/target-arm/internals.h b/target-arm/internals.h index 1e5071ea72..924aff9d04 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -388,6 +388,7 @@ void arm_handle_psci_call(ARMCPU *cpu); #endif /* Do a page table walk and add page to TLB if possible */ -int arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx); +bool arm_tlb_fill(CPUState *cpu, vaddr address, int rw, int mmu_idx, + uint32_t *fsr); #endif diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index 7583ae7121..7fa32c4707 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -81,9 +81,10 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, uintptr_t retaddr) { - int ret; + bool ret; + uint32_t fsr = 0; - ret = arm_tlb_fill(cs, addr, is_write, mmu_idx); + ret = arm_tlb_fill(cs, addr, is_write, mmu_idx, &fsr); if (unlikely(ret)) { ARMCPU *cpu = ARM_CPU(cs); CPUARMState *env = &cpu->env; @@ -96,7 +97,7 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, } /* AArch64 syndrome does not have an LPAE bit */ - syn = ret & ~(1 << 9); + syn = fsr & ~(1 << 9); /* For insn and data aborts we assume there is no instruction syndrome * information; this is always true for exceptions reported to EL1. @@ -107,13 +108,13 @@ void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx, } else { syn = syn_data_abort(same_el, 0, 0, 0, is_write == 1, syn); if (is_write == 1 && arm_feature(env, ARM_FEATURE_V6)) { - ret |= (1 << 11); + fsr |= (1 << 11); } exc = EXCP_DATA_ABORT; } env->exception.vaddress = addr; - env->exception.fsr = ret; + env->exception.fsr = fsr; raise_exception(env, exc, syn, exception_target_el(env)); } } From a8e81b319d1ae1224cc7059877dcdf04a5aad59d Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 22/28] arm: Implement uniprocessor with MP config Add a boolean for indicating uniprocessors with MP extensions. This drives the U bit in MPIDR. Prepares support for Cortex-R5. Signed-off-by: Peter Crosthwaite Message-id: a70a80583df265e0174f01fa1fc92b33ea6d1db5.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 3 +++ target-arm/helper.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 24a4cfb1ae..57b4a12069 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -116,6 +116,9 @@ typedef struct ARMCPU { /* KVM init features for this CPU */ uint32_t kvm_init_features[7]; + /* Uniprocessor system with MP extensions */ + bool mp_is_up; + /* The instance init functions for implementation-specific subclasses * set these fields to specify the implementation-dependent values of * various constant registers and reset values of non-constant diff --git a/target-arm/helper.c b/target-arm/helper.c index f51dece2fe..f038a03a6c 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2075,9 +2075,11 @@ static uint64_t mpidr_read(CPUARMState *env, const ARMCPRegInfo *ri) mpidr |= (1U << 31); /* Cores which are uniprocessor (non-coherent) * but still implement the MP extensions set - * bit 30. (For instance, A9UP.) However we do - * not currently model any of those cores. + * bit 30. (For instance, Cortex-R5). */ + if (cpu->mp_is_up) { + mpidr |= (1u << 30); + } } return mpidr; } From 8f325f568fbd0158cd413e7d637573ba90b3eaab Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 23/28] arm: Add has-mpu property For processors that support MPUs, add a property to de-feature it. This is similar to the implementation of the EL3 feature. The processor definition in init sets ARM_FEATURE_MPU if it can support an MPU. post_init exposes the property, defaulting to true. If cleared by the instantiator, ARM_FEATURE_MPU is then removed at realize time. This is to support R profile processors that may or may-not have an MPU configured. Signed-off-by: Peter Crosthwaite Message-id: 632918cc48786e868ea18aa6bd12f70597994cad.1434066412.git.peter.crosthwaite@xilinx.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- target-arm/cpu-qom.h | 3 +++ target-arm/cpu.c | 13 +++++++++++++ 2 files changed, 16 insertions(+) diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h index 57b4a12069..072aa9baa7 100644 --- a/target-arm/cpu-qom.h +++ b/target-arm/cpu-qom.h @@ -103,6 +103,9 @@ typedef struct ARMCPU { /* CPU has security extension */ bool has_el3; + /* CPU has memory protection unit */ + bool has_mpu; + /* PSCI conduit used to invoke PSCI methods * 0 - disabled, 1 - smc, 2 - hvc */ diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 6fa51f4446..7496983b42 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -454,6 +454,9 @@ static Property arm_cpu_rvbar_property = static Property arm_cpu_has_el3_property = DEFINE_PROP_BOOL("has_el3", ARMCPU, has_el3, true); +static Property arm_cpu_has_mpu_property = + DEFINE_PROP_BOOL("has-mpu", ARMCPU, has_mpu, true); + static void arm_cpu_post_init(Object *obj) { ARMCPU *cpu = ARM_CPU(obj); @@ -481,6 +484,12 @@ static void arm_cpu_post_init(Object *obj) qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property, &error_abort); } + + if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) { + qdev_property_add_static(DEVICE(obj), &arm_cpu_has_mpu_property, + &error_abort); + } + } static void arm_cpu_finalizefn(Object *obj) @@ -567,6 +576,10 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) cpu->id_aa64pfr0 &= ~0xf000; } + if (!cpu->has_mpu) { + unset_feature(env, ARM_FEATURE_MPU); + } + register_cp_regs_for_features(cpu); arm_cpu_register_gdb_regs_for_features(cpu); From 13689d43646482f7305282de1bdd662c0d2b8b77 Mon Sep 17 00:00:00 2001 From: Peter Crosthwaite Date: Mon, 15 Jun 2015 18:06:10 +0100 Subject: [PATCH 24/28] arm: helper: rename get_phys_addr_mpu This get_phys_addr is really for pmsav5. Rename it accordingly. Reviewed-by: Peter Maydell Signed-off-by: Peter Crosthwaite Message-id: bf4b019aa87d682a45998105ef8e4d4e97a5e117.1434066412.git.peter.crosthwaite@xilinx.com Signed-off-by: Peter Maydell --- target-arm/helper.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/target-arm/helper.c b/target-arm/helper.c index f038a03a6c..00509b1382 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -5759,9 +5759,9 @@ do_fault: return true; } -static bool get_phys_addr_mpu(CPUARMState *env, uint32_t address, - int access_type, ARMMMUIdx mmu_idx, - hwaddr *phys_ptr, int *prot, uint32_t *fsr) +static bool get_phys_addr_pmsav5(CPUARMState *env, uint32_t address, + int access_type, ARMMMUIdx mmu_idx, + hwaddr *phys_ptr, int *prot, uint32_t *fsr) { int n; uint32_t mask; @@ -5902,8 +5902,8 @@ static inline bool get_phys_addr(CPUARMState *env, target_ulong address, if (arm_feature(env, ARM_FEATURE_MPU)) { *page_size = TARGET_PAGE_SIZE; - return get_phys_addr_mpu(env, address, access_type, mmu_idx, phys_ptr, - prot, fsr); + return get_phys_addr_pmsav5(env, address, access_type, mmu_idx, + phys_ptr, prot, fsr); } if (regime_using_lpae_format(env, mmu_idx)) { From 63a183ed0eac2956574745c84faffa042d99afb8 Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Mon, 15 Jun 2015 18:06:11 +0100 Subject: [PATCH 25/28] hw/arm/boot: fix rom_reset notifier registration order commit ac9d32e39664e060cd1b538ff190980d57ad69e4 had the consequence to register the do_cpu_reset after the rom_reset one. Hence they get executed in the wrong order. This commit restores the registration of do_cpu_reset in arm_load_kernel. Signed-off-by: Eric Auger Reported-by: Peter Crosthwaite Reviewed-by: Peter Crosthwaite Tested-by: Peter Crosthwaite Message-id: 1434111582-9325-1-git-send-email-eric.auger@linaro.org Signed-off-by: Peter Maydell --- hw/arm/boot.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hw/arm/boot.c b/hw/arm/boot.c index d036624948..1e7fd28daa 100644 --- a/hw/arm/boot.c +++ b/hw/arm/boot.c @@ -574,15 +574,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) struct arm_boot_info *info = container_of(n, struct arm_boot_info, load_kernel_notifier); - /* CPU objects (unlike devices) are not automatically reset on system - * reset, so we must always register a handler to do so. If we're - * actually loading a kernel, the handler is also responsible for - * arranging that we start it correctly. - */ - for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { - qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); - } - /* Load the kernel. */ if (!info->kernel_filename || info->firmware_loaded) { @@ -783,7 +774,18 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data) void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) { + CPUState *cs; + info->load_kernel_notifier.cpu = cpu; info->load_kernel_notifier.notifier.notify = arm_load_kernel_notify; qemu_add_machine_init_done_notifier(&info->load_kernel_notifier.notifier); + + /* CPU objects (unlike devices) are not automatically reset on system + * reset, so we must always register a handler to do so. If we're + * actually loading a kernel, the handler is also responsible for + * arranging that we start it correctly. + */ + for (cs = CPU(cpu); cs; cs = CPU_NEXT(cs)) { + qemu_register_reset(do_cpu_reset, ARM_CPU(cs)); + } } From 3977ee5d7a9f2e3664dd8b233f3224694e23b62b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Mon, 15 Jun 2015 18:06:11 +0100 Subject: [PATCH 26/28] target-arm: Correct "preferred return address" for cpreg access exceptions The architecture defines that when taking an exception trying to access a coprocessor register, the "preferred return address" for the exception is the address of the instruction that caused the exception. Correct an off-by-4 error which meant we were returning the address after the instruction for traps which happened because of a failure of a runtime access-check function on an AArch32 register. (Traps caused by translate-time checkable permissions failures had the correct address, as did traps on AArch64 registers.) This fixes https://bugs.launchpad.net/qemu/+bug/1463338 Reported-by: Robert Buhren Signed-off-by: Peter Maydell Message-id: 1433861440-30133-1-git-send-email-peter.maydell@linaro.org --- target-arm/translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target-arm/translate.c b/target-arm/translate.c index 125b6da165..ead08f4820 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -7175,7 +7175,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) break; } - gen_set_pc_im(s, s->pc); + gen_set_pc_im(s, s->pc - 4); tmpptr = tcg_const_ptr(ri); tcg_syn = tcg_const_i32(syndrome); gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn); From b8a0d75ef85b8f24c92a6c50817fa9579b4a98d9 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 Jun 2015 18:06:11 +0100 Subject: [PATCH 27/28] ACPI: Add definitions for the SPCR table SPCR is the Serial Port Console Redirection Table. See the document linked from http://uefi.org/acpi. For serial port types, "Interface Type", see the documentation for the Debug Port Table 2 (DBG2). Signed-off-by: Andrew Jones Tested-by: Shannon Zhao Reviewed-by: Igor Mammedov Acked-by: Michael S. Tsirkin Message-id: 1433929959-29530-2-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- include/hw/acpi/acpi-defs.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/hw/acpi/acpi-defs.h b/include/hw/acpi/acpi-defs.h index 59cf277434..7b4bfb7494 100644 --- a/include/hw/acpi/acpi-defs.h +++ b/include/hw/acpi/acpi-defs.h @@ -196,6 +196,38 @@ enum { ACPI_FADT_ARM_PSCI_USE_HVC = 1, }; +/* + * Serial Port Console Redirection Table (SPCR), Rev. 1.02 + * + * For .interface_type see Debug Port Table 2 (DBG2) serial port + * subtypes in Table 3, Rev. May 22, 2012 + */ +struct AcpiSerialPortConsoleRedirection { + ACPI_TABLE_HEADER_DEF + uint8_t interface_type; + uint8_t reserved1[3]; + struct AcpiGenericAddress base_address; + uint8_t interrupt_types; + uint8_t irq; + uint32_t gsi; + uint8_t baud; + uint8_t parity; + uint8_t stopbits; + uint8_t flowctrl; + uint8_t term_type; + uint8_t reserved2; + uint16_t pci_device_id; + uint16_t pci_vendor_id; + uint8_t pci_bus; + uint8_t pci_slot; + uint8_t pci_func; + uint32_t pci_flags; + uint8_t pci_seg; + uint32_t reserved3; +} QEMU_PACKED; +typedef struct AcpiSerialPortConsoleRedirection + AcpiSerialPortConsoleRedirection; + /* * ACPI 1.0 Root System Description Table (RSDT) */ From f264d51d8ad939d7fb339d61a8cf680ed0cb21a2 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 15 Jun 2015 18:06:11 +0100 Subject: [PATCH 28/28] hw/arm/virt-acpi-build: Add SPCR table Signed-off-by: Andrew Jones Tested-by: Shannon Zhao Reviewed-by: Igor Mammedov Acked-by: Michael S. Tsirkin Message-id: 1433929959-29530-3-git-send-email-drjones@redhat.com Signed-off-by: Peter Maydell --- hw/arm/virt-acpi-build.c | 43 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index a9373ccaca..d5a8b9c017 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -84,6 +84,12 @@ static void acpi_dsdt_add_uart(Aml *scope, const MemMapEntry *uart_memmap, aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, AML_EXCLUSIVE, uart_irq)); aml_append(dev, aml_name_decl("_CRS", crs)); + + /* The _ADR entry is used to link this device to the UART described + * in the SPCR table, i.e. SPCR.base_address.address == _ADR. + */ + aml_append(dev, aml_name_decl("_ADR", aml_int(uart_memmap->base))); + aml_append(scope, dev); } @@ -333,6 +339,38 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt) return rsdp_table; } +static void +build_spcr(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) +{ + AcpiSerialPortConsoleRedirection *spcr; + const MemMapEntry *uart_memmap = &guest_info->memmap[VIRT_UART]; + int irq = guest_info->irqmap[VIRT_UART] + ARM_SPI_BASE; + + spcr = acpi_data_push(table_data, sizeof(*spcr)); + + spcr->interface_type = 0x3; /* ARM PL011 UART */ + + spcr->base_address.space_id = AML_SYSTEM_MEMORY; + spcr->base_address.bit_width = 8; + spcr->base_address.bit_offset = 0; + spcr->base_address.access_width = 1; + spcr->base_address.address = cpu_to_le64(uart_memmap->base); + + spcr->interrupt_types = (1 << 3); /* Bit[3] ARMH GIC interrupt */ + spcr->gsi = cpu_to_le32(irq); /* Global System Interrupt */ + + spcr->baud = 3; /* Baud Rate: 3 = 9600 */ + spcr->parity = 0; /* No Parity */ + spcr->stopbits = 1; /* 1 Stop bit */ + spcr->flowctrl = (1 << 1); /* Bit[1] = RTS/CTS hardware flow control */ + spcr->term_type = 0; /* Terminal Type: 0 = VT100 */ + + spcr->pci_device_id = 0xffff; /* PCI Device ID: not a PCI device */ + spcr->pci_vendor_id = 0xffff; /* PCI Vendor ID: not a PCI device */ + + build_header(linker, table_data, (void *)spcr, "SPCR", sizeof(*spcr), 2); +} + static void build_mcfg(GArray *table_data, GArray *linker, VirtGuestInfo *guest_info) { @@ -514,7 +552,7 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) dsdt = tables_blob->len; build_dsdt(tables_blob, tables->linker, guest_info); - /* FADT MADT GTDT pointed to by RSDT */ + /* FADT MADT GTDT SPCR pointed to by RSDT */ acpi_add_table(table_offsets, tables_blob); build_fadt(tables_blob, tables->linker, dsdt); @@ -527,6 +565,9 @@ void virt_acpi_build(VirtGuestInfo *guest_info, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_mcfg(tables_blob, tables->linker, guest_info); + acpi_add_table(table_offsets, tables_blob); + build_spcr(tables_blob, tables->linker, guest_info); + /* RSDT is pointed to by RSDP */ rsdt = tables_blob->len; build_rsdt(tables_blob, tables->linker, table_offsets);