>>> Keir Fraser <keir@xxxxxxxxxxxxx> 15.02.07 14:24 >>>
>On 15/2/07 13:08, "Jan Beulich" <jbeulich@xxxxxxxxxx> wrote:
>> But even for the general case - wouldn't it be possible to call
>> relinquish_memory() CONFIG_PAGING_LEVELS-1 times, each time lowering
>> the level of page tables that can be forced invalid by one?
>
>Yeah, this would work. Seems acceptable.
Okay, so here's a second try:
While full linear page table support makes little sense (and would be more
complicated to implement), partial linear page table support is almost identical
to that in non-PAE, and is used (at least) by NetWare.
Of course, the question here is whether this shouldn't be generalized - all
validated page tables (except for top level PAE) could be allowed to be
installed
at lower levels using the same scheme.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
Index: 2007-02-07/xen/arch/x86/domain.c
===================================================================
--- 2007-02-07.orig/xen/arch/x86/domain.c 2007-02-07 16:27:53.000000000
+0100
+++ 2007-02-07/xen/arch/x86/domain.c 2007-02-15 15:23:47.000000000 +0100
@@ -1333,7 +1333,8 @@ int hypercall_xlat_continuation(unsigned
}
#endif
-static void relinquish_memory(struct domain *d, struct list_head *list)
+static void relinquish_memory(struct domain *d, struct list_head *list,
+ unsigned long type)
{
struct list_head *ent;
struct page_info *page;
@@ -1362,23 +1363,24 @@ static void relinquish_memory(struct dom
put_page(page);
/*
- * Forcibly invalidate base page tables at this point to break circular
- * 'linear page table' references. This is okay because MMU structures
- * are not shared across domains and this domain is now dead. Thus base
- * tables are not in use so a non-zero count means circular reference.
+ * Forcibly invalidate top-most, still valid page tables at this point
+ * to break circular 'linear page table' references. This is okay
+ * because MMU structures are not shared across domains and this domain
+ * is now dead. Thus top-most valid tables are not in use so a non-zero
+ * count means circular reference.
*/
y = page->u.inuse.type_info;
for ( ; ; )
{
x = y;
if ( likely((x & (PGT_type_mask|PGT_validated)) !=
- (PGT_base_page_table|PGT_validated)) )
+ (type|PGT_validated)) )
break;
y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated);
if ( likely(y == x) )
{
- free_page_type(page, PGT_base_page_table);
+ free_page_type(page, type);
break;
}
}
@@ -1476,8 +1478,16 @@ void domain_relinquish_resources(struct
destroy_gdt(v);
/* Relinquish every page of memory. */
- relinquish_memory(d, &d->xenpage_list);
- relinquish_memory(d, &d->page_list);
+#if CONFIG_PAGING_LEVELS >= 4
+ relinquish_memory(d, &d->xenpage_list, PGT_l4_page_table);
+ relinquish_memory(d, &d->page_list, PGT_l4_page_table);
+#endif
+#if CONFIG_PAGING_LEVELS >= 3
+ relinquish_memory(d, &d->xenpage_list, PGT_l3_page_table);
+ relinquish_memory(d, &d->page_list, PGT_l3_page_table);
+#endif
+ relinquish_memory(d, &d->xenpage_list, PGT_l2_page_table);
+ relinquish_memory(d, &d->page_list, PGT_l2_page_table);
/* Free page used by xen oprofile buffer */
free_xenoprof_pages(d);
Index: 2007-02-07/xen/arch/x86/mm.c
===================================================================
--- 2007-02-07.orig/xen/arch/x86/mm.c 2007-02-07 16:08:05.000000000 +0100
+++ 2007-02-07/xen/arch/x86/mm.c 2007-02-07 16:31:33.000000000 +0100
@@ -547,7 +547,7 @@ get_linear_pagetable(
return 0;
/*
- * Make sure that the mapped frame is an already-validated L2 table.
+ * Make sure that the mapped frame is an already-validated root table.
* If so, atomically increment the count (checking for overflow).
*/
page = mfn_to_page(pfn);
@@ -569,6 +569,51 @@ get_linear_pagetable(
}
#endif /* !CONFIG_X86_PAE */
+#if defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)
+static int
+get_l2_linear_pagetable(
+ l2_pgentry_t l2e, unsigned long l2e_pfn, struct domain *d)
+{
+ unsigned long pfn;
+
+ if ( (l2e_get_flags(l2e) & _PAGE_RW) )
+ {
+ MEM_LOG("Attempt to create linear p.t. with write perms");
+ return 0;
+ }
+
+ if ( (pfn = l2e_get_pfn(l2e)) != l2e_pfn )
+ {
+ unsigned long x, y;
+ struct page_info *page;
+
+ /* Make sure the mapped frame belongs to the correct domain. */
+ if ( unlikely(!get_page_from_pagenr(pfn, d)) )
+ return 0;
+
+ /*
+ * Make sure that the mapped frame is an already-validated L2 table.
+ * If so, atomically increment the count (checking for overflow).
+ */
+ page = mfn_to_page(pfn);
+ y = page->u.inuse.type_info;
+ do {
+ x = y;
+ if ( unlikely((x & PGT_count_mask) == PGT_count_mask) ||
+ unlikely((x & (PGT_type_mask|PGT_validated)) !=
+ (PGT_l2_page_table|PGT_validated)) )
+ {
+ put_page(page);
+ return 0;
+ }
+ }
+ while ( (y = cmpxchg(&page->u.inuse.type_info, x, x + 1)) != x );
+ }
+
+ return 1;
+}
+#endif /* !CONFIG_X86_PAE */
+
int
get_page_from_l1e(
l1_pgentry_t l1e, struct domain *d)
@@ -645,10 +690,16 @@ get_page_from_l2e(
}
rc = get_page_and_type_from_pagenr(l2e_get_pfn(l2e), PGT_l1_page_table, d);
-#if CONFIG_PAGING_LEVELS == 2
if ( unlikely(!rc) )
+ {
+#if CONFIG_PAGING_LEVELS == 2
rc = get_linear_pagetable(l2e, pfn, d);
+#else
+ if ( (CONFIG_PAGING_LEVELS == 3 || IS_COMPAT(d)) )
+ rc = get_l2_linear_pagetable(l2e, pfn, d);
#endif
+ }
+
return rc;
}
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|