On 24.01.2013, at 04:20, David Gibson wrote: > There are currently a batch of occasionally used SPRs whose state we do > not synchronize with KVM. This might be a problem for debugging, and will > definitely be a problem for savevm / migration. KVM now supports accessing > these registers via the KVM_{GET,SET}_ONE_REG interface, so this patch > wires up the code to use this on the qemu side. > > Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> > --- > target-ppc/cpu.h | 4 ++ > target-ppc/kvm.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++---- > 2 files changed, 136 insertions(+), 10 deletions(-) > > diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h > index 953146e..6cb79fe 100644 > --- a/target-ppc/cpu.h > +++ b/target-ppc/cpu.h > @@ -1319,6 +1319,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, > target_ulong newsp) > #define SPR_MPC_CMPH (0x09B) > #define SPR_MPC_LCTRL1 (0x09C) > #define SPR_MPC_LCTRL2 (0x09D) > +#define SPR_UAMOR (0x09D) > #define SPR_MPC_ICTRL (0x09E) > #define SPR_MPC_BAR (0x09F) > #define SPR_VRSAVE (0x100) > @@ -1535,6 +1536,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, > target_ulong newsp) > #define SPR_UPERF0 (0x310) > #define SPR_UPERF1 (0x311) > #define SPR_UPERF2 (0x312) > +#define SPR_MMCRA (0x312) > #define SPR_UPERF3 (0x313) > #define SPR_620_PMC1W (0x313) > #define SPR_UPERF4 (0x314) > @@ -1544,7 +1546,9 @@ static inline void cpu_clone_regs(CPUPPCState *env, > target_ulong newsp) > #define SPR_UPERF7 (0x317) > #define SPR_UPERF8 (0x318) > #define SPR_UPERF9 (0x319) > +#define SPR_PMC7 (0x319) > #define SPR_UPERFA (0x31A) > +#define SPR_PMC8 (0x31A) > #define SPR_UPERFB (0x31B) > #define SPR_620_MMCR0W (0x31B) > #define SPR_UPERFC (0x31C) > diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c > index 2f4f068..7604d0b 100644 > --- a/target-ppc/kvm.c > +++ b/target-ppc/kvm.c > @@ -61,6 +61,7 @@ static int cap_ppc_smt; > static int cap_ppc_rma; > static int cap_spapr_tce; > static int cap_hior; > +static int cap_one_reg; > > /* XXX We have a race condition where we actually have a level triggered > * interrupt, but the infrastructure can't expose that yet, so the guest > @@ -89,6 +90,7 @@ int kvm_arch_init(KVMState *s) > cap_ppc_smt = kvm_check_extension(s, KVM_CAP_PPC_SMT); > cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); > cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); > + cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG); > cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); > > if (!cap_interrupt_level) { > @@ -444,6 +446,76 @@ static void kvm_sw_tlb_put(PowerPCCPU *cpu) > g_free(bitmap); > } > > +static void kvm_get_one_spr(CPUState *cs, uint64_t id, int spr) > +{ > + PowerPCCPU *cpu = POWERPC_CPU(cs); > + CPUPPCState *env = &cpu->env; > + union { > + uint32_t u32; > + uint64_t u64; > + } val; > + struct kvm_one_reg reg = { > + .id = id, > + .addr = (uintptr_t) &val, > + }; > + int ret; > + > + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); > + if (ret != 0) { > + fprintf(stderr, "Warning: Unable to retrieve SPR %d from KVM: %s\n", > + spr, strerror(errno));
Any way you could make this a WARN_ONCE style message? > + } else { > + switch (id & KVM_REG_SIZE_MASK) { > + case KVM_REG_SIZE_U32: > + env->spr[spr] = val.u32; > + break; > + > + case KVM_REG_SIZE_U64: > + env->spr[spr] = val.u64; > + break; > + > + default: > + /* Don't handle this size yet */ > + abort(); > + } > + } > +} > + > +static void kvm_put_one_spr(CPUState *cs, uint64_t id, int spr) > +{ > + PowerPCCPU *cpu = POWERPC_CPU(cs); > + CPUPPCState *env = &cpu->env; > + union { > + uint32_t u32; > + uint64_t u64; > + } val; > + struct kvm_one_reg reg = { > + .id = id, > + .addr = (uintptr_t) &val, > + }; > + int ret; > + > + switch (id & KVM_REG_SIZE_MASK) { > + case KVM_REG_SIZE_U32: > + val.u32 = env->spr[spr]; > + break; > + > + case KVM_REG_SIZE_U64: > + val.u64 = env->spr[spr]; > + break; > + > + default: > + /* Don't handle this size yet */ > + abort(); > + } > + > + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); > + if (ret != 0) { > + fprintf(stderr, "Warning: Unable to set SPR %d to KVM: %s\n", > + spr, strerror(errno)); > + } > +} > + > int kvm_arch_put_registers(CPUState *cs, int level) > { > PowerPCCPU *cpu = POWERPC_CPU(cs); > @@ -524,16 +596,35 @@ int kvm_arch_put_registers(CPUState *cs, int level) > } > } > > - if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { > - uint64_t hior = env->spr[SPR_HIOR]; > - struct kvm_one_reg reg = { > - .id = KVM_REG_PPC_HIOR, > - .addr = (uintptr_t) &hior, > - }; > - > - ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); > - if (ret) { > - return ret; > + if (cap_one_reg) { This needs a check that we're on book3s. Otherwise you just spam booke users. Alex > + /* We deliberately ignore errors here, for kernels which have > + * the ONE_REG calls, but don't support the specific > + * registers. There's still a good chance things will work, > + * as long as we don't try to migrate */ > + kvm_put_one_spr(cs, KVM_REG_PPC_DABR, SPR_DABR); > + kvm_put_one_spr(cs, KVM_REG_PPC_DSCR, SPR_DSCR); > + kvm_put_one_spr(cs, KVM_REG_PPC_PURR, SPR_PURR); > + kvm_put_one_spr(cs, KVM_REG_PPC_SPURR, SPR_SPURR); > + kvm_put_one_spr(cs, KVM_REG_PPC_DAR, SPR_DAR); > + kvm_put_one_spr(cs, KVM_REG_PPC_DSISR, SPR_DSISR); > + kvm_put_one_spr(cs, KVM_REG_PPC_AMR, SPR_AMR); > + kvm_put_one_spr(cs, KVM_REG_PPC_UAMOR, SPR_UAMOR); > + > + kvm_put_one_spr(cs, KVM_REG_PPC_MMCR0, SPR_MMCR0); > + kvm_put_one_spr(cs, KVM_REG_PPC_MMCR1, SPR_MMCR1); > + kvm_put_one_spr(cs, KVM_REG_PPC_MMCRA, SPR_MMCRA); > + > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC1, SPR_PMC1); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC2, SPR_PMC2); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC3, SPR_PMC3); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC4, SPR_PMC4); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC5, SPR_PMC5); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC6, SPR_PMC6); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC7, SPR_PMC7); > + kvm_put_one_spr(cs, KVM_REG_PPC_PMC8, SPR_PMC8); > + > + if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { > + kvm_put_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR); > } > } > > @@ -716,6 +807,37 @@ int kvm_arch_get_registers(CPUState *cs) > } > } > > + if (cap_one_reg) { > + /* We deliberately ignore errors here, for kernels which have > + * the ONE_REG calls, but don't support the specific > + * registers. There's still a good chance things will work, > + * as long as we don't try to migrate */ > + if (cap_hior) { > + kvm_get_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR); > + } > + kvm_get_one_spr(cs, KVM_REG_PPC_DABR, SPR_DABR); > + kvm_get_one_spr(cs, KVM_REG_PPC_DSCR, SPR_DSCR); > + kvm_get_one_spr(cs, KVM_REG_PPC_PURR, SPR_PURR); > + kvm_get_one_spr(cs, KVM_REG_PPC_SPURR, SPR_SPURR); > + kvm_get_one_spr(cs, KVM_REG_PPC_DAR, SPR_DAR); > + kvm_get_one_spr(cs, KVM_REG_PPC_DSISR, SPR_DSISR); > + kvm_get_one_spr(cs, KVM_REG_PPC_AMR, SPR_AMR); > + kvm_get_one_spr(cs, KVM_REG_PPC_UAMOR, SPR_UAMOR); > + > + kvm_get_one_spr(cs, KVM_REG_PPC_MMCR0, SPR_MMCR0); > + kvm_get_one_spr(cs, KVM_REG_PPC_MMCR1, SPR_MMCR1); > + kvm_get_one_spr(cs, KVM_REG_PPC_MMCRA, SPR_MMCRA); > + > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC1, SPR_PMC1); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC2, SPR_PMC2); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC3, SPR_PMC3); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC4, SPR_PMC4); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC5, SPR_PMC5); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC6, SPR_PMC6); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC7, SPR_PMC7); > + kvm_get_one_spr(cs, KVM_REG_PPC_PMC8, SPR_PMC8); > + } > + > return 0; > } > > -- > 1.7.10.4 >