[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PULL 11/27] arm: Allow system registers for KVM guests
From: |
Auger Eric |
Subject: |
Re: [Qemu-devel] [PULL 11/27] arm: Allow system registers for KVM guests to be changed by QEMU code |
Date: |
Thu, 21 Feb 2019 15:20:12 +0100 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0 |
Hi Peter, Alex,
On 2/14/19 8:05 PM, Peter Maydell wrote:
> At the moment the Arm implementations of kvm_arch_{get,put}_registers()
> don't support having QEMU change the values of system registers
> (aka coprocessor registers for AArch32). This is because although
> kvm_arch_get_registers() calls write_list_to_cpustate() to
> update the CPU state struct fields (so QEMU code can read the
> values in the usual way), kvm_arch_put_registers() does not
> call write_cpustate_to_list(), meaning that any changes to
> the CPU state struct fields will not be passed back to KVM.
>
> The rationale for this design is documented in a comment in the
> AArch32 kvm_arch_put_registers() -- writing the values in the
> cpregs list into the CPU state struct is "lossy" because the
> write of a register might not succeed, and so if we blindly
> copy the CPU state values back again we will incorrectly
> change register values for the guest. The assumption was that
> no QEMU code would need to write to the registers.
>
> However, when we implemented debug support for KVM guests, we
> broke that assumption: the code to handle "set the guest up
> to take a breakpoint exception" does so by updating various
> guest registers including ESR_EL1.
>
> Support this by making kvm_arch_put_registers() synchronize
> CPU state back into the list. We sync only those registers
> where the initial write succeeds, which should be sufficient.
>
> Signed-off-by: Peter Maydell <address@hidden>
> Reviewed-by: Alex Bennée <address@hidden>
> Tested-by: Alex Bennée <address@hidden>
> Tested-by: Dongjiu Geng <address@hidden>
This commit introduces a regression when running with EDK2 FW:
I get the following traces:
error: kvm run failed Function not implemented
PC=000000013f5a6208 X00=00000000404003c4 X01=000000000000003a
X02=0000000000000000 X03=00000000404003c4 X04=0000000000000000
X05=0000000096000046 X06=000000013d2ef270 X07=000000013e3d1710
X08=09010755ffaf8ba8 X09=ffaf8b9cfeeb5468 X10=feeb546409010756
X11=09010757ffaf8b90 X12=feeb50680903068b X13=090306a1ffaf8bc0
X14=0000000000000000 X15=0000000000000000 X16=000000013f872da0
X17=00000000ffffa6ab X18=0000000000000000 X19=000000013f5a92d0
X20=000000013f5a7a78 X21=000000000000003a X22=000000013f5a7ab2
X23=000000013f5a92e8 X24=000000013f631090 X25=0000000000000010
X26=0000000000000100 X27=000000013f89501b X28=000000013e3d14e0
X29=000000013e3d12a0 X30=000000013f5a2518 SP=000000013b7be0b0
PSTATE=404003c4 -Z-- EL1t
and in host dmesg:
[ 3507.926571] kvm [35042]: load/store instruction decoding not implemented
My qemu cmd line is:
qemu-system-aarch64 -M virt,gic-version=3 -cpu host -smp 2 -m 4G
-display none --enable-kvm -serial tcp:localhost:4444,server -qmp
unix:/home/augere/TEST/QEMU/qmp-sock,server,nowait -device
virtio-blk-pci,bus=pcie.0,scsi=off,drive=drv0,id=virtio-disk0,bootindex=1,werror=stop,rerror=stop
-drive
file=aarch64-vm0-rhel-alt-7.6.qcow2,format=qcow2,if=none,cache=writethrough,id=drv0
-device virtio-net-pci,bus=pcie.0,netdev=nic0,mac=6a:f5:10:b1:3d:d2
-netdev
tap,id=nic0,script=/home/augere/TEST/SCRIPTS/qemu-ifup,downscript=/home/augere/TEST/SCRIPTS/qemu-ifdown
-bios
/home/augere/UPSTREAM/edk2/Build/ArmVirtQemu-AARCH64/DEBUG_GCC5/FV/QEMU_EFI.fd
-net none -d guest_errors
reverting the patch removes the guest crash. Any clue?
thanks
Eric
> ---
> target/arm/cpu.h | 9 ++++++++-
> target/arm/helper.c | 27 +++++++++++++++++++++++++--
> target/arm/kvm32.c | 20 ++------------------
> target/arm/kvm64.c | 2 ++
> target/arm/machine.c | 2 +-
> 5 files changed, 38 insertions(+), 22 deletions(-)
>
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index f0334413ece..bfc05c796a5 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -2535,18 +2535,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 5ac335f598c..7653aa6a50a 100644
> --- a/target/arm/helper.c
> +++ b/target/arm/helper.c
> @@ -264,7 +264,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;
> @@ -273,6 +273,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) {
> @@ -282,7 +283,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;
> }
> diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
> index bd51eb43c86..a75e04cc8f3 100644
> --- a/target/arm/kvm32.c
> +++ b/target/arm/kvm32.c
> @@ -387,24 +387,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 089af9c5f02..e3ba1492482 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 b2925496148..124192bfc26 100644
> --- a/target/arm/machine.c
> +++ b/target/arm/machine.c
> @@ -630,7 +630,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();
> }
>
- [Qemu-devel] [PULL 07/27] target/arm: expose CPUID registers to userspace, (continued)
- [Qemu-devel] [PULL 07/27] target/arm: expose CPUID registers to userspace, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 08/27] target/arm: expose MPIDR_EL1 to userspace, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 09/27] target/arm: expose remaining CPUID registers as RAZ, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 10/27] linux-user/elfload: enable HWCAP_CPUID for AArch64, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 12/27] MAINTAINERS: Remove Peter Crosthwaite from various entries, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 15/27] target/arm: Rely on optimization within tcg_gen_gvec_or, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 19/27] target/arm: Remove neon min/max helpers, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 14/27] hw/arm/armsse: Fix miswiring of expansion IRQs, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 13/27] hw/intc/armv7m_nvic: Allow byte accesses to SHPR1, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 11/27] arm: Allow system registers for KVM guests to be changed by QEMU code, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 22/27] target/arm: Split out flags setting from vfp compares, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 18/27] target/arm: Use tcg integer min/max primitives for neon, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 23/27] target/arm: Fix set of bits kept in xregs[ARM_VFP_FPSCR], Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 17/27] target/arm: Use vector minmax expanders for aarch32, Peter Maydell, 2019/02/14
- [Qemu-devel] [PULL 21/27] target/arm: Fix arm_cpu_dump_state vs FPSCR, Peter Maydell, 2019/02/14