diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 41a00ea..4e0bc22 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -201,6 +201,8 @@ int kvmppc_set_sregs_ivor(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs);
 
 int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
 int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg);
+int kvm_vcpu_get_vpa_info(struct kvm_vcpu *vcpu, struct kvm_ppc_vpa *vpa);
+int kvm_vcpu_set_vpa_info(struct kvm_vcpu *vcpu, struct kvm_ppc_vpa *vpa);
 
 void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid);
 
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 817837d..53d950b 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -143,6 +143,57 @@ static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa)
 	vpa->yield_count = 1;
 }
 
+int kvm_vcpu_get_vpa_info(struct kvm_vcpu *vcpu, struct kvm_ppc_vpa *vpa)
+{
+	spin_lock(&vcpu->arch.vpa_update_lock);
+	vpa->vpa_addr = vcpu->arch.vpa.next_gpa;
+	vpa->slb_shadow_addr = vcpu->arch.slb_shadow.next_gpa;
+	vpa->slb_shadow_size = vcpu->arch.slb_shadow.len;
+	vpa->dtl_addr = vcpu->arch.dtl.next_gpa;
+	vpa->dtl_size = vcpu->arch.dtl.len;
+	spin_unlock(&vcpu->arch.vpa_update_lock);
+	return 0;
+}
+
+static inline void set_vpa(struct kvmppc_vpa *v, unsigned long addr,
+			   unsigned long len)
+{
+	if (v->next_gpa != addr || v->len != len) {
+		v->next_gpa = addr;
+		v->len = addr ? len : 0;
+		v->update_pending = 1;
+	}
+}
+
+int kvm_vcpu_set_vpa_info(struct kvm_vcpu *vcpu, struct kvm_ppc_vpa *vpa)
+{
+	/* check that addresses are cacheline aligned */
+	if ((vpa->vpa_addr & (L1_CACHE_BYTES - 1)) ||
+	    (vpa->slb_shadow_addr & (L1_CACHE_BYTES - 1)) ||
+	    (vpa->dtl_addr & (L1_CACHE_BYTES - 1)))
+		return -EINVAL;
+
+	/* DTL must be at least 1 entry long, if being set */
+	if (vpa->dtl_addr) {
+		if (vpa->dtl_size < sizeof(struct dtl_entry))
+			return -EINVAL;
+		vpa->dtl_size -= vpa->dtl_size % sizeof(struct dtl_entry);
+	}
+
+	/* DTL and SLB shadow require VPA */
+	if (!vpa->vpa_addr && (vpa->slb_shadow_addr || vpa->dtl_addr))
+		return -EINVAL;
+
+	spin_lock(&vcpu->arch.vpa_update_lock);
+	set_vpa(&vcpu->arch.vpa, vpa->vpa_addr, sizeof(struct lppaca));
+	set_vpa(&vcpu->arch.slb_shadow, vpa->slb_shadow_addr,
+		vpa->slb_shadow_size);
+	set_vpa(&vcpu->arch.dtl, vpa->dtl_addr, vpa->dtl_size);
+	spin_unlock(&vcpu->arch.vpa_update_lock);
+
+	return 0;
+}
+
 /* Length for a per-processor buffer is passed in at offset 4 in the buffer */
 struct reg_vpa {
 	u32 dummy;
@@ -321,7 +372,8 @@ static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
 	spin_lock(&vcpu->arch.vpa_update_lock);
 	if (vcpu->arch.vpa.update_pending) {
 		kvmppc_update_vpa(vcpu, &vcpu->arch.vpa);
-		init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
+		if (vcpu->arch.vpa.pinned_addr)
+			init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
 	}
 	if (vcpu->arch.dtl.update_pending) {
 		kvmppc_update_vpa(vcpu, &vcpu->arch.dtl);
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 10e4dfb..72764ba 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -341,6 +341,9 @@ int kvm_dev_ioctl_check_extension(long ext)
 		if (cpu_has_feature(CPU_FTR_ARCH_201))
 			r = 2;
 		break;
+	case KVM_CAP_PPC_VPA:
+		r = 1;
+		break;
 #endif
 	case KVM_CAP_SYNC_MMU:
 #ifdef CONFIG_KVM_BOOK3S_64_HV
@@ -821,6 +824,26 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
 		break;
 	}
 #endif
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+	case KVM_PPC_GET_VPA_INFO: {
+		struct kvm_ppc_vpa vpa;
+		r = kvm_vcpu_get_vpa_info(vcpu, &vpa);
+		if (r)
+			break;
+		r = -EFAULT;
+		if (copy_to_user(argp, &vpa, sizeof(vpa)))
+			break;
+		r = 0;
+	}
+	case KVM_PPC_SET_VPA_INFO: {
+		struct kvm_ppc_vpa vpa;
+		r = -EFAULT;
+		if (copy_from_user(&vpa, argp, sizeof(vpa)))
+			break;
+		r = kvm_vcpu_set_vpa_info(vcpu, &vpa);
+		break;
+	}
+#endif
 	default:
 		r = -EINVAL;
 	}
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index f4f5be8..4a8bb4f 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -622,6 +622,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_S390_COW 79
 #define KVM_CAP_PPC_ALLOC_HTAB 80
 #define KVM_CAP_PPC_BOOKE_WATCHDOG 81
+#define KVM_CAP_PPC_VPA 83
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -959,4 +960,15 @@ struct kvm_assigned_msix_entry {
 	__u16 padding[3];
 };
 
+struct kvm_ppc_vpa {
+	__u64 vpa_addr;
+	__u64 slb_shadow_addr;
+	__u64 dtl_addr;
+	__u32 slb_shadow_size;
+	__u32 dtl_size;
+};
+
+#define KVM_PPC_GET_VPA_INFO	_IOR(KVMIO, 0xae, struct kvm_ppc_vpa)
+#define KVM_PPC_SET_VPA_INFO	_IOW(KVMIO, 0xaf, struct kvm_ppc_vpa)
+
 #endif /* __LINUX_KVM_H */
