diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-05-08 00:06:43 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-05-08 00:06:43 +0100 |
commit | 629d166994725773dea9cef843fcb0ae5f3585fe (patch) | |
tree | 266ee580fe4be6008c5d4cdf1e3bc3b467ab2dcb /target/arm | |
parent | a6f6d24757a73f7176989134b97284a1a7df11e5 (diff) | |
parent | 63159601fb3e396b28da14cbb71e50ed3f5a0331 (diff) |
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190507' into staging
target-arm queue:
* Stop using variable length array in dc_zva
* Implement M-profile XPSR GE bits
* Don't enable ARMV7M_EXCP_DEBUG from reset
* armv7m_nvic: NS BFAR and BFSR are RAZ/WI if BFHFNMINS == 0
* armv7m_nvic: Check subpriority in nvic_recompute_state_secure()
* fix various minor issues to allow building for Windows-on-ARM64
* aspeed: Set SDRAM size
* Allow system registers for KVM guests to be changed by QEMU code
* raspi: Diagnose requests for too much RAM
* virt: Support firmware configuration with -blockdev
# gpg: Signature made Tue 07 May 2019 12:59:30 BST
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate]
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* remotes/pmaydell/tags/pull-target-arm-20190507:
target/arm: Stop using variable length array in dc_zva
target/arm: Implement XPSR GE bits
hw/intc/armv7m_nvic: Don't enable ARMV7M_EXCP_DEBUG from reset
hw/intc/armv7m_nvic: NS BFAR and BFSR are RAZ/WI if BFHFNMINS == 0
hw/arm/armv7m_nvic: Check subpriority in nvic_recompute_state_secure()
osdep: Fix mingw compilation regarding stdio formats
util/cacheinfo: Use uint64_t on LLP64 model to satisfy Windows ARM64
qga: Fix mingw compilation warnings on enum conversion
QEMU_PACKED: Remove gcc_struct attribute in Windows non x86 targets
arm: aspeed: Set SDRAM size
arm: Allow system registers for KVM guests to be changed by QEMU code
hw/arm/raspi: Diagnose requests for too much RAM
hw/arm/virt: Support firmware configuration with -blockdev
pflash_cfi01: New pflash_cfi01_legacy_drive()
pc: Rearrange pc_system_firmware_init()'s legacy -drive loop
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm')
-rw-r--r-- | target/arm/cpu.h | 13 | ||||
-rw-r--r-- | target/arm/helper.c | 47 | ||||
-rw-r--r-- | target/arm/kvm.c | 8 | ||||
-rw-r--r-- | target/arm/kvm32.c | 20 | ||||
-rw-r--r-- | target/arm/kvm64.c | 2 | ||||
-rw-r--r-- | target/arm/machine.c | 2 |
6 files changed, 66 insertions, 26 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 22bc6e00ab..733b840a71 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -1285,6 +1285,7 @@ static inline uint32_t xpsr_read(CPUARMState *env) | (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27) | (env->thumb << 24) | ((env->condexec_bits & 3) << 25) | ((env->condexec_bits & 0xfc) << 8) + | (env->GE << 16) | env->v7m.exception; } @@ -1300,6 +1301,9 @@ static inline void xpsr_write(CPUARMState *env, uint32_t val, uint32_t mask) if (mask & XPSR_Q) { env->QF = ((val & XPSR_Q) != 0); } + if (mask & XPSR_GE) { + env->GE = (val & XPSR_GE) >> 16; + } if (mask & XPSR_T) { env->thumb = ((val & XPSR_T) != 0); } @@ -2610,18 +2614,25 @@ bool write_list_to_cpustate(ARMCPU *cpu); /** * write_cpustate_to_list: * @cpu: ARMCPU + * @kvm_sync: true if this is for syncing back to KVM * * For each register listed in the ARMCPU cpreg_indexes list, write * its value from the ARMCPUState structure into the cpreg_values list. * This is used to copy info from TCG's working data structures into * KVM or for outbound migration. * + * @kvm_sync is true if we are doing this in order to sync the + * register state back to KVM. In this case we will only update + * values in the list if the previous list->cpustate sync actually + * successfully wrote the CPU state. Otherwise we will keep the value + * that is in the list. + * * Returns: true if all register values were read correctly, * false if some register was unknown or could not be read. * Note that we do not stop early on failure -- we will attempt * reading all registers in the list. */ -bool write_cpustate_to_list(ARMCPU *cpu); +bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync); #define ARM_CPUID_TI915T 0x54029152 #define ARM_CPUID_TI925T 0x54029252 diff --git a/target/arm/helper.c b/target/arm/helper.c index 81a92ab491..1e6eb0d0f3 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -1,4 +1,5 @@ #include "qemu/osdep.h" +#include "qemu/units.h" #include "target/arm/idau.h" #include "trace.h" #include "cpu.h" @@ -266,7 +267,7 @@ static bool raw_accessors_invalid(const ARMCPRegInfo *ri) return true; } -bool write_cpustate_to_list(ARMCPU *cpu) +bool write_cpustate_to_list(ARMCPU *cpu, bool kvm_sync) { /* Write the coprocessor state from cpu->env to the (index,value) list. */ int i; @@ -275,6 +276,7 @@ bool write_cpustate_to_list(ARMCPU *cpu) for (i = 0; i < cpu->cpreg_array_len; i++) { uint32_t regidx = kvm_to_cpreg_id(cpu->cpreg_indexes[i]); const ARMCPRegInfo *ri; + uint64_t newval; ri = get_arm_cp_reginfo(cpu->cp_regs, regidx); if (!ri) { @@ -284,7 +286,29 @@ bool write_cpustate_to_list(ARMCPU *cpu) if (ri->type & ARM_CP_NO_RAW) { continue; } - cpu->cpreg_values[i] = read_raw_cp_reg(&cpu->env, ri); + + newval = read_raw_cp_reg(&cpu->env, ri); + if (kvm_sync) { + /* + * Only sync if the previous list->cpustate sync succeeded. + * Rather than tracking the success/failure state for every + * item in the list, we just recheck "does the raw write we must + * have made in write_list_to_cpustate() read back OK" here. + */ + uint64_t oldval = cpu->cpreg_values[i]; + + if (oldval == newval) { + continue; + } + + write_raw_cp_reg(&cpu->env, ri, oldval); + if (read_raw_cp_reg(&cpu->env, ri) != oldval) { + continue; + } + + write_raw_cp_reg(&cpu->env, ri, newval); + } + cpu->cpreg_values[i] = newval; } return ok; } @@ -8704,7 +8728,7 @@ static void do_v7m_exception_exit(ARMCPU *cpu) { CPUARMState *env = &cpu->env; uint32_t excret; - uint32_t xpsr; + uint32_t xpsr, xpsr_mask; bool ufault = false; bool sfault = false; bool return_to_sp_process; @@ -9156,8 +9180,13 @@ static void do_v7m_exception_exit(ARMCPU *cpu) } *frame_sp_p = frameptr; } + + xpsr_mask = ~(XPSR_SPREALIGN | XPSR_SFPA); + if (!arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + xpsr_mask &= ~XPSR_GE; + } /* This xpsr_write() will invalidate frame_sp_p as it may switch stack */ - xpsr_write(env, xpsr, ~(XPSR_SPREALIGN | XPSR_SFPA)); + xpsr_write(env, xpsr, xpsr_mask); if (env->v7m.secure) { bool sfpa = xpsr & XPSR_SFPA; @@ -12642,6 +12671,9 @@ uint32_t HELPER(v7m_mrs)(CPUARMState *env, uint32_t reg) } if (!(reg & 4)) { mask |= XPSR_NZCV | XPSR_Q; /* APSR */ + if (arm_feature(env, ARM_FEATURE_THUMB_DSP)) { + mask |= XPSR_GE; + } } /* EPSR reads as zero */ return xpsr_read(env) & mask; @@ -13099,14 +13131,17 @@ void HELPER(dc_zva)(CPUARMState *env, uint64_t vaddr_in) * We know that in fact for any v8 CPU the page size is at least 4K * and the block size must be 2K or less, but TARGET_PAGE_SIZE is only * 1K as an artefact of legacy v5 subpage support being present in the - * same QEMU executable. + * same QEMU executable. So in practice the hostaddr[] array has + * two entries, given the current setting of TARGET_PAGE_BITS_MIN. */ int maxidx = DIV_ROUND_UP(blocklen, TARGET_PAGE_SIZE); - void *hostaddr[maxidx]; + void *hostaddr[DIV_ROUND_UP(2 * KiB, 1 << TARGET_PAGE_BITS_MIN)]; int try, i; unsigned mmu_idx = cpu_mmu_index(env, false); TCGMemOpIdx oi = make_memop_idx(MO_UB, mmu_idx); + assert(maxidx <= ARRAY_SIZE(hostaddr)); + for (try = 0; try < 2; try++) { for (i = 0; i < maxidx; i++) { diff --git a/target/arm/kvm.c b/target/arm/kvm.c index 79a79f0190..5995634612 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -497,6 +497,14 @@ void kvm_arm_reset_vcpu(ARMCPU *cpu) fprintf(stderr, "write_kvmstate_to_list failed\n"); abort(); } + /* + * Sync the reset values also into the CPUState. This is necessary + * because the next thing we do will be a kvm_arch_put_registers() + * which will update the list values from the CPUState before copying + * the list values back to KVM. It's OK to ignore failure returns here + * for the same reason we do so in kvm_arch_get_registers(). + */ + write_list_to_cpustate(cpu); } /* diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c index 50327989dc..327375f625 100644 --- a/target/arm/kvm32.c +++ b/target/arm/kvm32.c @@ -384,24 +384,8 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } - /* Note that we do not call write_cpustate_to_list() - * here, so we are only writing the tuple list back to - * KVM. This is safe because nothing can change the - * CPUARMState cp15 fields (in particular gdb accesses cannot) - * and so there are no changes to sync. In fact syncing would - * be wrong at this point: for a constant register where TCG and - * KVM disagree about its value, the preceding write_list_to_cpustate() - * would not have had any effect on the CPUARMState value (since the - * register is read-only), and a write_cpustate_to_list() here would - * then try to write the TCG value back into KVM -- this would either - * fail or incorrectly change the value the guest sees. - * - * If we ever want to allow the user to modify cp15 registers via - * the gdb stub, we would need to be more clever here (for instance - * tracking the set of registers kvm_arch_get_registers() successfully - * managed to update the CPUARMState with, and only allowing those - * to be written back up into the kernel). - */ + write_cpustate_to_list(cpu, true); + if (!write_list_to_kvmstate(cpu, level)) { return EINVAL; } diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c index 089af9c5f0..e3ba149248 100644 --- a/target/arm/kvm64.c +++ b/target/arm/kvm64.c @@ -838,6 +838,8 @@ int kvm_arch_put_registers(CPUState *cs, int level) return ret; } + write_cpustate_to_list(cpu, true); + if (!write_list_to_kvmstate(cpu, level)) { return EINVAL; } diff --git a/target/arm/machine.c b/target/arm/machine.c index 09567d4fc6..96d032f2a7 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -646,7 +646,7 @@ static int cpu_pre_save(void *opaque) abort(); } } else { - if (!write_cpustate_to_list(cpu)) { + if (!write_cpustate_to_list(cpu, false)) { /* This should never fail. */ abort(); } |