[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kvm-ppc
Subject:    [PATCH 2/6] kvmppc: magic page hypercall - host part
From:       ehrhardt () linux ! vnet ! ibm ! com
Date:       2008-09-16 6:27:51
Message-ID: 1221546475-15818-3-git-send-email-ehrhardt () linux ! vnet ! ibm ! com
[Download RAW message or body]

From: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>

This adds the host part of the magic page registration. This is a memory
area of the guest granted to the host.
The patch just introduces the infrastruture to receive and map the guest paddr.
This is later used storage area a guest can read unprivileged (using binary
rewriting to change privileges instructions).

Signed-off-by: Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
---

[diffstat]
 arch/powerpc/kvm/booke_guest.c |   13 +++++++++++++
 arch/powerpc/kvm/emulate.c     |    9 +++++++++
 arch/powerpc/kvm/powerpc.c     |   20 ++++++++++++++++++--
 include/asm-powerpc/kvm_host.h |    5 +++++
 include/asm-powerpc/kvm_para.h |   24 ++++++++++++++++++++++++
 include/linux/kvm.h            |    5 +++++
 6 files changed, 74 insertions(+), 2 deletions(-)

[diff]

diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c
--- a/arch/powerpc/kvm/booke_guest.c
+++ b/arch/powerpc/kvm/booke_guest.c
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/kvm_para.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -44,6 +45,7 @@
 	{ "itlb_v",     VCPU_STAT(itlb_virt_miss_exits) },
 	{ "dtlb_r",     VCPU_STAT(dtlb_real_miss_exits) },
 	{ "dtlb_v",     VCPU_STAT(dtlb_virt_miss_exits) },
+	{ "dtlb_pv",    VCPU_STAT(dtlb_pvmem_miss_exits) },
 	{ "sysc",       VCPU_STAT(syscall_exits) },
 	{ "hcall",      VCPU_STAT(hcall_exits) },
 	{ "isi",        VCPU_STAT(isi_exits) },
@@ -344,6 +346,15 @@
 		unsigned long eaddr = vcpu->arch.fault_dear;
 		gfn_t gfn;
 
+		if (kvmppc_is_pvmem(vcpu, eaddr)) {
+			kvmppc_mmu_map(vcpu, eaddr,
+			 vcpu->arch.pvmem_gpaddr >> KVM_PPCPV_MAGIC_PAGE_SHIFT,
+			 0, KVM_PPCPV_MAGIC_PAGE_FLAGS);
+			vcpu->stat.dtlb_pvmem_miss_exits++;
+			r = RESUME_GUEST;
+			break;
+		}
+
 		/* Check the guest TLB. */
 		gtlbe = kvmppc_44x_dtlb_search(vcpu, eaddr);
 		if (!gtlbe) {
@@ -495,6 +506,8 @@
 
 	vcpu->arch.shadow_pid = 1;
 
+	vcpu->arch.pvmem = NULL;
+
 	/* Eye-catching number so we know if the guest takes an interrupt
 	 * before it's programmed its own IVPR. */
 	vcpu->arch.ivpr = 0x55550000;
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -21,6 +21,7 @@
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <linux/highmem.h>
 #include <linux/kvm_host.h>
 #include <linux/kvm_para.h>
 
@@ -207,8 +208,16 @@
 int kvmppc_do_hypercall(struct kvm_vcpu *vcpu)
 {
 	u32 ret = 0;
+	struct page *pvmem_page;
 
 	switch (vcpu->arch.gpr[11]) {
+	case KVM_HCALL_RESERVE_MAGICPAGE:
+		vcpu->arch.pvmem_gvaddr = vcpu->arch.gpr[3];
+		vcpu->arch.pvmem_gpaddr = vcpu->arch.gpr[4];
+		pvmem_page = gfn_to_page(vcpu->kvm,
+			vcpu->arch.pvmem_gpaddr >> KVM_PPCPV_MAGIC_PAGE_SHIFT);
+		vcpu->arch.pvmem = kmap(pvmem_page);
+		break;
 	default:
 		printk(KERN_ERR "unknown hypercall %d\n", vcpu->arch.gpr[11]);
 		kvmppc_dump_vcpu(vcpu);
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -21,6 +21,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/kvm_host.h>
+#include <linux/kvm_para.h>
 #include <linux/module.h>
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
@@ -148,18 +149,33 @@
 	case KVM_CAP_COALESCED_MMIO:
 		r = KVM_COALESCED_MMIO_PAGE_OFFSET;
 		break;
+	case KVM_CAP_PPCPV_MAGICPAGE:
+		r = 1;
+		break;
 	default:
 		r = 0;
 		break;
 	}
 	return r;
-
 }
 
 long kvm_arch_dev_ioctl(struct file *filp,
                         unsigned int ioctl, unsigned long arg)
 {
-	return -EINVAL;
+	long r = -EINVAL;
+
+	switch (ioctl) {
+	case KVM_GET_PPCPV_MAGICPAGE_SIZE:
+		if (arg)
+			goto out;
+		r = KVM_PPCPV_MAGIC_PAGE_SIZE;
+		break;
+	default:
+		break;
+	}
+out:
+	return r;
+
 }
 
 int kvm_arch_set_memory_region(struct kvm *kvm,
diff --git a/include/asm-powerpc/kvm_host.h b/include/asm-powerpc/kvm_host.h
--- a/include/asm-powerpc/kvm_host.h
+++ b/include/asm-powerpc/kvm_host.h
@@ -54,6 +54,7 @@
 	u32 itlb_real_miss_exits;
 	u32 itlb_virt_miss_exits;
 	u32 dtlb_real_miss_exits;
+	u32 dtlb_pvmem_miss_exits;
 	u32 dtlb_virt_miss_exits;
 	u32 syscall_exits;
 	u32 hcall_exits;
@@ -152,6 +153,10 @@
 
 	struct timer_list dec_timer;
 	unsigned long pending_exceptions;
+
+	long unsigned int pvmem_gvaddr;
+	long unsigned int pvmem_gpaddr;
+	void *pvmem;	  /* host mapping of pvmem */
 };
 
 struct kvm_guest_debug {
diff --git a/include/asm-powerpc/kvm_para.h b/include/asm-powerpc/kvm_para.h
--- a/include/asm-powerpc/kvm_para.h
+++ b/include/asm-powerpc/kvm_para.h
@@ -22,7 +22,19 @@
 
 #ifdef __KERNEL__
 
+#include <linux/kvm_host.h>
+
 #define KVM_HYPERCALL_BIN 0x44000022
+
+#define KVM_HCALL_RESERVE_MAGICPAGE	0
+
+/*
+ * the guest guarantees alignment to requested size, choosing page size here
+ * easens tlb handling which is handled by host for the magic page
+ */
+#define KVM_PPCPV_MAGIC_PAGE_SIZE	4096
+#define KVM_PPCPV_MAGIC_PAGE_SHIFT	12
+#define KVM_PPCPV_MAGIC_PAGE_FLAGS	0x3f
 
 static inline int kvm_para_available(void)
 {
@@ -36,6 +48,18 @@
 
 extern int kvmppc_do_hypercall(struct kvm_vcpu *vcpu);
 
+static inline int kvmppc_is_pvmem(struct kvm_vcpu *vcpu, unsigned long eaddr)
+{
+	return vcpu->arch.pvmem &&
+		(eaddr >> KVM_PPCPV_MAGIC_PAGE_SHIFT) ==
+		(vcpu->arch.pvmem_gvaddr >> KVM_PPCPV_MAGIC_PAGE_SHIFT);
+}
+
+static inline int kvmppc_has_pvmem(struct kvm_vcpu *vcpu)
+{
+	return !!vcpu->arch.pvmem;
+}
+
 #endif /* __KERNEL__ */
 
 #endif /* __POWERPC_KVM_PARA_H__ */
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -365,6 +365,10 @@
 #define KVM_TRACE_PAUSE           _IO(KVMIO,  0x07)
 #define KVM_TRACE_DISABLE         _IO(KVMIO,  0x08)
 /*
+ * ioctls for powerpc paravirtualization extensions
+ */
+#define KVM_GET_PPCPV_MAGICPAGE_SIZE       _IO(KVMIO,   0x09)
+/*
  * Extension capability list.
  */
 #define KVM_CAP_IRQCHIP	  0
@@ -382,6 +386,7 @@
 #define KVM_CAP_PV_MMU 13
 #define KVM_CAP_MP_STATE 14
 #define KVM_CAP_COALESCED_MMIO 15
+#define KVM_CAP_PPCPV_MAGICPAGE 16
 
 /*
  * ioctls for VM fds
--
To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic