From: Christian Ehrhardt <[EMAIL PROTECTED]>

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 <[EMAIL PROTECTED]>
---

[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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to