[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 5/5] target-ppc: Synchronize VPA state with KVM
From: |
David Gibson |
Subject: |
[Qemu-ppc] [PATCH 5/5] target-ppc: Synchronize VPA state with KVM |
Date: |
Wed, 23 Jan 2013 16:05:01 +1100 |
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 <address@hidden>
---
target-ppc/kvm.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 105 insertions(+)
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 7ed76be..0ce0180 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -637,6 +637,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);
@@ -748,6 +841,12 @@ int kvm_arch_put_registers(CPUState *cs, int level)
if (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
[Qemu-ppc] [PATCH 4/5] target-ppc: Synchronize FPU state with KVM, David Gibson, 2013/01/23