x86 hvm: New hvm_op "set_mem_type" which allows marking ram page
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 10 Jul 2008 14:30:39 +0000 (15:30 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 10 Jul 2008 14:30:39 +0000 (15:30 +0100)
ranges as ro, rw, or mmio_dm.

Signed-off-by: Trolle Selander <trolle.selander@eu.citrix.com>
tools/libxc/xc_misc.c
tools/libxc/xenctrl.h
xen/arch/x86/hvm/hvm.c
xen/include/public/hvm/hvm_op.h

index 0fe5272eabc3f1f5066b63ad0fd219dc2ff899e8..7fa16078960ae92d9d3d8e75e2ba44dd31b22343 100644 (file)
@@ -295,6 +295,36 @@ int xc_hvm_modified_memory(
     return rc;
 }
 
+int xc_hvm_set_mem_type(
+    int xc_handle, domid_t dom, hvmmem_type_t mem_type, uint64_t first_pfn, uint64_t nr)
+{
+    DECLARE_HYPERCALL;
+    struct xen_hvm_set_mem_type arg;
+    int rc;
+
+    hypercall.op     = __HYPERVISOR_hvm_op;
+    hypercall.arg[0] = HVMOP_set_mem_type;
+    hypercall.arg[1] = (unsigned long)&arg;
+
+    arg.domid        = dom;
+    arg.hvmmem_type  = mem_type;
+    arg.first_pfn    = first_pfn;
+    arg.nr           = nr;
+
+    if ( (rc = lock_pages(&arg, sizeof(arg))) != 0 )
+    {
+        PERROR("Could not lock memory");
+        return rc;
+    }
+
+    rc = do_xen_hypercall(xc_handle, &hypercall);
+
+    unlock_pages(&arg, sizeof(arg));
+
+    return rc;
+}
+
+
 void *xc_map_foreign_pages(int xc_handle, uint32_t dom, int prot,
                            const xen_pfn_t *arr, int num)
 {
index 040f67dc9baefa64a25f18dc88fbc581bfbbb534..b70c3b81930801962a6a070b32fbf53a2d97b9b7 100644 (file)
@@ -27,6 +27,7 @@
 #include <xen/event_channel.h>
 #include <xen/sched.h>
 #include <xen/memory.h>
+#include <xen/hvm/params.h>
 #include <xen/xsm/acm.h>
 #include <xen/xsm/acm_ops.h>
 #include <xen/xsm/flask_op.h>
@@ -942,6 +943,14 @@ int xc_hvm_track_dirty_vram(
 int xc_hvm_modified_memory(
     int xc_handle, domid_t dom, uint64_t first_pfn, uint64_t nr);
 
+/*
+ * Set a range of memory to a specific type.
+ * Allowed types are HVMMEM_ram_rw, HVMMEM_ram_ro, HVMMEM_mmio_dm
+ */
+int xc_hvm_set_mem_type(
+    int xc_handle, domid_t dom, hvmmem_type_t memtype, uint64_t first_pfn, uint64_t nr);
+
+
 typedef enum {
   XC_ERROR_NONE = 0,
   XC_INTERNAL_ERROR = 1,
index 509b5e35d4ec5a109562cf1e645f0816fa897f3f..04e9da6e0e9e54479417dfee05c14d1c9d281723 100644 (file)
@@ -2611,6 +2611,65 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE(void) arg)
         break;
     }
 
+    case HVMOP_set_mem_type:
+    {
+        struct xen_hvm_set_mem_type a;
+        struct domain *d;
+        unsigned long pfn;
+        
+        /* Interface types to internal p2m types */
+        p2m_type_t memtype[] = {
+            p2m_ram_rw,        /* HVMMEM_ram_rw  */
+            p2m_ram_ro,        /* HVMMEM_ram_ro  */
+            p2m_mmio_dm        /* HVMMEM_mmio_dm */
+        };
+
+        if ( copy_from_guest(&a, arg, 1) )
+            return -EFAULT;
+
+        if ( a.domid == DOMID_SELF )
+        {
+            d = rcu_lock_current_domain();
+        }
+        else
+        {
+            if ( (d = rcu_lock_domain_by_id(a.domid)) == NULL )
+                return -ESRCH;
+            if ( !IS_PRIV_FOR(current->domain, d) )
+            {
+                rc = -EPERM;
+                goto param_fail4;
+            }
+        }
+
+        rc = -EINVAL;
+        if ( !is_hvm_domain(d) )
+            goto param_fail4;
+
+        rc = -EINVAL;
+        if ( (a.first_pfn > domain_get_maximum_gpfn(d)) ||
+             ((a.first_pfn + a.nr - 1) < a.first_pfn) ||
+             ((a.first_pfn + a.nr - 1) > domain_get_maximum_gpfn(d)) )
+            goto param_fail4;
+            
+        if ( a.hvmmem_type >= ARRAY_SIZE(memtype) )
+            goto param_fail4;
+            
+        rc = 0;
+        
+        for ( pfn = a.first_pfn; pfn < a.first_pfn + a.nr; pfn++ )
+        {
+            p2m_type_t t;
+            mfn_t mfn;
+            mfn = gfn_to_mfn(d, pfn, &t);
+            p2m_change_type(d, pfn, t, memtype[a.hvmmem_type]);
+        }
+         
+    param_fail4:
+        rcu_unlock_domain(d);
+        break;
+    }
+
     default:
     {
         gdprintk(XENLOG_WARNING, "Bad HVM op %ld.\n", op);
index a06d9416830d63b06e79e1180ad5ec175c3485c9..f0ada2d758d9586eedac80544d9e381067091162 100644 (file)
@@ -105,6 +105,27 @@ struct xen_hvm_modified_memory {
 typedef struct xen_hvm_modified_memory xen_hvm_modified_memory_t;
 DEFINE_XEN_GUEST_HANDLE(xen_hvm_modified_memory_t);
 
+#define HVMOP_set_mem_type    8
+typedef enum {
+    HVMMEM_ram_rw,             /* Normal read/write guest RAM */
+    HVMMEM_ram_ro,             /* Read-only; writes are discarded */
+    HVMMEM_mmio_dm,            /* Reads and write go to the device model */
+} hvmmem_type_t;
+/* Notify that a region of memory is to be treated in a specific way. */
+struct xen_hvm_set_mem_type {
+    /* Domain to be updated. */
+    domid_t domid;
+    /* Memory type */
+    hvmmem_type_t hvmmem_type;
+    /* First pfn. */
+    uint64_aligned_t first_pfn;
+    /* Number of pages. */
+    uint64_aligned_t nr;
+};
+typedef struct xen_hvm_set_mem_type xen_hvm_set_mem_type_t;
+DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_mem_type_t);
+
+
 #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
 
 #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */