From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH] x86/PAE partially linear page table support Date: Thu, 15 Feb 2007 09:41:55 +0000 Message-ID: <45D438F3.76E4.0078.0@novell.com> Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Return-path: Content-Disposition: inline List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: xen-devel@lists.xensource.com List-Id: xen-devel@lists.xenproject.org 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 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; }