int mem_hotplug = 0;
/* Private domain structs for DOMID_XEN and DOMID_IO. */
-struct domain *dom_xen, *dom_io;
+struct domain *dom_xen, *dom_io, *dom_cow;
/* Frame table size in pages. */
unsigned long max_page;
*/
dom_io = domain_create(DOMID_IO, DOMCRF_dummy, 0);
BUG_ON(dom_io == NULL);
+
+ /*
+ * Initialise our DOMID_IO domain.
+ * This domain owns sharable pages.
+ */
+ dom_cow = domain_create(DOMID_COW, DOMCRF_dummy, 0);
+ BUG_ON(dom_cow == NULL);
/* First 1MB of RAM is historically marked as I/O. */
for ( i = 0; i < 0x100; i++ )
return -1;
}
+int page_make_sharable(struct domain *d,
+ struct page_info *page,
+ int expected_refcnt)
+{
+ unsigned long x, nx, y;
+
+ /* Acquire ref first, so that the page doesn't dissapear from us */
+ if(!get_page(page, d))
+ return -EINVAL;
+
+ spin_lock(&d->page_alloc_lock);
+
+ /* Change page type and count atomically */
+ y = page->u.inuse.type_info;
+ nx = PGT_shared_page | PGT_validated | 1;
+ do {
+ x = y;
+ /* We can only change the type if count is zero, and
+ type is PGT_none */
+ if((x & (PGT_type_mask | PGT_count_mask)) != PGT_none)
+ {
+ put_page(page);
+ spin_unlock(&d->page_alloc_lock);
+ return -EEXIST;
+ }
+ y = cmpxchg(&page->u.inuse.type_info, x, nx);
+ } while(x != y);
+
+ /* Check if the ref count is 2. The first from PGT_allocated, and the second
+ * from get_page at the top of this function */
+ if(page->count_info != (PGC_allocated | (2 + expected_refcnt)))
+ {
+ /* Return type count back to zero */
+ put_page_and_type(page);
+ spin_unlock(&d->page_alloc_lock);
+ return -E2BIG;
+ }
+
+ page_set_owner(page, dom_cow);
+ d->tot_pages--;
+ page_list_del(page, &d->page_list);
+ spin_unlock(&d->page_alloc_lock);
+
+ /* NOTE: We are not putting the page back. In effect this function acquires
+ * one ref and type ref for the caller */
+
+ return 0;
+}
+
+int page_make_private(struct domain *d, struct page_info *page)
+{
+ unsigned long x, y;
+
+ if(!get_page(page, dom_cow))
+ return -EINVAL;
+
+ spin_lock(&d->page_alloc_lock);
+
+ /* Change page type and count atomically */
+ y = page->u.inuse.type_info;
+ do {
+ x = y;
+ /* We can only change the type if count is one */
+ if((x & (PGT_type_mask | PGT_count_mask)) !=
+ (PGT_shared_page | 1))
+ {
+ put_page(page);
+ spin_unlock(&d->page_alloc_lock);
+ return -EEXIST;
+ }
+ y = cmpxchg(&page->u.inuse.type_info, x, PGT_none);
+ } while(x != y);
+
+ /* We dropped type ref above, drop one ref count too */
+ put_page(page);
+
+ /* Change the owner */
+ ASSERT(page_get_owner(page) == dom_cow);
+ page_set_owner(page, d);
+
+ d->tot_pages++;
+ page_list_add_tail(page, &d->page_list);
+ spin_unlock(&d->page_alloc_lock);
+
+ put_page(page);
+
+ return 0;
+}
+
static int __do_update_va_mapping(
unsigned long va, u64 val64, unsigned long flags, struct domain *pg_owner)
{
#define PG_mask(x, idx) (x ## UL << PG_shift(idx))
/* The following page types are MUTUALLY EXCLUSIVE. */
-#define PGT_none PG_mask(0, 3) /* no special uses of this page */
-#define PGT_l1_page_table PG_mask(1, 3) /* using as an L1 page table? */
-#define PGT_l2_page_table PG_mask(2, 3) /* using as an L2 page table? */
-#define PGT_l3_page_table PG_mask(3, 3) /* using as an L3 page table? */
-#define PGT_l4_page_table PG_mask(4, 3) /* using as an L4 page table? */
-#define PGT_seg_desc_page PG_mask(5, 3) /* using this page in a GDT/LDT? */
-#define PGT_writable_page PG_mask(7, 3) /* has writable mappings? */
-#define PGT_type_mask PG_mask(7, 3) /* Bits 29-31. */
+#define PGT_none PG_mask(0, 4) /* no special uses of this page */
+#define PGT_l1_page_table PG_mask(1, 4) /* using as an L1 page table? */
+#define PGT_l2_page_table PG_mask(2, 4) /* using as an L2 page table? */
+#define PGT_l3_page_table PG_mask(3, 4) /* using as an L3 page table? */
+#define PGT_l4_page_table PG_mask(4, 4) /* using as an L4 page table? */
+#define PGT_seg_desc_page PG_mask(5, 4) /* using this page in a GDT/LDT? */
+#define PGT_writable_page PG_mask(7, 4) /* has writable mappings? */
+#define PGT_shared_page PG_mask(8, 4) /* CoW sharable page */
+#define PGT_type_mask PG_mask(15, 4) /* Bits 28-31 or 60-63. */
/* Owning guest has pinned this page to its current type? */
-#define _PGT_pinned PG_shift(4)
-#define PGT_pinned PG_mask(1, 4)
+#define _PGT_pinned PG_shift(5)
+#define PGT_pinned PG_mask(1, 5)
/* Has this page been validated for use as its current type? */
-#define _PGT_validated PG_shift(5)
-#define PGT_validated PG_mask(1, 5)
+#define _PGT_validated PG_shift(6)
+#define PGT_validated PG_mask(1, 6)
/* PAE only: is this an L2 page directory containing Xen-private mappings? */
-#define _PGT_pae_xen_l2 PG_shift(6)
-#define PGT_pae_xen_l2 PG_mask(1, 6)
+#define _PGT_pae_xen_l2 PG_shift(7)
+#define PGT_pae_xen_l2 PG_mask(1, 7)
/* Has this page been *partially* validated for use as its current type? */
-#define _PGT_partial PG_shift(7)
-#define PGT_partial PG_mask(1, 7)
+#define _PGT_partial PG_shift(8)
+#define PGT_partial PG_mask(1, 8)
/* Page is locked? */
-#define _PGT_locked PG_shift(8)
-#define PGT_locked PG_mask(1, 8)
+#define _PGT_locked PG_shift(9)
+#define PGT_locked PG_mask(1, 9)
/* Count of uses of this frame as its current type. */
-#define PGT_count_width PG_shift(8)
+#define PGT_count_width PG_shift(9)
#define PGT_count_mask ((1UL<<PGT_count_width)-1)
/* Cleared when the owning guest 'frees' this page. */
struct domain *d, struct page_info *page, unsigned int memflags);
int donate_page(
struct domain *d, struct page_info *page, unsigned int memflags);
+int page_make_sharable(struct domain *d,
+ struct page_info *page,
+ int expected_refcnt);
+int page_make_private(struct domain *d, struct page_info *page);
int map_ldt_shadow_page(unsigned int);
unsigned long domain_get_maximum_gpfn(struct domain *d);
-extern struct domain *dom_xen, *dom_io; /* for vmcoreinfo */
+extern struct domain *dom_xen, *dom_io, *dom_cow; /* for vmcoreinfo */
#endif /* __ASM_X86_MM_H__ */