From ff27f515689c50e591dd4fd6a5b47f82cf33d489 Mon Sep 17 00:00:00 2001 From: "kfraser@ubuntu.eng.hq.xensource.com" Date: Fri, 8 Sep 2006 16:45:39 -0700 Subject: [PATCH 1/5] [XEN] Remove backpointer info from page type info. No longer used. Replace with a flag for PAE final L2, needed for detecting PAE L2's which contain Xen mappings. Signed-off-by: Keir Fraser --- xen/arch/ia64/xen/mm.c | 95 +++----- xen/arch/powerpc/mm.c | 78 ++----- xen/arch/x86/domain_build.c | 8 +- xen/arch/x86/mm.c | 285 ++++++++--------------- xen/arch/x86/mm/shadow/common.c | 10 +- xen/arch/x86/mm/shadow/multi.c | 2 - xen/include/asm-ia64/mm.h | 8 - xen/include/asm-powerpc/mm.h | 8 - xen/include/asm-x86/mm.h | 50 +--- xen/include/asm-x86/x86_32/page-3level.h | 2 +- 10 files changed, 156 insertions(+), 390 deletions(-) diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 326e66c8a3..356f383534 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -1624,13 +1624,6 @@ void put_page_type(struct page_info *page) nx &= ~PGT_validated; } } - else if ( unlikely(((nx & (PGT_pinned | PGT_count_mask)) == - (PGT_pinned | 1)) && - ((nx & PGT_type_mask) != PGT_writable_page)) ) - { - /* Page is now only pinned. Make the back pointer mutable again. */ - nx |= PGT_va_mutable; - } } while ( unlikely((y = cmpxchg_rel(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -1640,6 +1633,8 @@ int get_page_type(struct page_info *page, u32 type) { u32 nx, x, y = page->u.inuse.type_info; + ASSERT(!(type & ~PGT_type_mask)); + again: do { x = y; @@ -1651,29 +1646,25 @@ int get_page_type(struct page_info *page, u32 type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) + if ( (x & PGT_type_mask) != type ) { - if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) - { - /* - * On type change we check to flush stale TLB - * entries. This may be unnecessary (e.g., page - * was GDT/LDT) but those circumstances should be - * very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); + /* + * On type change we check to flush stale TLB entries. This + * may be unnecessary (e.g., page was GDT/LDT) but those + * circumstances should be very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); - if ( unlikely(!cpus_empty(mask)) ) - { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); - } + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -1682,46 +1673,22 @@ int get_page_type(struct page_info *page, u32 type) nx |= PGT_validated; } } - else + else if ( unlikely((x & PGT_type_mask) != type) ) { - if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) - { - if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) - { - if ( ((x & PGT_type_mask) != PGT_l2_page_table) || - ((type & PGT_type_mask) != PGT_l1_page_table) ) - MEM_LOG("Bad type (saw %08x != exp %08x) " - "for mfn %016lx (pfn %016lx)", - x, type, page_to_mfn(page), - get_gpfn_from_mfn(page_to_mfn(page))); - return 0; - } - else if ( (x & PGT_va_mask) == PGT_va_mutable ) - { - /* The va backpointer is mutable, hence we update it. */ - nx &= ~PGT_va_mask; - nx |= type; /* we know the actual type is correct */ - } - else if ( ((type & PGT_va_mask) != PGT_va_mutable) && - ((type & PGT_va_mask) != (x & PGT_va_mask)) ) - { -#ifdef CONFIG_X86_PAE - /* We use backptr as extra typing. Cannot be unknown. */ - if ( (type & PGT_type_mask) == PGT_l2_page_table ) - return 0; -#endif - /* This table is possibly mapped at multiple locations. */ - nx &= ~PGT_va_mask; - nx |= PGT_va_unknown; - } - } - if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; - } + if ( ((x & PGT_type_mask) != PGT_l2_page_table) || + (type != PGT_l1_page_table) ) + MEM_LOG("Bad type (saw %08x != exp %08x) " + "for mfn %016lx (pfn %016lx)", + x, type, page_to_mfn(page), + get_gpfn_from_mfn(page_to_mfn(page))); + return 0; + } + else if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; } } while ( unlikely((y = cmpxchg_acq(&page->u.inuse.type_info, x, nx)) != x) ); diff --git a/xen/arch/powerpc/mm.c b/xen/arch/powerpc/mm.c index 1ca8f9fda4..d6ed40bce8 100644 --- a/xen/arch/powerpc/mm.c +++ b/xen/arch/powerpc/mm.c @@ -87,12 +87,6 @@ void put_page_type(struct page_info *page) /* Record TLB information for flush later. */ page->tlbflush_timestamp = tlbflush_current_time(); } - else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) == - (PGT_pinned | 1)) ) - { - /* Page is now only pinned. Make the back pointer mutable again. */ - nx |= PGT_va_mutable; - } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -102,6 +96,8 @@ int get_page_type(struct page_info *page, unsigned long type) { unsigned long nx, x, y = page->u.inuse.type_info; + ASSERT(!(type & ~PGT_type_mask)); + again: do { x = y; @@ -113,29 +109,25 @@ int get_page_type(struct page_info *page, unsigned long type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) + if ( (x & PGT_type_mask) != type ) { - if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) - { - /* - * On type change we check to flush stale TLB - * entries. This may be unnecessary (e.g., page - * was GDT/LDT) but those circumstances should be - * very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); + /* + * On type change we check to flush stale TLB entries. This + * may be unnecessary (e.g., page was GDT/LDT) but those + * circumstances should be very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); - if ( unlikely(!cpus_empty(mask)) ) - { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); - } + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -144,36 +136,16 @@ int get_page_type(struct page_info *page, unsigned long type) nx |= PGT_validated; } } - else + else if ( unlikely((x & PGT_type_mask) != type) ) { - if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) - { - if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) - { - return 0; - } - else if ( (x & PGT_va_mask) == PGT_va_mutable ) - { - /* The va backpointer is mutable, hence we update it. */ - nx &= ~PGT_va_mask; - nx |= type; /* we know the actual type is correct */ - } - else if ( (type & PGT_va_mask) != PGT_va_mutable ) - { - ASSERT((type & PGT_va_mask) != (x & PGT_va_mask)); - - /* This table is possibly mapped at multiple locations. */ - nx &= ~PGT_va_mask; - nx |= PGT_va_unknown; - } - } - if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; - } + return 0; + } + if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index dd44e827f4..8f55ef2f40 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -510,15 +510,13 @@ int construct_dom0(struct domain *d, case 1 ... 4: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l2_page_table; - page->u.inuse.type_info |= - (count-1) << PGT_va_shift; + if ( count == 4 ) + page->u.inuse.type_info |= PGT_pae_xen_l2; get_page(page, d); /* an extra ref because of readable mapping */ break; default: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l1_page_table; - page->u.inuse.type_info |= - ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-5))<u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l1_page_table; - page->u.inuse.type_info |= - ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-1))<>= L2_PAGETABLE_SHIFT; - vaddr <<= PGT_va_shift; - rc = get_page_and_type_from_pagenr( - l2e_get_pfn(l2e), PGT_l1_page_table | vaddr, d); + rc = get_page_and_type_from_pagenr(l2e_get_pfn(l2e), PGT_l1_page_table, d); #if CONFIG_PAGING_LEVELS == 2 if ( unlikely(!rc) ) rc = get_linear_pagetable(l2e, pfn, d); @@ -654,8 +650,7 @@ get_page_from_l2e( #if CONFIG_PAGING_LEVELS >= 3 static int get_page_from_l3e( - l3_pgentry_t l3e, unsigned long pfn, - struct domain *d, unsigned long vaddr) + l3_pgentry_t l3e, unsigned long pfn, struct domain *d) { int rc; @@ -668,11 +663,7 @@ get_page_from_l3e( return 0; } - vaddr >>= L3_PAGETABLE_SHIFT; - vaddr <<= PGT_va_shift; - rc = get_page_and_type_from_pagenr( - l3e_get_pfn(l3e), - PGT_l2_page_table | vaddr, d); + rc = get_page_and_type_from_pagenr(l3e_get_pfn(l3e), PGT_l2_page_table, d); return rc; } #endif /* 3 level */ @@ -680,8 +671,7 @@ get_page_from_l3e( #if CONFIG_PAGING_LEVELS >= 4 static int get_page_from_l4e( - l4_pgentry_t l4e, unsigned long pfn, - struct domain *d, unsigned long vaddr) + l4_pgentry_t l4e, unsigned long pfn, struct domain *d) { int rc; @@ -694,11 +684,7 @@ get_page_from_l4e( return 0; } - vaddr >>= L4_PAGETABLE_SHIFT; - vaddr <<= PGT_va_shift; - rc = get_page_and_type_from_pagenr( - l4e_get_pfn(l4e), - PGT_l3_page_table | vaddr, d); + rc = get_page_and_type_from_pagenr(l4e_get_pfn(l4e), PGT_l3_page_table, d); if ( unlikely(!rc) ) rc = get_linear_pagetable(l4e, pfn, d); @@ -877,8 +863,8 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) /* * The Xen-private mappings include linear mappings. The L2 thus cannot * be shared by multiple L3 tables. The test here is adequate because: - * 1. Cannot appear in slots != 3 because the page would then then have - * unknown va backpointer, which get_page_type() explicitly disallows. + * 1. Cannot appear in slots != 3 because get_page_type() checks the + * PGT_pae_xen_l2 flag, which is asserted iff the L2 appears in slot 3 * 2. Cannot appear in another page table's L3: * a. alloc_l3_table() calls this function and this check will fail * b. mod_l3_entry() disallows updates to slot 3 in an existing table @@ -888,6 +874,7 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) page = l3e_get_page(l3e3); BUG_ON(page->u.inuse.type_info & PGT_pinned); BUG_ON((page->u.inuse.type_info & PGT_count_mask) == 0); + BUG_ON(!(page->u.inuse.type_info & PGT_pae_xen_l2)); if ( (page->u.inuse.type_info & PGT_count_mask) != 1 ) { MEM_LOG("PAE L3 3rd slot is shared"); @@ -949,61 +936,17 @@ static void pae_flush_pgd( flush_tlb_mask(d->domain_dirty_cpumask); } -static inline int l1_backptr( - unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type) -{ - unsigned long l2_backptr = l2_type & PGT_va_mask; - ASSERT(l2_backptr != PGT_va_unknown); - ASSERT(l2_backptr != PGT_va_mutable); - *backptr = - ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | - (offset_in_l2 << L2_PAGETABLE_SHIFT); - return 1; -} - #elif CONFIG_X86_64 # define create_pae_xen_mappings(pl3e) (1) # define pae_flush_pgd(mfn, idx, nl3e) ((void)0) - -static inline int l1_backptr( - unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type) -{ - unsigned long l2_backptr = l2_type & PGT_va_mask; - ASSERT(l2_backptr != PGT_va_unknown); - ASSERT(l2_backptr != PGT_va_mutable); - *backptr = ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | - (offset_in_l2 << L2_PAGETABLE_SHIFT); - return 1; -} - -static inline int l2_backptr( - unsigned long *backptr, unsigned long offset_in_l3, unsigned long l3_type) -{ - unsigned long l3_backptr = l3_type & PGT_va_mask; - ASSERT(l3_backptr != PGT_va_unknown); - ASSERT(l3_backptr != PGT_va_mutable); - *backptr = ((l3_backptr >> PGT_va_shift) << L4_PAGETABLE_SHIFT) | - (offset_in_l3 << L3_PAGETABLE_SHIFT); - return 1; -} - -static inline int l3_backptr( - unsigned long *backptr, unsigned long offset_in_l4, unsigned long l4_type) -{ - *backptr = (offset_in_l4 << L4_PAGETABLE_SHIFT); - return 1; -} #else # define create_pae_xen_mappings(pl3e) (1) -# define l1_backptr(bp,l2o,l2t) \ - ({ *(bp) = (unsigned long)(l2o) << L2_PAGETABLE_SHIFT; 1; }) #endif static int alloc_l2_table(struct page_info *page, unsigned long type) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); - unsigned long vaddr; l2_pgentry_t *pl2e; int i; @@ -1013,10 +956,8 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { - if ( !l1_backptr(&vaddr, i, type) ) - goto fail; if ( is_guest_l2_slot(type, i) && - unlikely(!get_page_from_l2e(pl2e[i], pfn, d, vaddr)) ) + unlikely(!get_page_from_l2e(pl2e[i], pfn, d)) ) goto fail; adjust_guest_l2e(pl2e[i]); @@ -1051,11 +992,10 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) #if CONFIG_PAGING_LEVELS >= 3 -static int alloc_l3_table(struct page_info *page, unsigned long type) +static int alloc_l3_table(struct page_info *page) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); - unsigned long vaddr; l3_pgentry_t *pl3e; int i; @@ -1079,14 +1019,21 @@ static int alloc_l3_table(struct page_info *page, unsigned long type) pl3e = map_domain_page(pfn); for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ ) { -#if CONFIG_PAGING_LEVELS >= 4 - if ( !l2_backptr(&vaddr, i, type) ) - goto fail; -#else - vaddr = (unsigned long)i << L3_PAGETABLE_SHIFT; +#ifdef CONFIG_X86_PAE + if ( i == 3 ) + { + if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) || + (l3e_get_flags(pl3e[i]) & L3_DISALLOW_MASK) || + !get_page_and_type_from_pagenr(l3e_get_pfn(pl3e[i]), + PGT_l2_page_table | + PGT_pae_xen_l2, + d) ) + goto fail; + } + else #endif if ( is_guest_l3_slot(i) && - unlikely(!get_page_from_l3e(pl3e[i], pfn, d, vaddr)) ) + unlikely(!get_page_from_l3e(pl3e[i], pfn, d)) ) goto fail; adjust_guest_l3e(pl3e[i]); @@ -1108,27 +1055,23 @@ static int alloc_l3_table(struct page_info *page, unsigned long type) return 0; } #else -#define alloc_l3_table(page, type) (0) +#define alloc_l3_table(page) (0) #endif #if CONFIG_PAGING_LEVELS >= 4 -static int alloc_l4_table(struct page_info *page, unsigned long type) +static int alloc_l4_table(struct page_info *page) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); l4_pgentry_t *pl4e = page_to_virt(page); - unsigned long vaddr; int i; ASSERT(!shadow_mode_refcounts(d)); for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ ) { - if ( !l3_backptr(&vaddr, i, type) ) - goto fail; - if ( is_guest_l4_slot(i) && - unlikely(!get_page_from_l4e(pl4e[i], pfn, d, vaddr)) ) + unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) ) goto fail; adjust_guest_l4e(pl4e[i]); @@ -1156,7 +1099,7 @@ static int alloc_l4_table(struct page_info *page, unsigned long type) return 0; } #else -#define alloc_l4_table(page, type) (0) +#define alloc_l4_table(page) (0) #endif @@ -1190,6 +1133,8 @@ static void free_l2_table(struct page_info *page) put_page_from_l2e(pl2e[i], pfn); unmap_domain_page(pl2e); + + page->u.inuse.type_info &= ~PGT_pae_xen_l2; } @@ -1357,7 +1302,6 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, unsigned long type) { l2_pgentry_t ol2e; - unsigned long vaddr = 0; if ( unlikely(!is_guest_l2_slot(type,pgentry_ptr_to_slot(pl2e))) ) { @@ -1383,8 +1327,7 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT)) return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn); - if ( unlikely(!l1_backptr(&vaddr, pgentry_ptr_to_slot(pl2e), type)) || - unlikely(!get_page_from_l2e(nl2e, pfn, current->domain, vaddr)) ) + if ( unlikely(!get_page_from_l2e(nl2e, pfn, current->domain)) ) return 0; if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn)) ) @@ -1407,11 +1350,9 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, /* Update the L3 entry at pl3e to new value nl3e. pl3e is within frame pfn. */ static int mod_l3_entry(l3_pgentry_t *pl3e, l3_pgentry_t nl3e, - unsigned long pfn, - unsigned long type) + unsigned long pfn) { l3_pgentry_t ol3e; - unsigned long vaddr; int okay; if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) ) @@ -1447,16 +1388,8 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT)) return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn); -#if CONFIG_PAGING_LEVELS >= 4 - if ( unlikely(!l2_backptr(&vaddr, pgentry_ptr_to_slot(pl3e), type)) || - unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) ) + if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain)) ) return 0; -#else - vaddr = (((unsigned long)pl3e & ~PAGE_MASK) / sizeof(l3_pgentry_t)) - << L3_PAGETABLE_SHIFT; - if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) ) - return 0; -#endif if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn)) ) { @@ -1485,11 +1418,9 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, /* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */ static int mod_l4_entry(l4_pgentry_t *pl4e, l4_pgentry_t nl4e, - unsigned long pfn, - unsigned long type) + unsigned long pfn) { l4_pgentry_t ol4e; - unsigned long vaddr; if ( unlikely(!is_guest_l4_slot(pgentry_ptr_to_slot(pl4e))) ) { @@ -1515,8 +1446,7 @@ static int mod_l4_entry(l4_pgentry_t *pl4e, if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT)) return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn); - if ( unlikely(!l3_backptr(&vaddr, pgentry_ptr_to_slot(pl4e), type)) || - unlikely(!get_page_from_l4e(nl4e, pfn, current->domain, vaddr)) ) + if ( unlikely(!get_page_from_l4e(nl4e, pfn, current->domain)) ) return 0; if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn)) ) @@ -1550,9 +1480,9 @@ int alloc_page_type(struct page_info *page, unsigned long type) case PGT_l2_page_table: return alloc_l2_table(page, type); case PGT_l3_page_table: - return alloc_l3_table(page, type); + return alloc_l3_table(page); case PGT_l4_page_table: - return alloc_l4_table(page, type); + return alloc_l4_table(page); case PGT_gdt_page: case PGT_ldt_page: return alloc_segdesc_page(page); @@ -1672,12 +1602,6 @@ void put_page_type(struct page_info *page) /* Record TLB information for flush later. */ page->tlbflush_timestamp = tlbflush_current_time(); } - else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) == - (PGT_pinned|PGT_l1_page_table|1)) ) - { - /* Page is now only pinned. Make the back pointer mutable again. */ - nx |= PGT_va_mutable; - } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -1687,6 +1611,8 @@ int get_page_type(struct page_info *page, unsigned long type) { unsigned long nx, x, y = page->u.inuse.type_info; + ASSERT(!(type & ~(PGT_type_mask | PGT_pae_xen_l2))); + again: do { x = y; @@ -1698,29 +1624,26 @@ int get_page_type(struct page_info *page, unsigned long type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) + ASSERT(!(x & PGT_pae_xen_l2)); + if ( (x & PGT_type_mask) != type ) { - if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) - { - /* - * On type change we check to flush stale TLB - * entries. This may be unnecessary (e.g., page - * was GDT/LDT) but those circumstances should be - * very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); + /* + * On type change we check to flush stale TLB entries. This + * may be unnecessary (e.g., page was GDT/LDT) but those + * circumstances should be very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); - if ( unlikely(!cpus_empty(mask)) ) - { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); - } + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -1729,51 +1652,23 @@ int get_page_type(struct page_info *page, unsigned long type) nx |= PGT_validated; } } - else + else if ( unlikely((x & (PGT_type_mask|PGT_pae_xen_l2)) != type) ) { - if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) - { - if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) - { - if ( ((x & PGT_type_mask) != PGT_l2_page_table) || - ((type & PGT_type_mask) != PGT_l1_page_table) ) - MEM_LOG("Bad type (saw %" PRtype_info - " != exp %" PRtype_info ") " - "for mfn %lx (pfn %lx)", - x, type, page_to_mfn(page), - get_gpfn_from_mfn(page_to_mfn(page))); - return 0; - } - else if ( (x & PGT_va_mask) == PGT_va_mutable ) - { - /* The va backpointer is mutable, hence we update it. */ - nx &= ~PGT_va_mask; - nx |= type; /* we know the actual type is correct */ - } - else if ( (type & PGT_va_mask) != PGT_va_mutable ) - { - ASSERT((type & PGT_va_mask) != (x & PGT_va_mask)); -#ifdef CONFIG_X86_PAE - /* We use backptr as extra typing. Cannot be unknown. */ - if ( (type & PGT_type_mask) == PGT_l2_page_table ) - return 0; -#endif - /* Fixme: add code to propagate va_unknown to subtables. */ - if ( ((type & PGT_type_mask) >= PGT_l2_page_table) && - !shadow_mode_refcounts(page_get_owner(page)) ) - return 0; - /* This table is possibly mapped at multiple locations. */ - nx &= ~PGT_va_mask; - nx |= PGT_va_unknown; - } - } - if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; - } + if ( ((x & PGT_type_mask) != PGT_l2_page_table) || + (type != PGT_l1_page_table) ) + MEM_LOG("Bad type (saw %" PRtype_info + " != exp %" PRtype_info ") " + "for mfn %lx (pfn %lx)", + x, type, page_to_mfn(page), + get_gpfn_from_mfn(page_to_mfn(page))); + return 0; + } + else if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); @@ -2030,19 +1925,25 @@ int do_mmuext_op( switch ( op.cmd ) { case MMUEXT_PIN_L1_TABLE: - type = PGT_l1_page_table | PGT_va_mutable; + type = PGT_l1_page_table; goto pin_page; case MMUEXT_PIN_L2_TABLE: - case MMUEXT_PIN_L3_TABLE: - case MMUEXT_PIN_L4_TABLE: - /* Ignore pinning of subdirectories. */ - if ( (op.cmd - MMUEXT_PIN_L1_TABLE) != (CONFIG_PAGING_LEVELS - 1) ) - break; + type = PGT_l2_page_table; + goto pin_page; - type = PGT_root_page_table; + case MMUEXT_PIN_L3_TABLE: + type = PGT_l3_page_table; + goto pin_page; + + case MMUEXT_PIN_L4_TABLE: + type = PGT_l4_page_table; pin_page: + /* Ignore pinning of invalid paging levels. */ + if ( (op.cmd - MMUEXT_PIN_L1_TABLE) > (CONFIG_PAGING_LEVELS - 1) ) + break; + if ( shadow_mode_refcounts(FOREIGNDOM) ) break; @@ -2326,7 +2227,7 @@ int do_mmu_update( } if ( unlikely(!get_page_type( - page, type_info & (PGT_type_mask|PGT_va_mask))) ) + page, type_info & PGT_type_mask)) ) goto not_a_pt; switch ( type_info & PGT_type_mask ) @@ -2348,7 +2249,7 @@ int do_mmu_update( case PGT_l3_page_table: { l3_pgentry_t l3e = l3e_from_intpte(req.val); - okay = mod_l3_entry(va, l3e, mfn, type_info); + okay = mod_l3_entry(va, l3e, mfn); } break; #endif @@ -2356,7 +2257,7 @@ int do_mmu_update( case PGT_l4_page_table: { l4_pgentry_t l4e = l4e_from_intpte(req.val); - okay = mod_l4_entry(va, l4e, mfn, type_info); + okay = mod_l4_entry(va, l4e, mfn); } break; #endif @@ -2454,7 +2355,7 @@ static int create_grant_pte_mapping( void *va; unsigned long gmfn, mfn; struct page_info *page; - u32 type_info; + u32 type; l1_pgentry_t ol1e; struct domain *d = v->domain; @@ -2475,9 +2376,8 @@ static int create_grant_pte_mapping( va = (void *)((unsigned long)va + (pte_addr & ~PAGE_MASK)); page = mfn_to_page(mfn); - type_info = page->u.inuse.type_info; - if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) || - !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) ) + type = page->u.inuse.type_info & PGT_type_mask; + if ( (type != PGT_l1_page_table) || !get_page_type(page, type) ) { MEM_LOG("Grant map attempted to update a non-L1 page"); rc = GNTST_general_error; @@ -2511,7 +2411,7 @@ static int destroy_grant_pte_mapping( void *va; unsigned long gmfn, mfn; struct page_info *page; - u32 type_info; + u32 type; l1_pgentry_t ol1e; gmfn = addr >> PAGE_SHIFT; @@ -2527,9 +2427,8 @@ static int destroy_grant_pte_mapping( va = (void *)((unsigned long)va + (addr & ~PAGE_MASK)); page = mfn_to_page(mfn); - type_info = page->u.inuse.type_info; - if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) || - !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) ) + type = page->u.inuse.type_info & PGT_type_mask; + if ( (type != PGT_l1_page_table) || !get_page_type(page, type) ) { MEM_LOG("Grant map attempted to update a non-L1 page"); rc = GNTST_general_error; diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index 664b09f209..bdccf7a2d9 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -21,8 +21,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define SHADOW 1 - #include #include #include @@ -225,7 +223,6 @@ struct x86_emulate_ops shadow_emulator_ops = { .cmpxchg8b_emulated = sh_x86_emulate_cmpxchg8b_emulated, }; - /**************************************************************************/ /* Code for "promoting" a guest page to the point where the shadow code is * willing to let it be treated as a guest page table. This generally @@ -235,7 +232,6 @@ struct x86_emulate_ops shadow_emulator_ops = { void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type) { struct page_info *page = mfn_to_page(gmfn); - unsigned long type_info; ASSERT(valid_mfn(gmfn)); @@ -251,10 +247,8 @@ void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type) // vcpu or not, or even what kind of type we get; we just want the type // count to be > 0. // - do { - type_info = - page->u.inuse.type_info & (PGT_type_mask | PGT_va_mask); - } while ( !get_page_type(page, type_info) ); + while ( !get_page_type(page, page->u.inuse.type_info & PGT_type_mask) ) + continue; // Now that the type ref is non-zero, we can safely use the // shadow_flags. diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index ace6a258f3..840c516fd6 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -35,8 +35,6 @@ // space for both PV and HVM guests. // -#define SHADOW 1 - #include #include #include diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index 111325936d..862b10176d 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -103,14 +103,6 @@ struct page_info #define _PGT_pinned 27 #define PGT_pinned (1U<<_PGT_pinned) - /* The 27 most significant bits of virt address if this is a page table. */ -#define PGT_va_shift 32 -#define PGT_va_mask ((unsigned long)((1U<<28)-1)<> PGT_va_shift) != 3) || \ + ( !((t) & PGT_pae_xen_l2) || \ ((s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES - 1))) ) #define is_guest_l3_slot(s) (1) From d37211bc5ebda671250059f2a235af83988b3037 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Sat, 9 Sep 2006 20:48:16 +0100 Subject: [PATCH 2/5] [LINUX] Move .bss declaration after .data.* in x86_64 linker script. Older binutils (prior to 2.16) have a problem with the linker script resulting from the change introducing explicit segment maps. Namely does the respective linker not properly handle @nobits sections (i.e. .bss) sitting between @progbits ones (i.e. .data.*). The .bss section must therefore be moved past all initialized sections (as is already the case on i386). Replacement patch attached. From: Jan Beulich Signed-off-by: Ian Campbell --- ...ns-into-a-pt_note-segment-in-vmlinux.patch | 35 +++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch b/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch index 1dd70cf728..9c0cd81d76 100644 --- a/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch +++ b/patches/linux-2.6.16.13/x86_64-put-note-sections-into-a-pt_note-segment-in-vmlinux.patch @@ -1,5 +1,3 @@ -diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S -index 7c4de31..ef418b3 100644 --- a/arch/x86_64/kernel/vmlinux.lds.S +++ b/arch/x86_64/kernel/vmlinux.lds.S @@ -13,6 +13,12 @@ OUTPUT_FORMAT("elf64-x86-64", "elf64-x86 @@ -24,7 +22,7 @@ index 7c4de31..ef418b3 100644 /* out-of-line lock text */ .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) } -@@ -57,7 +63,7 @@ #endif +@@ -57,17 +63,10 @@ #endif .data : AT(ADDR(.data) - LOAD_OFFSET) { *(.data) CONSTRUCTORS @@ -33,7 +31,17 @@ index 7c4de31..ef418b3 100644 _edata = .; /* End of data section */ -@@ -89,7 +95,7 @@ #define VVIRT_OFFSET (VSYSCALL_ADDR - VS +- __bss_start = .; /* BSS */ +- .bss : AT(ADDR(.bss) - LOAD_OFFSET) { +- *(.bss.page_aligned) +- *(.bss) +- } +- __bss_stop = .; +- + . = ALIGN(PAGE_SIZE); + . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { +@@ -89,7 +88,7 @@ #define VVIRT_OFFSET (VSYSCALL_ADDR - VS #define VVIRT(x) (ADDR(x) - VVIRT_OFFSET) . = VSYSCALL_ADDR; @@ -42,7 +50,7 @@ index 7c4de31..ef418b3 100644 __vsyscall_0 = VSYSCALL_VIRT_ADDR; . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); -@@ -132,7 +138,7 @@ #undef VVIRT +@@ -132,7 +131,7 @@ #undef VVIRT . = ALIGN(8192); /* init_task */ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { *(.data.init_task) @@ -51,7 +59,22 @@ index 7c4de31..ef418b3 100644 . = ALIGN(4096); .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { -@@ -235,4 +241,6 @@ #endif +@@ -222,6 +221,14 @@ SECTIONS + . = ALIGN(4096); + __nosave_end = .; + ++ __bss_start = .; /* BSS */ ++ . = ALIGN(4096); ++ .bss : AT(ADDR(.bss) - LOAD_OFFSET) { ++ *(.bss.page_aligned) ++ *(.bss) ++ } ++ __bss_stop = .; ++ + _end = . ; + + /* Sections to be discarded */ +@@ -235,4 +242,6 @@ #endif STABS_DEBUG DWARF_DEBUG From 84ef1509a4f816997a679d0e0daccdff245abc63 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 11 Sep 2006 01:55:03 +0100 Subject: [PATCH 3/5] [XEN] Revert changeset 11438. Needs fixing for PAE. Signed-off-by: Keir Fraser --- xen/arch/ia64/xen/mm.c | 95 +++++--- xen/arch/powerpc/mm.c | 78 +++++-- xen/arch/x86/domain_build.c | 8 +- xen/arch/x86/mm.c | 283 +++++++++++++++-------- xen/arch/x86/mm/shadow/common.c | 10 +- xen/arch/x86/mm/shadow/multi.c | 2 + xen/include/asm-ia64/mm.h | 8 + xen/include/asm-powerpc/mm.h | 8 + xen/include/asm-x86/mm.h | 50 +++- xen/include/asm-x86/x86_32/page-3level.h | 2 +- 10 files changed, 389 insertions(+), 155 deletions(-) diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 356f383534..326e66c8a3 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -1624,6 +1624,13 @@ void put_page_type(struct page_info *page) nx &= ~PGT_validated; } } + else if ( unlikely(((nx & (PGT_pinned | PGT_count_mask)) == + (PGT_pinned | 1)) && + ((nx & PGT_type_mask) != PGT_writable_page)) ) + { + /* Page is now only pinned. Make the back pointer mutable again. */ + nx |= PGT_va_mutable; + } } while ( unlikely((y = cmpxchg_rel(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -1633,8 +1640,6 @@ int get_page_type(struct page_info *page, u32 type) { u32 nx, x, y = page->u.inuse.type_info; - ASSERT(!(type & ~PGT_type_mask)); - again: do { x = y; @@ -1646,25 +1651,29 @@ int get_page_type(struct page_info *page, u32 type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - if ( (x & PGT_type_mask) != type ) + if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) { - /* - * On type change we check to flush stale TLB entries. This - * may be unnecessary (e.g., page was GDT/LDT) but those - * circumstances should be very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); - - if ( unlikely(!cpus_empty(mask)) ) + if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); + /* + * On type change we check to flush stale TLB + * entries. This may be unnecessary (e.g., page + * was GDT/LDT) but those circumstances should be + * very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); + + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); + } } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -1673,22 +1682,46 @@ int get_page_type(struct page_info *page, u32 type) nx |= PGT_validated; } } - else if ( unlikely((x & PGT_type_mask) != type) ) + else { - if ( ((x & PGT_type_mask) != PGT_l2_page_table) || - (type != PGT_l1_page_table) ) - MEM_LOG("Bad type (saw %08x != exp %08x) " - "for mfn %016lx (pfn %016lx)", - x, type, page_to_mfn(page), - get_gpfn_from_mfn(page_to_mfn(page))); - return 0; - } - else if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; + if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) + { + if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) + { + if ( ((x & PGT_type_mask) != PGT_l2_page_table) || + ((type & PGT_type_mask) != PGT_l1_page_table) ) + MEM_LOG("Bad type (saw %08x != exp %08x) " + "for mfn %016lx (pfn %016lx)", + x, type, page_to_mfn(page), + get_gpfn_from_mfn(page_to_mfn(page))); + return 0; + } + else if ( (x & PGT_va_mask) == PGT_va_mutable ) + { + /* The va backpointer is mutable, hence we update it. */ + nx &= ~PGT_va_mask; + nx |= type; /* we know the actual type is correct */ + } + else if ( ((type & PGT_va_mask) != PGT_va_mutable) && + ((type & PGT_va_mask) != (x & PGT_va_mask)) ) + { +#ifdef CONFIG_X86_PAE + /* We use backptr as extra typing. Cannot be unknown. */ + if ( (type & PGT_type_mask) == PGT_l2_page_table ) + return 0; +#endif + /* This table is possibly mapped at multiple locations. */ + nx &= ~PGT_va_mask; + nx |= PGT_va_unknown; + } + } + if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; + } } } while ( unlikely((y = cmpxchg_acq(&page->u.inuse.type_info, x, nx)) != x) ); diff --git a/xen/arch/powerpc/mm.c b/xen/arch/powerpc/mm.c index d6ed40bce8..1ca8f9fda4 100644 --- a/xen/arch/powerpc/mm.c +++ b/xen/arch/powerpc/mm.c @@ -87,6 +87,12 @@ void put_page_type(struct page_info *page) /* Record TLB information for flush later. */ page->tlbflush_timestamp = tlbflush_current_time(); } + else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) == + (PGT_pinned | 1)) ) + { + /* Page is now only pinned. Make the back pointer mutable again. */ + nx |= PGT_va_mutable; + } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -96,8 +102,6 @@ int get_page_type(struct page_info *page, unsigned long type) { unsigned long nx, x, y = page->u.inuse.type_info; - ASSERT(!(type & ~PGT_type_mask)); - again: do { x = y; @@ -109,25 +113,29 @@ int get_page_type(struct page_info *page, unsigned long type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - if ( (x & PGT_type_mask) != type ) + if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) { - /* - * On type change we check to flush stale TLB entries. This - * may be unnecessary (e.g., page was GDT/LDT) but those - * circumstances should be very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); - - if ( unlikely(!cpus_empty(mask)) ) + if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); + /* + * On type change we check to flush stale TLB + * entries. This may be unnecessary (e.g., page + * was GDT/LDT) but those circumstances should be + * very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); + + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); + } } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -136,16 +144,36 @@ int get_page_type(struct page_info *page, unsigned long type) nx |= PGT_validated; } } - else if ( unlikely((x & PGT_type_mask) != type) ) + else { - return 0; - } - if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; + if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) + { + if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) + { + return 0; + } + else if ( (x & PGT_va_mask) == PGT_va_mutable ) + { + /* The va backpointer is mutable, hence we update it. */ + nx &= ~PGT_va_mask; + nx |= type; /* we know the actual type is correct */ + } + else if ( (type & PGT_va_mask) != PGT_va_mutable ) + { + ASSERT((type & PGT_va_mask) != (x & PGT_va_mask)); + + /* This table is possibly mapped at multiple locations. */ + nx &= ~PGT_va_mask; + nx |= PGT_va_unknown; + } + } + if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; + } } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 8f55ef2f40..dd44e827f4 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -510,13 +510,15 @@ int construct_dom0(struct domain *d, case 1 ... 4: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l2_page_table; - if ( count == 4 ) - page->u.inuse.type_info |= PGT_pae_xen_l2; + page->u.inuse.type_info |= + (count-1) << PGT_va_shift; get_page(page, d); /* an extra ref because of readable mapping */ break; default: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l1_page_table; + page->u.inuse.type_info |= + ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-5))<u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l1_page_table; + page->u.inuse.type_info |= + ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-1))<>= L2_PAGETABLE_SHIFT; + vaddr <<= PGT_va_shift; + rc = get_page_and_type_from_pagenr( + l2e_get_pfn(l2e), PGT_l1_page_table | vaddr, d); #if CONFIG_PAGING_LEVELS == 2 if ( unlikely(!rc) ) rc = get_linear_pagetable(l2e, pfn, d); @@ -650,7 +654,8 @@ get_page_from_l2e( #if CONFIG_PAGING_LEVELS >= 3 static int get_page_from_l3e( - l3_pgentry_t l3e, unsigned long pfn, struct domain *d) + l3_pgentry_t l3e, unsigned long pfn, + struct domain *d, unsigned long vaddr) { int rc; @@ -663,7 +668,11 @@ get_page_from_l3e( return 0; } - rc = get_page_and_type_from_pagenr(l3e_get_pfn(l3e), PGT_l2_page_table, d); + vaddr >>= L3_PAGETABLE_SHIFT; + vaddr <<= PGT_va_shift; + rc = get_page_and_type_from_pagenr( + l3e_get_pfn(l3e), + PGT_l2_page_table | vaddr, d); return rc; } #endif /* 3 level */ @@ -671,7 +680,8 @@ get_page_from_l3e( #if CONFIG_PAGING_LEVELS >= 4 static int get_page_from_l4e( - l4_pgentry_t l4e, unsigned long pfn, struct domain *d) + l4_pgentry_t l4e, unsigned long pfn, + struct domain *d, unsigned long vaddr) { int rc; @@ -684,7 +694,11 @@ get_page_from_l4e( return 0; } - rc = get_page_and_type_from_pagenr(l4e_get_pfn(l4e), PGT_l3_page_table, d); + vaddr >>= L4_PAGETABLE_SHIFT; + vaddr <<= PGT_va_shift; + rc = get_page_and_type_from_pagenr( + l4e_get_pfn(l4e), + PGT_l3_page_table | vaddr, d); if ( unlikely(!rc) ) rc = get_linear_pagetable(l4e, pfn, d); @@ -863,8 +877,8 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) /* * The Xen-private mappings include linear mappings. The L2 thus cannot * be shared by multiple L3 tables. The test here is adequate because: - * 1. Cannot appear in slots != 3 because get_page_type() checks the - * PGT_pae_xen_l2 flag, which is asserted iff the L2 appears in slot 3 + * 1. Cannot appear in slots != 3 because the page would then then have + * unknown va backpointer, which get_page_type() explicitly disallows. * 2. Cannot appear in another page table's L3: * a. alloc_l3_table() calls this function and this check will fail * b. mod_l3_entry() disallows updates to slot 3 in an existing table @@ -874,7 +888,6 @@ static int create_pae_xen_mappings(l3_pgentry_t *pl3e) page = l3e_get_page(l3e3); BUG_ON(page->u.inuse.type_info & PGT_pinned); BUG_ON((page->u.inuse.type_info & PGT_count_mask) == 0); - BUG_ON(!(page->u.inuse.type_info & PGT_pae_xen_l2)); if ( (page->u.inuse.type_info & PGT_count_mask) != 1 ) { MEM_LOG("PAE L3 3rd slot is shared"); @@ -936,17 +949,61 @@ static void pae_flush_pgd( flush_tlb_mask(d->domain_dirty_cpumask); } +static inline int l1_backptr( + unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type) +{ + unsigned long l2_backptr = l2_type & PGT_va_mask; + ASSERT(l2_backptr != PGT_va_unknown); + ASSERT(l2_backptr != PGT_va_mutable); + *backptr = + ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | + (offset_in_l2 << L2_PAGETABLE_SHIFT); + return 1; +} + #elif CONFIG_X86_64 # define create_pae_xen_mappings(pl3e) (1) # define pae_flush_pgd(mfn, idx, nl3e) ((void)0) + +static inline int l1_backptr( + unsigned long *backptr, unsigned long offset_in_l2, unsigned long l2_type) +{ + unsigned long l2_backptr = l2_type & PGT_va_mask; + ASSERT(l2_backptr != PGT_va_unknown); + ASSERT(l2_backptr != PGT_va_mutable); + *backptr = ((l2_backptr >> PGT_va_shift) << L3_PAGETABLE_SHIFT) | + (offset_in_l2 << L2_PAGETABLE_SHIFT); + return 1; +} + +static inline int l2_backptr( + unsigned long *backptr, unsigned long offset_in_l3, unsigned long l3_type) +{ + unsigned long l3_backptr = l3_type & PGT_va_mask; + ASSERT(l3_backptr != PGT_va_unknown); + ASSERT(l3_backptr != PGT_va_mutable); + *backptr = ((l3_backptr >> PGT_va_shift) << L4_PAGETABLE_SHIFT) | + (offset_in_l3 << L3_PAGETABLE_SHIFT); + return 1; +} + +static inline int l3_backptr( + unsigned long *backptr, unsigned long offset_in_l4, unsigned long l4_type) +{ + *backptr = (offset_in_l4 << L4_PAGETABLE_SHIFT); + return 1; +} #else # define create_pae_xen_mappings(pl3e) (1) +# define l1_backptr(bp,l2o,l2t) \ + ({ *(bp) = (unsigned long)(l2o) << L2_PAGETABLE_SHIFT; 1; }) #endif static int alloc_l2_table(struct page_info *page, unsigned long type) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); + unsigned long vaddr; l2_pgentry_t *pl2e; int i; @@ -956,8 +1013,10 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) for ( i = 0; i < L2_PAGETABLE_ENTRIES; i++ ) { + if ( !l1_backptr(&vaddr, i, type) ) + goto fail; if ( is_guest_l2_slot(type, i) && - unlikely(!get_page_from_l2e(pl2e[i], pfn, d)) ) + unlikely(!get_page_from_l2e(pl2e[i], pfn, d, vaddr)) ) goto fail; adjust_guest_l2e(pl2e[i]); @@ -992,10 +1051,11 @@ static int alloc_l2_table(struct page_info *page, unsigned long type) #if CONFIG_PAGING_LEVELS >= 3 -static int alloc_l3_table(struct page_info *page) +static int alloc_l3_table(struct page_info *page, unsigned long type) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); + unsigned long vaddr; l3_pgentry_t *pl3e; int i; @@ -1019,21 +1079,14 @@ static int alloc_l3_table(struct page_info *page) pl3e = map_domain_page(pfn); for ( i = 0; i < L3_PAGETABLE_ENTRIES; i++ ) { -#ifdef CONFIG_X86_PAE - if ( i == 3 ) - { - if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) || - (l3e_get_flags(pl3e[i]) & L3_DISALLOW_MASK) || - !get_page_and_type_from_pagenr(l3e_get_pfn(pl3e[i]), - PGT_l2_page_table | - PGT_pae_xen_l2, - d) ) - goto fail; - } - else +#if CONFIG_PAGING_LEVELS >= 4 + if ( !l2_backptr(&vaddr, i, type) ) + goto fail; +#else + vaddr = (unsigned long)i << L3_PAGETABLE_SHIFT; #endif if ( is_guest_l3_slot(i) && - unlikely(!get_page_from_l3e(pl3e[i], pfn, d)) ) + unlikely(!get_page_from_l3e(pl3e[i], pfn, d, vaddr)) ) goto fail; adjust_guest_l3e(pl3e[i]); @@ -1055,23 +1108,27 @@ static int alloc_l3_table(struct page_info *page) return 0; } #else -#define alloc_l3_table(page) (0) +#define alloc_l3_table(page, type) (0) #endif #if CONFIG_PAGING_LEVELS >= 4 -static int alloc_l4_table(struct page_info *page) +static int alloc_l4_table(struct page_info *page, unsigned long type) { struct domain *d = page_get_owner(page); unsigned long pfn = page_to_mfn(page); l4_pgentry_t *pl4e = page_to_virt(page); + unsigned long vaddr; int i; ASSERT(!shadow_mode_refcounts(d)); for ( i = 0; i < L4_PAGETABLE_ENTRIES; i++ ) { + if ( !l3_backptr(&vaddr, i, type) ) + goto fail; + if ( is_guest_l4_slot(i) && - unlikely(!get_page_from_l4e(pl4e[i], pfn, d)) ) + unlikely(!get_page_from_l4e(pl4e[i], pfn, d, vaddr)) ) goto fail; adjust_guest_l4e(pl4e[i]); @@ -1099,7 +1156,7 @@ static int alloc_l4_table(struct page_info *page) return 0; } #else -#define alloc_l4_table(page) (0) +#define alloc_l4_table(page, type) (0) #endif @@ -1133,8 +1190,6 @@ static void free_l2_table(struct page_info *page) put_page_from_l2e(pl2e[i], pfn); unmap_domain_page(pl2e); - - page->u.inuse.type_info &= ~PGT_pae_xen_l2; } @@ -1302,6 +1357,7 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, unsigned long type) { l2_pgentry_t ol2e; + unsigned long vaddr = 0; if ( unlikely(!is_guest_l2_slot(type,pgentry_ptr_to_slot(pl2e))) ) { @@ -1327,7 +1383,8 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT)) return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn); - if ( unlikely(!get_page_from_l2e(nl2e, pfn, current->domain)) ) + if ( unlikely(!l1_backptr(&vaddr, pgentry_ptr_to_slot(pl2e), type)) || + unlikely(!get_page_from_l2e(nl2e, pfn, current->domain, vaddr)) ) return 0; if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn)) ) @@ -1350,9 +1407,11 @@ static int mod_l2_entry(l2_pgentry_t *pl2e, /* Update the L3 entry at pl3e to new value nl3e. pl3e is within frame pfn. */ static int mod_l3_entry(l3_pgentry_t *pl3e, l3_pgentry_t nl3e, - unsigned long pfn) + unsigned long pfn, + unsigned long type) { l3_pgentry_t ol3e; + unsigned long vaddr; int okay; if ( unlikely(!is_guest_l3_slot(pgentry_ptr_to_slot(pl3e))) ) @@ -1388,8 +1447,16 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT)) return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn); - if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain)) ) +#if CONFIG_PAGING_LEVELS >= 4 + if ( unlikely(!l2_backptr(&vaddr, pgentry_ptr_to_slot(pl3e), type)) || + unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) ) return 0; +#else + vaddr = (((unsigned long)pl3e & ~PAGE_MASK) / sizeof(l3_pgentry_t)) + << L3_PAGETABLE_SHIFT; + if ( unlikely(!get_page_from_l3e(nl3e, pfn, current->domain, vaddr)) ) + return 0; +#endif if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn)) ) { @@ -1418,9 +1485,11 @@ static int mod_l3_entry(l3_pgentry_t *pl3e, /* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */ static int mod_l4_entry(l4_pgentry_t *pl4e, l4_pgentry_t nl4e, - unsigned long pfn) + unsigned long pfn, + unsigned long type) { l4_pgentry_t ol4e; + unsigned long vaddr; if ( unlikely(!is_guest_l4_slot(pgentry_ptr_to_slot(pl4e))) ) { @@ -1446,7 +1515,8 @@ static int mod_l4_entry(l4_pgentry_t *pl4e, if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT)) return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn); - if ( unlikely(!get_page_from_l4e(nl4e, pfn, current->domain)) ) + if ( unlikely(!l3_backptr(&vaddr, pgentry_ptr_to_slot(pl4e), type)) || + unlikely(!get_page_from_l4e(nl4e, pfn, current->domain, vaddr)) ) return 0; if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn)) ) @@ -1480,9 +1550,9 @@ int alloc_page_type(struct page_info *page, unsigned long type) case PGT_l2_page_table: return alloc_l2_table(page, type); case PGT_l3_page_table: - return alloc_l3_table(page); + return alloc_l3_table(page, type); case PGT_l4_page_table: - return alloc_l4_table(page); + return alloc_l4_table(page, type); case PGT_gdt_page: case PGT_ldt_page: return alloc_segdesc_page(page); @@ -1602,6 +1672,12 @@ void put_page_type(struct page_info *page) /* Record TLB information for flush later. */ page->tlbflush_timestamp = tlbflush_current_time(); } + else if ( unlikely((nx & (PGT_pinned|PGT_type_mask|PGT_count_mask)) == + (PGT_pinned|PGT_l1_page_table|1)) ) + { + /* Page is now only pinned. Make the back pointer mutable again. */ + nx |= PGT_va_mutable; + } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); } @@ -1611,8 +1687,6 @@ int get_page_type(struct page_info *page, unsigned long type) { unsigned long nx, x, y = page->u.inuse.type_info; - ASSERT(!(type & ~(PGT_type_mask | PGT_pae_xen_l2))); - again: do { x = y; @@ -1624,26 +1698,29 @@ int get_page_type(struct page_info *page, unsigned long type) } else if ( unlikely((x & PGT_count_mask) == 0) ) { - ASSERT(!(x & PGT_pae_xen_l2)); - if ( (x & PGT_type_mask) != type ) + if ( (x & (PGT_type_mask|PGT_va_mask)) != type ) { - /* - * On type change we check to flush stale TLB entries. This - * may be unnecessary (e.g., page was GDT/LDT) but those - * circumstances should be very rare. - */ - cpumask_t mask = - page_get_owner(page)->domain_dirty_cpumask; - tlbflush_filter(mask, page->tlbflush_timestamp); - - if ( unlikely(!cpus_empty(mask)) ) + if ( (x & PGT_type_mask) != (type & PGT_type_mask) ) { - perfc_incrc(need_flush_tlb_flush); - flush_tlb_mask(mask); + /* + * On type change we check to flush stale TLB + * entries. This may be unnecessary (e.g., page + * was GDT/LDT) but those circumstances should be + * very rare. + */ + cpumask_t mask = + page_get_owner(page)->domain_dirty_cpumask; + tlbflush_filter(mask, page->tlbflush_timestamp); + + if ( unlikely(!cpus_empty(mask)) ) + { + perfc_incrc(need_flush_tlb_flush); + flush_tlb_mask(mask); + } } /* We lose existing type, back pointer, and validity. */ - nx &= ~(PGT_type_mask | PGT_validated); + nx &= ~(PGT_type_mask | PGT_va_mask | PGT_validated); nx |= type; /* No special validation needed for writable pages. */ @@ -1652,23 +1729,51 @@ int get_page_type(struct page_info *page, unsigned long type) nx |= PGT_validated; } } - else if ( unlikely((x & (PGT_type_mask|PGT_pae_xen_l2)) != type) ) + else { - if ( ((x & PGT_type_mask) != PGT_l2_page_table) || - (type != PGT_l1_page_table) ) - MEM_LOG("Bad type (saw %" PRtype_info - " != exp %" PRtype_info ") " - "for mfn %lx (pfn %lx)", - x, type, page_to_mfn(page), - get_gpfn_from_mfn(page_to_mfn(page))); - return 0; - } - else if ( unlikely(!(x & PGT_validated)) ) - { - /* Someone else is updating validation of this page. Wait... */ - while ( (y = page->u.inuse.type_info) == x ) - cpu_relax(); - goto again; + if ( unlikely((x & (PGT_type_mask|PGT_va_mask)) != type) ) + { + if ( unlikely((x & PGT_type_mask) != (type & PGT_type_mask) ) ) + { + if ( ((x & PGT_type_mask) != PGT_l2_page_table) || + ((type & PGT_type_mask) != PGT_l1_page_table) ) + MEM_LOG("Bad type (saw %" PRtype_info + " != exp %" PRtype_info ") " + "for mfn %lx (pfn %lx)", + x, type, page_to_mfn(page), + get_gpfn_from_mfn(page_to_mfn(page))); + return 0; + } + else if ( (x & PGT_va_mask) == PGT_va_mutable ) + { + /* The va backpointer is mutable, hence we update it. */ + nx &= ~PGT_va_mask; + nx |= type; /* we know the actual type is correct */ + } + else if ( (type & PGT_va_mask) != PGT_va_mutable ) + { + ASSERT((type & PGT_va_mask) != (x & PGT_va_mask)); +#ifdef CONFIG_X86_PAE + /* We use backptr as extra typing. Cannot be unknown. */ + if ( (type & PGT_type_mask) == PGT_l2_page_table ) + return 0; +#endif + /* Fixme: add code to propagate va_unknown to subtables. */ + if ( ((type & PGT_type_mask) >= PGT_l2_page_table) && + !shadow_mode_refcounts(page_get_owner(page)) ) + return 0; + /* This table is possibly mapped at multiple locations. */ + nx &= ~PGT_va_mask; + nx |= PGT_va_unknown; + } + } + if ( unlikely(!(x & PGT_validated)) ) + { + /* Someone else is updating validation of this page. Wait... */ + while ( (y = page->u.inuse.type_info) == x ) + cpu_relax(); + goto again; + } } } while ( unlikely((y = cmpxchg(&page->u.inuse.type_info, x, nx)) != x) ); @@ -1925,25 +2030,19 @@ int do_mmuext_op( switch ( op.cmd ) { case MMUEXT_PIN_L1_TABLE: - type = PGT_l1_page_table; + type = PGT_l1_page_table | PGT_va_mutable; goto pin_page; case MMUEXT_PIN_L2_TABLE: - type = PGT_l2_page_table; - goto pin_page; - case MMUEXT_PIN_L3_TABLE: - type = PGT_l3_page_table; - goto pin_page; - case MMUEXT_PIN_L4_TABLE: - type = PGT_l4_page_table; - - pin_page: - /* Ignore pinning of invalid paging levels. */ - if ( (op.cmd - MMUEXT_PIN_L1_TABLE) > (CONFIG_PAGING_LEVELS - 1) ) + /* Ignore pinning of subdirectories. */ + if ( (op.cmd - MMUEXT_PIN_L1_TABLE) != (CONFIG_PAGING_LEVELS - 1) ) break; + type = PGT_root_page_table; + + pin_page: if ( shadow_mode_refcounts(FOREIGNDOM) ) break; @@ -2227,7 +2326,7 @@ int do_mmu_update( } if ( unlikely(!get_page_type( - page, type_info & PGT_type_mask)) ) + page, type_info & (PGT_type_mask|PGT_va_mask))) ) goto not_a_pt; switch ( type_info & PGT_type_mask ) @@ -2249,7 +2348,7 @@ int do_mmu_update( case PGT_l3_page_table: { l3_pgentry_t l3e = l3e_from_intpte(req.val); - okay = mod_l3_entry(va, l3e, mfn); + okay = mod_l3_entry(va, l3e, mfn, type_info); } break; #endif @@ -2257,7 +2356,7 @@ int do_mmu_update( case PGT_l4_page_table: { l4_pgentry_t l4e = l4e_from_intpte(req.val); - okay = mod_l4_entry(va, l4e, mfn); + okay = mod_l4_entry(va, l4e, mfn, type_info); } break; #endif @@ -2355,7 +2454,7 @@ static int create_grant_pte_mapping( void *va; unsigned long gmfn, mfn; struct page_info *page; - u32 type; + u32 type_info; l1_pgentry_t ol1e; struct domain *d = v->domain; @@ -2376,8 +2475,9 @@ static int create_grant_pte_mapping( va = (void *)((unsigned long)va + (pte_addr & ~PAGE_MASK)); page = mfn_to_page(mfn); - type = page->u.inuse.type_info & PGT_type_mask; - if ( (type != PGT_l1_page_table) || !get_page_type(page, type) ) + type_info = page->u.inuse.type_info; + if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) || + !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) ) { MEM_LOG("Grant map attempted to update a non-L1 page"); rc = GNTST_general_error; @@ -2411,7 +2511,7 @@ static int destroy_grant_pte_mapping( void *va; unsigned long gmfn, mfn; struct page_info *page; - u32 type; + u32 type_info; l1_pgentry_t ol1e; gmfn = addr >> PAGE_SHIFT; @@ -2427,8 +2527,9 @@ static int destroy_grant_pte_mapping( va = (void *)((unsigned long)va + (addr & ~PAGE_MASK)); page = mfn_to_page(mfn); - type = page->u.inuse.type_info & PGT_type_mask; - if ( (type != PGT_l1_page_table) || !get_page_type(page, type) ) + type_info = page->u.inuse.type_info; + if ( ((type_info & PGT_type_mask) != PGT_l1_page_table) || + !get_page_type(page, type_info & (PGT_type_mask|PGT_va_mask)) ) { MEM_LOG("Grant map attempted to update a non-L1 page"); rc = GNTST_general_error; diff --git a/xen/arch/x86/mm/shadow/common.c b/xen/arch/x86/mm/shadow/common.c index bdccf7a2d9..664b09f209 100644 --- a/xen/arch/x86/mm/shadow/common.c +++ b/xen/arch/x86/mm/shadow/common.c @@ -21,6 +21,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define SHADOW 1 + #include #include #include @@ -223,6 +225,7 @@ struct x86_emulate_ops shadow_emulator_ops = { .cmpxchg8b_emulated = sh_x86_emulate_cmpxchg8b_emulated, }; + /**************************************************************************/ /* Code for "promoting" a guest page to the point where the shadow code is * willing to let it be treated as a guest page table. This generally @@ -232,6 +235,7 @@ struct x86_emulate_ops shadow_emulator_ops = { void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type) { struct page_info *page = mfn_to_page(gmfn); + unsigned long type_info; ASSERT(valid_mfn(gmfn)); @@ -247,8 +251,10 @@ void shadow_promote(struct vcpu *v, mfn_t gmfn, u32 type) // vcpu or not, or even what kind of type we get; we just want the type // count to be > 0. // - while ( !get_page_type(page, page->u.inuse.type_info & PGT_type_mask) ) - continue; + do { + type_info = + page->u.inuse.type_info & (PGT_type_mask | PGT_va_mask); + } while ( !get_page_type(page, type_info) ); // Now that the type ref is non-zero, we can safely use the // shadow_flags. diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c index 840c516fd6..ace6a258f3 100644 --- a/xen/arch/x86/mm/shadow/multi.c +++ b/xen/arch/x86/mm/shadow/multi.c @@ -35,6 +35,8 @@ // space for both PV and HVM guests. // +#define SHADOW 1 + #include #include #include diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index 862b10176d..111325936d 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -103,6 +103,14 @@ struct page_info #define _PGT_pinned 27 #define PGT_pinned (1U<<_PGT_pinned) + /* The 27 most significant bits of virt address if this is a page table. */ +#define PGT_va_shift 32 +#define PGT_va_mask ((unsigned long)((1U<<28)-1)<> PGT_va_shift) != 3) || \ ((s) < (L2_PAGETABLE_FIRST_XEN_SLOT & (L2_PAGETABLE_ENTRIES - 1))) ) #define is_guest_l3_slot(s) (1) From f1b7d71605255cf27677ddc85f86f9c48badc588 Mon Sep 17 00:00:00 2001 From: Steven Hand Date: Tue, 12 Sep 2006 11:09:22 +0100 Subject: [PATCH 4/5] This patch fixes return codes for the acm-related Xen management scripts (error conditions) and addresses minor issues that 'pycheck' complains about. It is tested with xm-test and by manually running the xm commands. It also handles the return case (reported by Masaki Kanno) that was missed in the originally patch. Signed-off by: Reiner Sailer --- tools/python/xen/xm/addlabel.py | 6 ++--- tools/python/xen/xm/cfgbootpolicy.py | 6 ++--- tools/python/xen/xm/create.py | 4 +-- tools/python/xen/xm/dry-run.py | 13 ++++++---- tools/python/xen/xm/dumppolicy.py | 8 +++--- tools/python/xen/xm/getlabel.py | 38 +++++++++++++--------------- tools/python/xen/xm/labels.py | 4 ++- tools/python/xen/xm/loadpolicy.py | 5 ++-- tools/python/xen/xm/makepolicy.py | 3 ++- tools/python/xen/xm/resources.py | 21 +++++++++------ tools/python/xen/xm/rmlabel.py | 10 +++----- 11 files changed, 62 insertions(+), 56 deletions(-) diff --git a/tools/python/xen/xm/addlabel.py b/tools/python/xen/xm/addlabel.py index 1831ec2f80..0a11c35978 100644 --- a/tools/python/xen/xm/addlabel.py +++ b/tools/python/xen/xm/addlabel.py @@ -20,8 +20,6 @@ """Labeling a domain configuration file or a resoruce. """ import sys, os -import string -import traceback from xen.util import dictio from xen.util import security @@ -33,6 +31,7 @@ def usage(): print " resource. It derives the policy from the running hypervisor" print " if it is not given (optional parameter). If a label already" print " exists for the given domain or resource, then addlabel fails.\n" + security.err("Usage") def validate_config_file(configfile): @@ -134,7 +133,6 @@ def main (argv): for prefix in [".", "/etc/xen"]: configfile = prefix + "/" + configfile if os.path.isfile(configfile): - fd = open(configfile, "rb") break if not validate_config_file(configfile): usage() @@ -147,7 +145,7 @@ def main (argv): usage() except security.ACMError: - traceback.print_exc(limit=1) + sys.exit(-1) if __name__ == '__main__': diff --git a/tools/python/xen/xm/cfgbootpolicy.py b/tools/python/xen/xm/cfgbootpolicy.py index 380b869aa2..f62e4c7a8d 100644 --- a/tools/python/xen/xm/cfgbootpolicy.py +++ b/tools/python/xen/xm/cfgbootpolicy.py @@ -70,7 +70,7 @@ def determine_kernelversion(user_specified): within_xen_title = 0 within_xen_entry = 0 if len(version_list) > 1: - err("Cannot decide between entries for kernels: " + version_list) + err("Cannot decide between entries for kernels %s" % version_list) elif len(version_list) == 0: err("Cannot find a boot entry candidate (please create a Xen boot entry first).") else: @@ -87,7 +87,6 @@ def insert_policy(boot_file, kernel_version, policy_name): within_xen_entry = 0 insert_at_end_of_entry = 0 path_prefix = '' - done = False (tmp_fd, tmp_grub) = tempfile.mkstemp() #follow symlink since menue.lst might be linked to grub.conf if stat.S_ISLNK(os.lstat(boot_file)[stat.ST_MODE]): @@ -175,9 +174,10 @@ def main(argv): print "Boot entry created and \'%s\' copied to /boot" % (policy + ".bin") except ACMError: - pass + sys.exit(-1) except: traceback.print_exc(limit=1) + sys.exit(-1) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index bfff93de47..9d5048e445 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -1155,7 +1155,7 @@ def create_security_check(config): else: print "Checking resources: (skipped)" except security.ACMError: - traceback.print_exc(limit=1) + sys.exit(-1) return passed @@ -1176,7 +1176,7 @@ def main(argv): PrettyPrint.prettyprint(config) else: if not create_security_check(config): - print "Security configuration prevents domain from starting" + err("Security configuration prevents domain from starting.") else: dom = make_domain(opts, config) if opts.vals.console_autoconnect: diff --git a/tools/python/xen/xm/dry-run.py b/tools/python/xen/xm/dry-run.py index 4290528636..924235c392 100644 --- a/tools/python/xen/xm/dry-run.py +++ b/tools/python/xen/xm/dry-run.py @@ -18,6 +18,7 @@ """Tests the security settings for a domain and its resources. """ +import sys from xen.util import security from xen.xm import create from xen.xend import sxp @@ -28,14 +29,14 @@ def usage(): print "to see if the domain created by the configfile can access" print "the resources. The status of each resource is listed" print "individually along with the final security decision.\n" + security.err("Usage") def main (argv): - if len(argv) != 2: - usage() - return - try: + if len(argv) != 2: + usage() + passed = 0 (opts, config) = create.parseCommandLine(argv) if create.check_domain_label(config, verbose=1): @@ -48,8 +49,10 @@ def main (argv): print "Dry Run: PASSED" else: print "Dry Run: FAILED" + sys.exit(-1) + except security.ACMError: - pass + sys.exit(-1) if __name__ == '__main__': diff --git a/tools/python/xen/xm/dumppolicy.py b/tools/python/xen/xm/dumppolicy.py index bf69d5e825..9df36611be 100644 --- a/tools/python/xen/xm/dumppolicy.py +++ b/tools/python/xen/xm/dumppolicy.py @@ -18,7 +18,6 @@ """Display currently enforced policy (low-level hypervisor representation). """ import sys -import traceback from xen.util.security import ACMError, err, dump_policy @@ -31,12 +30,13 @@ def usage(): def main(argv): try: + if len(argv) != 1: + usage() + dump_policy() except ACMError: - pass - except: - traceback.print_exc(limit=1) + sys.exit(-1) if __name__ == '__main__': diff --git a/tools/python/xen/xm/getlabel.py b/tools/python/xen/xm/getlabel.py index c74e29f7a2..3450d2799c 100644 --- a/tools/python/xen/xm/getlabel.py +++ b/tools/python/xen/xm/getlabel.py @@ -19,8 +19,6 @@ """Show the label for a domain or resoruce. """ import sys, os, re -import string -import traceback from xen.util import dictio from xen.util import security @@ -28,6 +26,7 @@ def usage(): print "\nUsage: xm getlabel dom " print " xm getlabel res \n" print " This program shows the label for a domain or resource.\n" + security.err("Usage") def get_resource_label(resource): @@ -38,8 +37,7 @@ def get_resource_label(resource): try: access_control = dictio.dict_read("resources", file) except: - print "Resource label file not found" - return + security.err("Resource label file not found") # get the entry and print label if access_control.has_key(resource): @@ -47,7 +45,7 @@ def get_resource_label(resource): label = access_control[resource][1] print "policy="+policy+",label="+label else: - print "Resource not labeled" + security.err("Resource not labeled") def get_domain_label(configfile): @@ -63,8 +61,7 @@ def get_domain_label(configfile): fd = open(file, "rb") break if not fd: - print "Configuration file '"+configfile+"' not found." - return + security.err("Configuration file '"+configfile+"' not found.") # read in the domain config file, finding the label line ac_entry_re = re.compile("^access_control\s*=.*", re.IGNORECASE) @@ -82,8 +79,7 @@ def get_domain_label(configfile): # send error message if we didn't find anything if acline == "": - print "Label does not exist in domain configuration file." - return + security.err("Domain not labeled") # print out the label (title, data) = acline.split("=", 1) @@ -94,19 +90,21 @@ def get_domain_label(configfile): def main (argv): - if len(argv) != 3: - usage() - return + try: + if len(argv) != 3: + usage() - if argv[1].lower() == "dom": - configfile = argv[2] - get_domain_label(configfile) - elif argv[1].lower() == "res": - resource = argv[2] - get_resource_label(resource) - else: - usage() + if argv[1].lower() == "dom": + configfile = argv[2] + get_domain_label(configfile) + elif argv[1].lower() == "res": + resource = argv[2] + get_resource_label(resource) + else: + usage() + except security.ACMError: + sys.exit(-1) if __name__ == '__main__': main(sys.argv) diff --git a/tools/python/xen/xm/labels.py b/tools/python/xen/xm/labels.py index 469758f7a9..6536b5e27d 100644 --- a/tools/python/xen/xm/labels.py +++ b/tools/python/xen/xm/labels.py @@ -70,10 +70,12 @@ def main(argv): labels.sort() for label in labels: print label + except ACMError: - pass + sys.exit(-1) except: traceback.print_exc(limit=1) + sys.exit(-1) if __name__ == '__main__': diff --git a/tools/python/xen/xm/loadpolicy.py b/tools/python/xen/xm/loadpolicy.py index ba96487920..3eb0e28e75 100644 --- a/tools/python/xen/xm/loadpolicy.py +++ b/tools/python/xen/xm/loadpolicy.py @@ -34,11 +34,12 @@ def main(argv): if len(argv) != 2: usage() load_policy(argv[1]) + except ACMError: - pass + sys.exit(-1) except: traceback.print_exc(limit=1) - + sys.exit(-1) if __name__ == '__main__': diff --git a/tools/python/xen/xm/makepolicy.py b/tools/python/xen/xm/makepolicy.py index fa3d03aeab..191566804d 100644 --- a/tools/python/xen/xm/makepolicy.py +++ b/tools/python/xen/xm/makepolicy.py @@ -37,9 +37,10 @@ def main(argv): make_policy(argv[1]) except ACMError: - pass + sys.exit(-1) except: traceback.print_exc(limit=1) + sys.exit(-1) diff --git a/tools/python/xen/xm/resources.py b/tools/python/xen/xm/resources.py index ef1184eec8..c3a83a5f29 100644 --- a/tools/python/xen/xm/resources.py +++ b/tools/python/xen/xm/resources.py @@ -18,8 +18,7 @@ """List the resource label information from the global resource label file """ -import sys, os -import string +import sys from xen.util import dictio from xen.util import security @@ -27,6 +26,7 @@ def usage(): print "\nUsage: xm resource\n" print " This program lists information for each resource in the" print " global resource label file\n" + security.err("Usage") def print_resource_data(access_control): @@ -41,14 +41,19 @@ def print_resource_data(access_control): def main (argv): try: - file = security.res_label_filename - access_control = dictio.dict_read("resources", file) - except: - print "Resource file not found." - return + if len(argv) != 1: + usage() - print_resource_data(access_control) + try: + file = security.res_label_filename + access_control = dictio.dict_read("resources", file) + except: + security.err("Error reading resource file.") + print_resource_data(access_control) + + except security.ACMError: + sys.exit(-1) if __name__ == '__main__': main(sys.argv) diff --git a/tools/python/xen/xm/rmlabel.py b/tools/python/xen/xm/rmlabel.py index ebd94a3163..e9df1ad573 100644 --- a/tools/python/xen/xm/rmlabel.py +++ b/tools/python/xen/xm/rmlabel.py @@ -19,8 +19,6 @@ """Remove a label from a domain configuration file or a resoruce. """ import sys, os, re -import string -import traceback from xen.util import dictio from xen.util import security @@ -31,6 +29,7 @@ def usage(): print " for a domain or from the global resource label file for a" print " resource. If the label does not exist for the given domain or" print " resource, then rmlabel fails.\n" + security.err("Usage") def rm_resource_label(resource): @@ -48,7 +47,7 @@ def rm_resource_label(resource): del access_control[resource] dictio.dict_write(access_control, "resources", file) else: - security.err("Label does not exist in resource label file.") + security.err("Resource not labeled.") def rm_domain_label(configfile): @@ -85,7 +84,7 @@ def rm_domain_label(configfile): # send error message if we didn't find anything to remove if not removed: - security.err("Label does not exist in domain configuration file.") + security.err("Domain not labeled.") # write the data back out to the file fd = open(file, "wb") @@ -97,7 +96,6 @@ def main (argv): try: if len(argv) != 3: usage() - return if argv[1].lower() == "dom": configfile = argv[2] @@ -109,7 +107,7 @@ def main (argv): usage() except security.ACMError: - traceback.print_exc(limit=1) + sys.exit(-1) if __name__ == '__main__': From 82f6d80e3a5d151d7a434e6637a0f438fdc94109 Mon Sep 17 00:00:00 2001 From: "atse@norwich.uk.xensource.com" Date: Tue, 12 Sep 2006 16:33:33 +0100 Subject: [PATCH 5/5] [XEND] Return an Internal Server Error via the Xend HTTP server. This allows domain creation failures can be detected when done via HTTP. Signed-off-by: Daniel P. Berrange --- tools/python/xen/web/SrvBase.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/python/xen/web/SrvBase.py b/tools/python/xen/web/SrvBase.py index 59eb313b3e..bf59b556c8 100644 --- a/tools/python/xen/web/SrvBase.py +++ b/tools/python/xen/web/SrvBase.py @@ -84,6 +84,7 @@ class SrvBase(resource.Resource): try: return op_method(op, req) except Exception, exn: + req.setResponseCode(http.INTERNAL_SERVER_ERROR, "Request failed: " + op) log.exception("Request %s failed.", op) if req.useSxp(): return ['xend.err', str(exn)]