From a036f5302c13634f3d375615b2949fd1fa1657b6 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Mon, 25 Mar 2019 14:16:46 +0000 Subject: [PATCH 1/6] target/arm: Fix non-parallel expansion of CASP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The second word has been loaded from the unincremented address since the first commit. Fixes: 44ac14b06fa Reported-by: Alex Bennée Signed-off-by: Richard Henderson Reviewed-by: Alex Bennée Tested-by: Alex Bennée Message-id: 20190322234302.12770-1-richard.henderson@linaro.org Signed-off-by: Peter Maydell --- target/arm/translate-a64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c index 1959046343..dcdeb80176 100644 --- a/target/arm/translate-a64.c +++ b/target/arm/translate-a64.c @@ -2510,7 +2510,7 @@ static void gen_compare_and_swap_pair(DisasContext *s, int rs, int rt, tcg_gen_qemu_ld_i64(d1, clean_addr, memidx, MO_64 | MO_ALIGN_16 | s->be_data); tcg_gen_addi_i64(a2, clean_addr, 8); - tcg_gen_qemu_ld_i64(d2, clean_addr, memidx, MO_64 | s->be_data); + tcg_gen_qemu_ld_i64(d2, a2, memidx, MO_64 | s->be_data); /* Compare the two words, also in memory order. */ tcg_gen_setcond_i64(TCG_COND_EQ, c1, d1, s1); From 4261b2f915cbc1538c528d982a521c76dd46e66c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Mon, 25 Mar 2019 14:16:46 +0000 Subject: [PATCH 2/6] nrf51_gpio: reflect pull-up/pull-down to IRQs Some drivers do I2C bitbanging by keeping the output to 0 and flipping the GPIO direction between input and output (see for example in Linux gpio_set_open_drain_value_commit, in drivers/gpio/gpiolib.c). When the GPIO is set to input, the pull-up resistor brings the output to 1, while when the GPIO is set to output, the output driver brings the output to 0. Implement this for the nRF51 GPIO device model. First, if both input and output are floating, and there is a pull-up or pull-down resistor configured, do not just set s->in, but also make any devices listening on the output qemu_irq receive that value. Second, if the pin is driven both internally (output pin) and externally you don't get a short circuit if both sides drive the pin to the same value. Signed-off-by: Paolo Bonzini Acked-by: Stefan Hajnoczi Message-id: 20190317141001.3346-1-pbonzini@redhat.com [PMM: wrapped long line] Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/gpio/nrf51_gpio.c | 65 +++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/hw/gpio/nrf51_gpio.c b/hw/gpio/nrf51_gpio.c index 86e047d649..87a2f2a0dc 100644 --- a/hw/gpio/nrf51_gpio.c +++ b/hw/gpio/nrf51_gpio.c @@ -43,6 +43,17 @@ static bool is_connected(uint32_t config, uint32_t level) return state; } +static int pull_value(uint32_t config) +{ + int pull = extract32(config, 2, 2); + if (pull == NRF51_GPIO_PULLDOWN) { + return 0; + } else if (pull == NRF51_GPIO_PULLUP) { + return 1; + } + return -1; +} + static void update_output_irq(NRF51GPIOState *s, size_t i, bool connected, bool level) { @@ -61,43 +72,47 @@ static void update_output_irq(NRF51GPIOState *s, size_t i, static void update_state(NRF51GPIOState *s) { - uint32_t pull; + int pull; size_t i; - bool connected_out, dir, connected_in, out, input; + bool connected_out, dir, connected_in, out, in, input; for (i = 0; i < NRF51_GPIO_PINS; i++) { - pull = extract32(s->cnf[i], 2, 2); + pull = pull_value(s->cnf[i]); dir = extract32(s->cnf[i], 0, 1); connected_in = extract32(s->in_mask, i, 1); out = extract32(s->out, i, 1); + in = extract32(s->in, i, 1); input = !extract32(s->cnf[i], 1, 1); connected_out = is_connected(s->cnf[i], out) && dir; - update_output_irq(s, i, connected_out, out); - - /* Pin both driven externally and internally */ - if (connected_out && connected_in) { - qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i); - } - - /* - * Input buffer disconnected from internal/external drives, so - * pull-up/pull-down becomes relevant - */ - if (!input || (input && !connected_in && !connected_out)) { - if (pull == NRF51_GPIO_PULLDOWN) { - s->in = deposit32(s->in, i, 1, 0); - } else if (pull == NRF51_GPIO_PULLUP) { - s->in = deposit32(s->in, i, 1, 1); + if (!input) { + if (pull >= 0) { + /* Input buffer disconnected from external drives */ + s->in = deposit32(s->in, i, 1, pull); + } + } else { + if (connected_out && connected_in && out != in) { + /* Pin both driven externally and internally */ + qemu_log_mask(LOG_GUEST_ERROR, + "GPIO pin %zu short circuited\n", i); + } + if (!connected_in) { + /* + * Floating input: the output stimulates IN if connected, + * otherwise pull-up/pull-down resistors put a value on both + * IN and OUT. + */ + if (pull >= 0 && !connected_out) { + connected_out = true; + out = pull; + } + if (connected_out) { + s->in = deposit32(s->in, i, 1, out); + } } } - - /* Self stimulation through internal output driver */ - if (connected_out && !connected_in && input) { - s->in = deposit32(s->in, i, 1, out); - } + update_output_irq(s, i, connected_out, out); } - } /* From da77e0fad445eda22277c786b7d45cd96b7c3b2a Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 25 Mar 2019 14:16:46 +0000 Subject: [PATCH 3/6] target/arm: add PCI_TESTDEV back to default config In the kconfig shuffle arm lost pci-testdev which is used by kvm-unit-tests. Let's add it back. Signed-off-by: Andrew Jones Reviewed-by: Thomas Huth Message-id: 20190322163059.9716-1-drjones@redhat.com Signed-off-by: Peter Maydell --- default-configs/arm-softmmu.mak | 1 + 1 file changed, 1 insertion(+) diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak index 2a7efc1167..613d19a06d 100644 --- a/default-configs/arm-softmmu.mak +++ b/default-configs/arm-softmmu.mak @@ -2,6 +2,7 @@ CONFIG_PCI=y CONFIG_PCI_DEVICES=y +CONFIG_PCI_TESTDEV=y CONFIG_VGA=y CONFIG_NAND=y CONFIG_ECC=y From cbbb3041fe2f57a475cef5d6b0ef836118aad106 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 25 Mar 2019 14:16:47 +0000 Subject: [PATCH 4/6] target/arm: fix crash on pmu register access Fix a QEMU NULL derefence that occurs when the guest attempts to enable PMU counters with a non-v8 cpu model or a v8 cpu model which has not configured a PMU. Fixes: 4e7beb0cc0f3 ("target/arm: Add a timer to predict PMU counter overflow") Signed-off-by: Andrew Jones Reviewed-by: Richard Henderson Message-id: 20190322162333.17159-2-drjones@redhat.com Signed-off-by: Peter Maydell --- target/arm/helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/target/arm/helper.c b/target/arm/helper.c index c8d3c213b6..fc73488f6c 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1259,6 +1259,10 @@ static bool pmu_counter_enabled(CPUARMState *env, uint8_t counter) int el = arm_current_el(env); uint8_t hpmn = env->cp15.mdcr_el2 & MDCR_HPMN; + if (!arm_feature(env, ARM_FEATURE_PMU)) { + return false; + } + if (!arm_feature(env, ARM_FEATURE_EL2) || (counter < hpmn || counter == 31)) { e = env->cp15.c9_pmcr & PMCRE; From a46118fc16537a593119e5b316052a98514046bb Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 25 Mar 2019 14:16:47 +0000 Subject: [PATCH 5/6] target/arm: cortex-a7 and cortex-a15 have pmus cortex-a7 and cortex-a15 have pmus (PMUv2) and they advertise them in ID_DFR0. Let's allow them to function. This also enables the pmu cpu property to work with these cpu types, i.e. we can now do '-cpu cortex-a15,pmu=off' to remove the pmu. Signed-off-by: Andrew Jones Reviewed-by: Richard Henderson Message-id: 20190322162333.17159-3-drjones@redhat.com Signed-off-by: Peter Maydell --- target/arm/cpu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index 96f0ff0ec7..504a4771fb 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -1109,6 +1109,7 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp) #endif } else { cpu->id_aa64dfr0 &= ~0xf00; + cpu->id_dfr0 &= ~(0xf << 24); cpu->pmceid0 = 0; cpu->pmceid1 = 0; } @@ -1744,6 +1745,7 @@ static void cortex_a7_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7; cpu->midr = 0x410fc075; cpu->reset_fpsid = 0x41023075; @@ -1789,6 +1791,7 @@ static void cortex_a15_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_CBAR_RO); set_feature(&cpu->env, ARM_FEATURE_EL2); set_feature(&cpu->env, ARM_FEATURE_EL3); + set_feature(&cpu->env, ARM_FEATURE_PMU); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15; cpu->midr = 0x412fc0f1; cpu->reset_fpsid = 0x410430f0; From f2b2f53f6429b5abd7cd86bd65747f5f13e195eb Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 25 Mar 2019 14:16:47 +0000 Subject: [PATCH 6/6] target/arm: make pmccntr_op_start/finish static These functions are not used outside helper.c Signed-off-by: Andrew Jones Reviewed-by: Richard Henderson Message-id: 20190322162333.17159-4-drjones@redhat.com Signed-off-by: Peter Maydell --- target/arm/cpu.h | 11 ----------- target/arm/helper.c | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 5f23c62132..d4d2836923 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -992,17 +992,6 @@ static inline bool is_a64(CPUARMState *env) int cpu_arm_signal_handler(int host_signum, void *pinfo, void *puc); -/** - * pmccntr_op_start/finish - * @env: CPUARMState - * - * Convert the counter in the PMCCNTR between its delta form (the typical mode - * when it's enabled) and the guest-visible value. These two calls must always - * surround any action which might affect the counter. - */ -void pmccntr_op_start(CPUARMState *env); -void pmccntr_op_finish(CPUARMState *env); - /** * pmu_op_start/finish * @env: CPUARMState diff --git a/target/arm/helper.c b/target/arm/helper.c index fc73488f6c..a36f4b3d69 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1337,7 +1337,7 @@ static void pmu_update_irq(CPUARMState *env) * etc. can be done logically. This is essentially a no-op if the counter is * not enabled at the time of the call. */ -void pmccntr_op_start(CPUARMState *env) +static void pmccntr_op_start(CPUARMState *env) { uint64_t cycles = cycles_get_count(env); @@ -1367,7 +1367,7 @@ void pmccntr_op_start(CPUARMState *env) * guest-visible count. A call to pmccntr_op_finish should follow every call to * pmccntr_op_start. */ -void pmccntr_op_finish(CPUARMState *env) +static void pmccntr_op_finish(CPUARMState *env) { if (pmu_counter_enabled(env, 31)) { #ifndef CONFIG_USER_ONLY