For PAPR guests, KVM tracks the various areas registered with the H_REGISTER_VPA hypercall. For full emulation, of course, these are tracked within qemu. At present these values are not synchronized. This is a problem for reset (qemu's reset of the VPA address is not pushed to KVM) and will also be a problem for savevm / migration.
The kernel now supports accessing the VPA state via the ONE_REG interface, this patch adds code to qemu to use that interface to keep the qemu and KVM ideas of the VPA state synchronized. Signed-off-by: David Gibson <da...@gibson.dropbear.id.au> --- target-ppc/kvm.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 11e123f..8e7a6a9 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -635,6 +635,99 @@ static void kvm_get_fp(CPUState *cs) } } +#if defined(TARGET_PPC64) +static void kvm_get_vpa(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + struct kvm_one_reg reg; + int ret; + + reg.id = KVM_REG_PPC_VPA_ADDR; + reg.addr = (uintptr_t)&env->vpa_addr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, "Warning: Unable to get VPA address from KVM: %s\n", + strerror(errno)); + } + + assert((uintptr_t)&env->slb_shadow_size + == ((uintptr_t)&env->slb_shadow_addr + 8)); + reg.id = KVM_REG_PPC_VPA_SLB; + reg.addr = (uintptr_t)&env->slb_shadow_addr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, + "Warning: Unable to get SLB shadow state from KVM: %s\n", + strerror(errno)); + } + + assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8)); + reg.id = KVM_REG_PPC_VPA_DTL; + reg.addr = (uintptr_t)&env->dtl_addr; + ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, + "Warning: Unable to get dispatch trace log state from KVM: %s\n", + strerror(errno)); + } +} + +static void kvm_put_vpa(CPUState *cs) +{ + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; + struct kvm_one_reg reg; + int ret; + + /* SLB shadow or DTL can't be registered unless a master VPA is + * registered. That means when restoring state, if a VPA *is* + * registered, we need to set that up first. If not, we need to + * deregister the others before deregistering the master VPA */ + assert(env->vpa_addr || !(env->slb_shadow_addr || env->dtl_addr)); + + if (env->vpa_addr) { + reg.id = KVM_REG_PPC_VPA_ADDR; + reg.addr = (uintptr_t)&env->vpa_addr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, "Warning: Unable to set VPA address to KVM: %s\n", + strerror(errno)); + } + } + + assert((uintptr_t)&env->slb_shadow_size + == ((uintptr_t)&env->slb_shadow_addr + 8)); + reg.id = KVM_REG_PPC_VPA_SLB; + reg.addr = (uintptr_t)&env->slb_shadow_addr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, "Warning: Unable to set SLB shadow state to KVM: %s\n", + strerror(errno)); + } + + assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8)); + reg.id = KVM_REG_PPC_VPA_DTL; + reg.addr = (uintptr_t)&env->dtl_addr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, + "Warning: Unable to set dispatch trace log state to KVM: %s\n", + strerror(errno)); + } + + if (!env->vpa_addr) { + reg.id = KVM_REG_PPC_VPA_ADDR; + reg.addr = (uintptr_t)&env->vpa_addr; + ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, ®); + if (ret < 0) { + fprintf(stderr, "Warning: Unable to set VPA address to KVM: %s\n", + strerror(errno)); + } + } +} +#endif /* TARGET_PPC64 */ + int kvm_arch_put_registers(CPUState *cs, int level) { PowerPCCPU *cpu = POWERPC_CPU(cs); @@ -746,6 +839,12 @@ int kvm_arch_put_registers(CPUState *cs, int level) if (cap_hior && (level >= KVM_PUT_RESET_STATE)) { kvm_put_one_spr(cs, KVM_REG_PPC_HIOR, SPR_HIOR); + +#ifdef TARGET_PPC64 + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_PAPR)) { + kvm_put_vpa(cs); + } +#endif /* TARGET_PPC64 */ } } @@ -959,6 +1058,12 @@ int kvm_arch_get_registers(CPUState *cs) 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); + +#ifdef TARGET_PPC64 + if (kvm_check_extension(cs->kvm_state, KVM_CAP_PPC_PAPR)) { + kvm_get_vpa(cs); + } +#endif } return 0; -- 1.7.10.4