[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v4 26/31] x86/mm: move pv_{alloc, free}_page_type
Move them and the helper functions to pv/mm.c. Use bool in the moved code where appropriate. Put BUG() in the stub because the callers will call BUG or BUG_ON anyway. Signed-off-by: Wei Liu <wei.liu2@xxxxxxxxxx> --- v4: add BUG() in stubs --- xen/arch/x86/domain.c | 1 + xen/arch/x86/mm.c | 492 -------------------------------------------- xen/arch/x86/pv/mm.c | 491 +++++++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/mm.h | 3 - xen/include/asm-x86/pv/mm.h | 14 ++ 5 files changed, 506 insertions(+), 495 deletions(-) diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 8fae38485c..e79a7de7e4 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -64,6 +64,7 @@ #include <compat/vcpu.h> #include <asm/psr.h> #include <asm/pv/domain.h> +#include <asm/pv/mm.h> #include <asm/pv/processor.h> DEFINE_PER_CPU(struct vcpu *, curr_vcpu); diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 590e7ae65b..204c20d6fd 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -510,21 +510,6 @@ static void invalidate_shadow_ldt(struct vcpu *v, int flush) } -static int alloc_segdesc_page(struct page_info *page) -{ - const struct domain *owner = page_get_owner(page); - struct desc_struct *descs = __map_domain_page(page); - unsigned i; - - for ( i = 0; i < 512; i++ ) - if ( unlikely(!check_descriptor(owner, &descs[i])) ) - break; - - unmap_domain_page(descs); - - return i == 512 ? 0 : -EINVAL; -} - bool get_page_from_mfn(mfn_t mfn, struct domain *d) { struct page_info *page = mfn_to_page(mfn_x(mfn)); @@ -539,7 +524,6 @@ bool get_page_from_mfn(mfn_t mfn, struct domain *d) return true; } - int get_page_and_type_from_mfn(mfn_t mfn, unsigned long type, struct domain *d, int partial, bool preemptible) { @@ -1165,172 +1149,6 @@ int put_page_from_l4e(l4_pgentry_t l4e, unsigned long pfn, int partial, return 1; } -static int alloc_l1_table(struct page_info *page) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l1_pgentry_t *pl1e; - unsigned int i; - int ret = 0; - - pl1e = map_domain_page(_mfn(pfn)); - - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - { - switch ( ret = get_page_from_l1e(pl1e[i], d, d) ) - { - default: - goto fail; - case 0: - break; - case _PAGE_RW ... _PAGE_RW | PAGE_CACHE_ATTRS: - ASSERT(!(ret & ~(_PAGE_RW | PAGE_CACHE_ATTRS))); - l1e_flip_flags(pl1e[i], ret); - break; - } - - adjust_guest_l1e(pl1e[i], d); - } - - unmap_domain_page(pl1e); - return 0; - - fail: - gdprintk(XENLOG_WARNING, "Failure in alloc_l1_table: slot %#x\n", i); - while ( i-- > 0 ) - put_page_from_l1e(pl1e[i], d); - - unmap_domain_page(pl1e); - return ret; -} - -static int alloc_l2_table(struct page_info *page, unsigned long type, - int preemptible) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l2_pgentry_t *pl2e; - unsigned int i; - int rc = 0; - - pl2e = map_domain_page(_mfn(pfn)); - - for ( i = page->nr_validated_ptes; i < L2_PAGETABLE_ENTRIES; i++ ) - { - if ( preemptible && i > page->nr_validated_ptes - && hypercall_preempt_check() ) - { - page->nr_validated_ptes = i; - rc = -ERESTART; - break; - } - - if ( !is_guest_l2_slot(d, type, i) || - (rc = get_page_from_l2e(pl2e[i], pfn, d)) > 0 ) - continue; - - if ( rc < 0 ) - { - gdprintk(XENLOG_WARNING, "Failure in alloc_l2_table: slot %#x\n", i); - while ( i-- > 0 ) - if ( is_guest_l2_slot(d, type, i) ) - put_page_from_l2e(pl2e[i], pfn); - break; - } - - adjust_guest_l2e(pl2e[i], d); - } - - if ( rc >= 0 && (type & PGT_pae_xen_l2) ) - { - /* Xen private mappings. */ - memcpy(&pl2e[COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d)], - &compat_idle_pg_table_l2[ - l2_table_offset(HIRO_COMPAT_MPT_VIRT_START)], - COMPAT_L2_PAGETABLE_XEN_SLOTS(d) * sizeof(*pl2e)); - } - - unmap_domain_page(pl2e); - return rc > 0 ? 0 : rc; -} - -static int alloc_l3_table(struct page_info *page) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l3_pgentry_t *pl3e; - unsigned int i; - int rc = 0, partial = page->partial_pte; - - pl3e = map_domain_page(_mfn(pfn)); - - /* - * PAE guests allocate full pages, but aren't required to initialize - * more than the first four entries; when running in compatibility - * mode, however, the full page is visible to the MMU, and hence all - * 512 entries must be valid/verified, which is most easily achieved - * by clearing them out. - */ - if ( is_pv_32bit_domain(d) ) - memset(pl3e + 4, 0, (L3_PAGETABLE_ENTRIES - 4) * sizeof(*pl3e)); - - for ( i = page->nr_validated_ptes; i < L3_PAGETABLE_ENTRIES; - i++, partial = 0 ) - { - if ( is_pv_32bit_domain(d) && (i == 3) ) - { - if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) || - (l3e_get_flags(pl3e[i]) & l3_disallow_mask(d)) ) - rc = -EINVAL; - else - rc = get_page_and_type_from_mfn( - _mfn(l3e_get_pfn(pl3e[i])), - PGT_l2_page_table | PGT_pae_xen_l2, d, partial, true); - } - else if ( !is_guest_l3_slot(i) || - (rc = get_page_from_l3e(pl3e[i], pfn, d, partial)) > 0 ) - continue; - - if ( rc == -ERESTART ) - { - page->nr_validated_ptes = i; - page->partial_pte = partial ?: 1; - } - else if ( rc == -EINTR && i ) - { - page->nr_validated_ptes = i; - page->partial_pte = 0; - rc = -ERESTART; - } - if ( rc < 0 ) - break; - - adjust_guest_l3e(pl3e[i], d); - } - - if ( rc >= 0 && !pv_create_pae_xen_mappings(d, pl3e) ) - rc = -EINVAL; - if ( rc < 0 && rc != -ERESTART && rc != -EINTR ) - { - gdprintk(XENLOG_WARNING, "Failure in alloc_l3_table: slot %#x\n", i); - if ( i ) - { - page->nr_validated_ptes = i; - page->partial_pte = 0; - current->arch.old_guest_table = page; - } - while ( i-- > 0 ) - { - if ( !is_guest_l3_slot(i) ) - continue; - unadjust_guest_l3e(pl3e[i], d); - } - } - - unmap_domain_page(pl3e); - return rc > 0 ? 0 : rc; -} - bool fill_ro_mpt(unsigned long mfn) { l4_pgentry_t *l4tab = map_domain_page(_mfn(mfn)); @@ -1355,188 +1173,6 @@ void zap_ro_mpt(unsigned long mfn) unmap_domain_page(l4tab); } -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 = map_domain_page(_mfn(pfn)); - unsigned int i; - int rc = 0, partial = page->partial_pte; - - for ( i = page->nr_validated_ptes; i < L4_PAGETABLE_ENTRIES; - i++, partial = 0 ) - { - if ( !is_guest_l4_slot(d, i) || - (rc = get_page_from_l4e(pl4e[i], pfn, d, partial)) > 0 ) - continue; - - if ( rc == -ERESTART ) - { - page->nr_validated_ptes = i; - page->partial_pte = partial ?: 1; - } - else if ( rc < 0 ) - { - if ( rc != -EINTR ) - gdprintk(XENLOG_WARNING, - "Failure in alloc_l4_table: slot %#x\n", i); - if ( i ) - { - page->nr_validated_ptes = i; - page->partial_pte = 0; - if ( rc == -EINTR ) - rc = -ERESTART; - else - { - if ( current->arch.old_guest_table ) - page->nr_validated_ptes++; - current->arch.old_guest_table = page; - } - } - } - if ( rc < 0 ) - { - unmap_domain_page(pl4e); - return rc; - } - - adjust_guest_l4e(pl4e[i], d); - } - - if ( rc >= 0 ) - { - pv_init_guest_l4_table(pl4e, d, !VM_ASSIST(d, m2p_strict)); - atomic_inc(&d->arch.pv_domain.nr_l4_pages); - rc = 0; - } - unmap_domain_page(pl4e); - - return rc; -} - -static void free_l1_table(struct page_info *page) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l1_pgentry_t *pl1e; - unsigned int i; - - pl1e = map_domain_page(_mfn(pfn)); - - for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - put_page_from_l1e(pl1e[i], d); - - unmap_domain_page(pl1e); -} - - -static int free_l2_table(struct page_info *page, int preemptible) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l2_pgentry_t *pl2e; - unsigned int i = page->nr_validated_ptes - 1; - int err = 0; - - pl2e = map_domain_page(_mfn(pfn)); - - ASSERT(page->nr_validated_ptes); - do { - if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) && - put_page_from_l2e(pl2e[i], pfn) == 0 && - preemptible && i && hypercall_preempt_check() ) - { - page->nr_validated_ptes = i; - err = -ERESTART; - } - } while ( !err && i-- ); - - unmap_domain_page(pl2e); - - if ( !err ) - page->u.inuse.type_info &= ~PGT_pae_xen_l2; - - return err; -} - -static int free_l3_table(struct page_info *page) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l3_pgentry_t *pl3e; - int rc = 0, partial = page->partial_pte; - unsigned int i = page->nr_validated_ptes - !partial; - - pl3e = map_domain_page(_mfn(pfn)); - - do { - if ( is_guest_l3_slot(i) ) - { - rc = put_page_from_l3e(pl3e[i], pfn, partial, 0); - if ( rc < 0 ) - break; - partial = 0; - if ( rc > 0 ) - continue; - unadjust_guest_l3e(pl3e[i], d); - } - } while ( i-- ); - - unmap_domain_page(pl3e); - - if ( rc == -ERESTART ) - { - page->nr_validated_ptes = i; - page->partial_pte = partial ?: -1; - } - else if ( rc == -EINTR && i < L3_PAGETABLE_ENTRIES - 1 ) - { - page->nr_validated_ptes = i + 1; - page->partial_pte = 0; - rc = -ERESTART; - } - return rc > 0 ? 0 : rc; -} - -static int free_l4_table(struct page_info *page) -{ - struct domain *d = page_get_owner(page); - unsigned long pfn = page_to_mfn(page); - l4_pgentry_t *pl4e = map_domain_page(_mfn(pfn)); - int rc = 0, partial = page->partial_pte; - unsigned int i = page->nr_validated_ptes - !partial; - - do { - if ( is_guest_l4_slot(d, i) ) - rc = put_page_from_l4e(pl4e[i], pfn, partial, 0); - if ( rc < 0 ) - break; - partial = 0; - } while ( i-- ); - - if ( rc == -ERESTART ) - { - page->nr_validated_ptes = i; - page->partial_pte = partial ?: -1; - } - else if ( rc == -EINTR && i < L4_PAGETABLE_ENTRIES - 1 ) - { - page->nr_validated_ptes = i + 1; - page->partial_pte = 0; - rc = -ERESTART; - } - - unmap_domain_page(pl4e); - - if ( rc >= 0 ) - { - atomic_dec(&d->arch.pv_domain.nr_l4_pages); - rc = 0; - } - - return rc; -} - int page_lock(struct page_info *page) { unsigned long x, nx; @@ -1951,134 +1587,6 @@ void get_page_light(struct page_info *page) while ( unlikely(y != x) ); } -static int pv_alloc_page_type(struct page_info *page, unsigned long type, - bool preemptible) -{ - struct domain *owner = page_get_owner(page); - int rc; - - /* A page table is dirtied when its type count becomes non-zero. */ - if ( likely(owner != NULL) ) - paging_mark_dirty(owner, _mfn(page_to_mfn(page))); - - switch ( type & PGT_type_mask ) - { - case PGT_l1_page_table: - rc = alloc_l1_table(page); - break; - case PGT_l2_page_table: - rc = alloc_l2_table(page, type, preemptible); - break; - case PGT_l3_page_table: - ASSERT(preemptible); - rc = alloc_l3_table(page); - break; - case PGT_l4_page_table: - ASSERT(preemptible); - rc = alloc_l4_table(page); - break; - case PGT_seg_desc_page: - rc = alloc_segdesc_page(page); - break; - default: - printk("Bad type in alloc_page_type %lx t=%" PRtype_info " c=%lx\n", - type, page->u.inuse.type_info, - page->count_info); - rc = -EINVAL; - BUG(); - } - - /* No need for atomic update of type_info here: noone else updates it. */ - smp_wmb(); - switch ( rc ) - { - case 0: - page->u.inuse.type_info |= PGT_validated; - break; - case -EINTR: - ASSERT((page->u.inuse.type_info & - (PGT_count_mask|PGT_validated|PGT_partial)) == 1); - page->u.inuse.type_info &= ~PGT_count_mask; - break; - default: - ASSERT(rc < 0); - gdprintk(XENLOG_WARNING, "Error while validating mfn %" PRI_mfn - " (pfn %" PRI_pfn ") for type %" PRtype_info - ": caf=%08lx taf=%" PRtype_info "\n", - page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)), - type, page->count_info, page->u.inuse.type_info); - if ( page != current->arch.old_guest_table ) - page->u.inuse.type_info = 0; - else - { - ASSERT((page->u.inuse.type_info & - (PGT_count_mask | PGT_validated)) == 1); - case -ERESTART: - get_page_light(page); - page->u.inuse.type_info |= PGT_partial; - } - break; - } - - return rc; -} - - -int pv_free_page_type(struct page_info *page, unsigned long type, - bool preemptible) -{ - struct domain *owner = page_get_owner(page); - unsigned long gmfn; - int rc; - - if ( likely(owner != NULL) && unlikely(paging_mode_enabled(owner)) ) - { - /* A page table is dirtied when its type count becomes zero. */ - paging_mark_dirty(owner, _mfn(page_to_mfn(page))); - - ASSERT(!shadow_mode_refcounts(owner)); - - gmfn = mfn_to_gmfn(owner, page_to_mfn(page)); - ASSERT(VALID_M2P(gmfn)); - /* Page sharing not supported for shadowed domains */ - if(!SHARED_M2P(gmfn)) - shadow_remove_all_shadows(owner, _mfn(gmfn)); - } - - if ( !(type & PGT_partial) ) - { - page->nr_validated_ptes = 1U << PAGETABLE_ORDER; - page->partial_pte = 0; - } - - switch ( type & PGT_type_mask ) - { - case PGT_l1_page_table: - free_l1_table(page); - rc = 0; - break; - case PGT_l2_page_table: - rc = free_l2_table(page, preemptible); - break; - case PGT_l3_page_table: - ASSERT(preemptible); - rc = free_l3_table(page); - break; - case PGT_l4_page_table: - ASSERT(preemptible); - rc = free_l4_table(page); - break; - default: - gdprintk(XENLOG_WARNING, "type %" PRtype_info " mfn %" PRI_mfn "\n", - type, page_to_mfn(page)); - rc = -EINVAL; - BUG(); - } - - return rc; -} - - static int __put_final_page_type( struct page_info *page, unsigned long type, int preemptible) { diff --git a/xen/arch/x86/pv/mm.c b/xen/arch/x86/pv/mm.c index 46e1fcf4e5..f0393b9e3c 100644 --- a/xen/arch/x86/pv/mm.c +++ b/xen/arch/x86/pv/mm.c @@ -20,10 +20,13 @@ * along with this program; If not, see <http://www.gnu.org/licenses/>. */ +#include <xen/event.h> #include <xen/guest_access.h> +#include <asm/mm.h> #include <asm/pv/mm.h> #include <asm/setup.h> +#include <asm/shadow.h> /* * PTE updates can be done with ordinary writes except: @@ -251,6 +254,494 @@ bool pv_create_pae_xen_mappings(struct domain *d, l3_pgentry_t *pl3e) return true; } +static int alloc_l1_table(struct page_info *page) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l1_pgentry_t *pl1e; + unsigned int i; + int ret = 0; + + pl1e = map_domain_page(_mfn(pfn)); + + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + { + switch ( ret = get_page_from_l1e(pl1e[i], d, d) ) + { + default: + goto fail; + case 0: + break; + case _PAGE_RW ... _PAGE_RW | PAGE_CACHE_ATTRS: + ASSERT(!(ret & ~(_PAGE_RW | PAGE_CACHE_ATTRS))); + l1e_flip_flags(pl1e[i], ret); + break; + } + + adjust_guest_l1e(pl1e[i], d); + } + + unmap_domain_page(pl1e); + return 0; + + fail: + gdprintk(XENLOG_WARNING, "Failure in alloc_l1_table: slot %#x\n", i); + while ( i-- > 0 ) + put_page_from_l1e(pl1e[i], d); + + unmap_domain_page(pl1e); + return ret; +} + +static int alloc_l2_table(struct page_info *page, unsigned long type, + bool preemptible) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l2_pgentry_t *pl2e; + unsigned int i; + int rc = 0; + + pl2e = map_domain_page(_mfn(pfn)); + + for ( i = page->nr_validated_ptes; i < L2_PAGETABLE_ENTRIES; i++ ) + { + if ( preemptible && i > page->nr_validated_ptes + && hypercall_preempt_check() ) + { + page->nr_validated_ptes = i; + rc = -ERESTART; + break; + } + + if ( !is_guest_l2_slot(d, type, i) || + (rc = get_page_from_l2e(pl2e[i], pfn, d)) > 0 ) + continue; + + if ( rc < 0 ) + { + gdprintk(XENLOG_WARNING, "Failure in alloc_l2_table: slot %#x\n", i); + while ( i-- > 0 ) + if ( is_guest_l2_slot(d, type, i) ) + put_page_from_l2e(pl2e[i], pfn); + break; + } + + adjust_guest_l2e(pl2e[i], d); + } + + if ( rc >= 0 && (type & PGT_pae_xen_l2) ) + { + /* Xen private mappings. */ + memcpy(&pl2e[COMPAT_L2_PAGETABLE_FIRST_XEN_SLOT(d)], + &compat_idle_pg_table_l2[ + l2_table_offset(HIRO_COMPAT_MPT_VIRT_START)], + COMPAT_L2_PAGETABLE_XEN_SLOTS(d) * sizeof(*pl2e)); + } + + unmap_domain_page(pl2e); + return rc > 0 ? 0 : rc; +} + +static int alloc_l3_table(struct page_info *page) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l3_pgentry_t *pl3e; + unsigned int i; + int rc = 0, partial = page->partial_pte; + + pl3e = map_domain_page(_mfn(pfn)); + + /* + * PAE guests allocate full pages, but aren't required to initialize + * more than the first four entries; when running in compatibility + * mode, however, the full page is visible to the MMU, and hence all + * 512 entries must be valid/verified, which is most easily achieved + * by clearing them out. + */ + if ( is_pv_32bit_domain(d) ) + memset(pl3e + 4, 0, (L3_PAGETABLE_ENTRIES - 4) * sizeof(*pl3e)); + + for ( i = page->nr_validated_ptes; i < L3_PAGETABLE_ENTRIES; + i++, partial = 0 ) + { + if ( is_pv_32bit_domain(d) && (i == 3) ) + { + if ( !(l3e_get_flags(pl3e[i]) & _PAGE_PRESENT) || + (l3e_get_flags(pl3e[i]) & l3_disallow_mask(d)) ) + rc = -EINVAL; + else + rc = get_page_and_type_from_mfn( + _mfn(l3e_get_pfn(pl3e[i])), + PGT_l2_page_table | PGT_pae_xen_l2, d, partial, true); + } + else if ( !is_guest_l3_slot(i) || + (rc = get_page_from_l3e(pl3e[i], pfn, d, partial)) > 0 ) + continue; + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; + page->partial_pte = partial ?: 1; + } + else if ( rc == -EINTR && i ) + { + page->nr_validated_ptes = i; + page->partial_pte = 0; + rc = -ERESTART; + } + if ( rc < 0 ) + break; + + adjust_guest_l3e(pl3e[i], d); + } + + if ( rc >= 0 && !pv_create_pae_xen_mappings(d, pl3e) ) + rc = -EINVAL; + if ( rc < 0 && rc != -ERESTART && rc != -EINTR ) + { + gdprintk(XENLOG_WARNING, "Failure in alloc_l3_table: slot %#x\n", i); + if ( i ) + { + page->nr_validated_ptes = i; + page->partial_pte = 0; + current->arch.old_guest_table = page; + } + while ( i-- > 0 ) + { + if ( !is_guest_l3_slot(i) ) + continue; + unadjust_guest_l3e(pl3e[i], d); + } + } + + unmap_domain_page(pl3e); + return rc > 0 ? 0 : rc; +} + +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 = map_domain_page(_mfn(pfn)); + unsigned int i; + int rc = 0, partial = page->partial_pte; + + for ( i = page->nr_validated_ptes; i < L4_PAGETABLE_ENTRIES; + i++, partial = 0 ) + { + if ( !is_guest_l4_slot(d, i) || + (rc = get_page_from_l4e(pl4e[i], pfn, d, partial)) > 0 ) + continue; + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; + page->partial_pte = partial ?: 1; + } + else if ( rc < 0 ) + { + if ( rc != -EINTR ) + gdprintk(XENLOG_WARNING, + "Failure in alloc_l4_table: slot %#x\n", i); + if ( i ) + { + page->nr_validated_ptes = i; + page->partial_pte = 0; + if ( rc == -EINTR ) + rc = -ERESTART; + else + { + if ( current->arch.old_guest_table ) + page->nr_validated_ptes++; + current->arch.old_guest_table = page; + } + } + } + if ( rc < 0 ) + { + unmap_domain_page(pl4e); + return rc; + } + + adjust_guest_l4e(pl4e[i], d); + } + + if ( rc >= 0 ) + { + pv_init_guest_l4_table(pl4e, d, !VM_ASSIST(d, m2p_strict)); + atomic_inc(&d->arch.pv_domain.nr_l4_pages); + rc = 0; + } + unmap_domain_page(pl4e); + + return rc; +} + +static void free_l1_table(struct page_info *page) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l1_pgentry_t *pl1e; + unsigned int i; + + pl1e = map_domain_page(_mfn(pfn)); + + for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) + put_page_from_l1e(pl1e[i], d); + + unmap_domain_page(pl1e); +} + +static int free_l2_table(struct page_info *page, int preemptible) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l2_pgentry_t *pl2e; + unsigned int i = page->nr_validated_ptes - 1; + int err = 0; + + pl2e = map_domain_page(_mfn(pfn)); + + ASSERT(page->nr_validated_ptes); + do { + if ( is_guest_l2_slot(d, page->u.inuse.type_info, i) && + put_page_from_l2e(pl2e[i], pfn) == 0 && + preemptible && i && hypercall_preempt_check() ) + { + page->nr_validated_ptes = i; + err = -ERESTART; + } + } while ( !err && i-- ); + + unmap_domain_page(pl2e); + + if ( !err ) + page->u.inuse.type_info &= ~PGT_pae_xen_l2; + + return err; +} + +static int free_l3_table(struct page_info *page) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l3_pgentry_t *pl3e; + int rc = 0, partial = page->partial_pte; + unsigned int i = page->nr_validated_ptes - !partial; + + pl3e = map_domain_page(_mfn(pfn)); + + do { + if ( is_guest_l3_slot(i) ) + { + rc = put_page_from_l3e(pl3e[i], pfn, partial, 0); + if ( rc < 0 ) + break; + partial = 0; + if ( rc > 0 ) + continue; + unadjust_guest_l3e(pl3e[i], d); + } + } while ( i-- ); + + unmap_domain_page(pl3e); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; + page->partial_pte = partial ?: -1; + } + else if ( rc == -EINTR && i < L3_PAGETABLE_ENTRIES - 1 ) + { + page->nr_validated_ptes = i + 1; + page->partial_pte = 0; + rc = -ERESTART; + } + return rc > 0 ? 0 : rc; +} + +static int free_l4_table(struct page_info *page) +{ + struct domain *d = page_get_owner(page); + unsigned long pfn = page_to_mfn(page); + l4_pgentry_t *pl4e = map_domain_page(_mfn(pfn)); + int rc = 0, partial = page->partial_pte; + unsigned int i = page->nr_validated_ptes - !partial; + + do { + if ( is_guest_l4_slot(d, i) ) + rc = put_page_from_l4e(pl4e[i], pfn, partial, 0); + if ( rc < 0 ) + break; + partial = 0; + } while ( i-- ); + + if ( rc == -ERESTART ) + { + page->nr_validated_ptes = i; + page->partial_pte = partial ?: -1; + } + else if ( rc == -EINTR && i < L4_PAGETABLE_ENTRIES - 1 ) + { + page->nr_validated_ptes = i + 1; + page->partial_pte = 0; + rc = -ERESTART; + } + + unmap_domain_page(pl4e); + + if ( rc >= 0 ) + { + atomic_dec(&d->arch.pv_domain.nr_l4_pages); + rc = 0; + } + + return rc; +} + +static int alloc_segdesc_page(struct page_info *page) +{ + const struct domain *owner = page_get_owner(page); + struct desc_struct *descs = __map_domain_page(page); + unsigned i; + + for ( i = 0; i < 512; i++ ) + if ( unlikely(!check_descriptor(owner, &descs[i])) ) + break; + + unmap_domain_page(descs); + + return i == 512 ? 0 : -EINVAL; +} + +int pv_alloc_page_type(struct page_info *page, unsigned long type, + bool preemptible) +{ + struct domain *owner = page_get_owner(page); + int rc; + + /* A page table is dirtied when its type count becomes non-zero. */ + if ( likely(owner != NULL) ) + paging_mark_dirty(owner, _mfn(page_to_mfn(page))); + + switch ( type & PGT_type_mask ) + { + case PGT_l1_page_table: + rc = alloc_l1_table(page); + break; + case PGT_l2_page_table: + rc = alloc_l2_table(page, type, preemptible); + break; + case PGT_l3_page_table: + ASSERT(preemptible); + rc = alloc_l3_table(page); + break; + case PGT_l4_page_table: + ASSERT(preemptible); + rc = alloc_l4_table(page); + break; + case PGT_seg_desc_page: + rc = alloc_segdesc_page(page); + break; + default: + printk("Bad type in alloc_page_type %lx t=%" PRtype_info " c=%lx\n", + type, page->u.inuse.type_info, + page->count_info); + rc = -EINVAL; + BUG(); + } + + /* No need for atomic update of type_info here: noone else updates it. */ + smp_wmb(); + switch ( rc ) + { + case 0: + page->u.inuse.type_info |= PGT_validated; + break; + case -EINTR: + ASSERT((page->u.inuse.type_info & + (PGT_count_mask|PGT_validated|PGT_partial)) == 1); + page->u.inuse.type_info &= ~PGT_count_mask; + break; + default: + ASSERT(rc < 0); + gdprintk(XENLOG_WARNING, "Error while validating mfn %" PRI_mfn + " (pfn %" PRI_pfn ") for type %" PRtype_info + ": caf=%08lx taf=%" PRtype_info "\n", + page_to_mfn(page), get_gpfn_from_mfn(page_to_mfn(page)), + type, page->count_info, page->u.inuse.type_info); + if ( page != current->arch.old_guest_table ) + page->u.inuse.type_info = 0; + else + { + ASSERT((page->u.inuse.type_info & + (PGT_count_mask | PGT_validated)) == 1); + case -ERESTART: + get_page_light(page); + page->u.inuse.type_info |= PGT_partial; + } + break; + } + + return rc; +} + +int pv_free_page_type(struct page_info *page, unsigned long type, + bool preemptible) +{ + struct domain *owner = page_get_owner(page); + unsigned long gmfn; + int rc; + + if ( likely(owner != NULL) && unlikely(paging_mode_enabled(owner)) ) + { + /* A page table is dirtied when its type count becomes zero. */ + paging_mark_dirty(owner, _mfn(page_to_mfn(page))); + + ASSERT(!shadow_mode_refcounts(owner)); + + gmfn = mfn_to_gmfn(owner, page_to_mfn(page)); + ASSERT(VALID_M2P(gmfn)); + /* Page sharing not supported for shadowed domains */ + if(!SHARED_M2P(gmfn)) + shadow_remove_all_shadows(owner, _mfn(gmfn)); + } + + if ( !(type & PGT_partial) ) + { + page->nr_validated_ptes = 1U << PAGETABLE_ORDER; + page->partial_pte = 0; + } + + switch ( type & PGT_type_mask ) + { + case PGT_l1_page_table: + free_l1_table(page); + rc = 0; + break; + case PGT_l2_page_table: + rc = free_l2_table(page, preemptible); + break; + case PGT_l3_page_table: + ASSERT(preemptible); + rc = free_l3_table(page); + break; + case PGT_l4_page_table: + ASSERT(preemptible); + rc = free_l4_table(page); + break; + default: + gdprintk(XENLOG_WARNING, "type %" PRtype_info " mfn %" PRI_mfn "\n", + type, page_to_mfn(page)); + rc = -EINVAL; + BUG(); + } + + return rc; +} + /* * Local variables: * mode: C diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 6857651db1..7480341240 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -302,9 +302,6 @@ static inline void *__page_to_virt(const struct page_info *pg) (PAGE_SIZE / (sizeof(*pg) & -sizeof(*pg)))); } -int pv_free_page_type(struct page_info *page, unsigned long type, - bool preemptible); - bool_t fill_ro_mpt(unsigned long mfn); void zap_ro_mpt(unsigned long mfn); diff --git a/xen/include/asm-x86/pv/mm.h b/xen/include/asm-x86/pv/mm.h index 648b26d7d0..7de5ea2f12 100644 --- a/xen/include/asm-x86/pv/mm.h +++ b/xen/include/asm-x86/pv/mm.h @@ -95,10 +95,17 @@ void pv_arch_init_memory(void); int pv_new_guest_cr3(unsigned long pfn); +int pv_alloc_page_type(struct page_info *page, unsigned long type, + bool preemptible); +int pv_free_page_type(struct page_info *page, unsigned long type, + bool preemptible); + #else #include <xen/errno.h> +#include <asm/bug.h> + static inline void pv_get_guest_eff_l1e(unsigned long addr, l1_pgentry_t *eff_l1e) {} @@ -125,6 +132,13 @@ static inline void pv_arch_init_memory(void) {} static inline int pv_new_guest_cr3(unsigned long pfn) { return -EINVAL; } +static inline int pv_alloc_page_type(struct page_info *page, unsigned long type, + bool preemptible) +{ BUG(); return -EINVAL; } +static inline int pv_free_page_type(struct page_info *page, unsigned long type, + bool preemptible) +{ BUG(); return -EINVAL; } + #endif #endif /* __X86_PV_MM_H__ */ -- 2.11.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |