[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v6 3/5] xen: implement guest_physmap_pin_range and guest_physmap_unpin_range
guest_physmap_pin_range pins a range of guest pages so that their p2m mappings won't be changed. guest_physmap_unpin_range unpins the previously pinned pages. The pinning is done using a new count_info flag. Provide empty stubs for x86. Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx> Changes in v6: - guest_physmap_pin_range: check that the pages are normal r/w ram pages; - guest_physmap_unpin_range: return -EINVAL instead of -EBUSY if a page is not pinned; - use a count_info flag rather than using spare bits in the ptes. Changes in v5: - return -EBUSY when the P2M_DMA_PIN check fails; - rename _guest_physmap_pin_range to pin_one_pte; - rename _guest_physmap_unpin_range to unpin_one_pte. Changes in v4: - use p2m_walker to implement guest_physmap_pin_range and guest_physmap_unpin_range; - return -EINVAL when the P2M_DMA_PIN check fails; - change the printk into a gdprintk; - add a comment on what type of page can be pinned. --- xen/arch/arm/p2m.c | 57 ++++++++++++++++++++++++++++++++++++++++++++- xen/include/asm-arm/mm.h | 7 +++++ xen/include/asm-x86/p2m.h | 12 +++++++++ 3 files changed, 75 insertions(+), 1 deletions(-) diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c index 05048c2..ff32b5a 100644 --- a/xen/arch/arm/p2m.c +++ b/xen/arch/arm/p2m.c @@ -157,6 +157,49 @@ paddr_t p2m_lookup(struct domain *d, paddr_t paddr) return p2m.maddr; } +int guest_physmap_pin_range(struct domain *d, + xen_pfn_t gpfn, + unsigned int order) +{ + int i; + struct page_info *page; + xen_pfn_t mfn; + + for ( i = 0; i < (1UL << order); i++ ) + { + mfn = gmfn_to_mfn(d, gpfn + i); + page = mfn_to_page(mfn); + if ( !page ) + return -EINVAL; + if ( is_iomem_page(mfn) || + !get_page_type(page, PGT_writable_page) ) + return -EINVAL; + if ( test_and_set_bit(_PGC_p2m_pinned, &page->count_info) ) + return -EBUSY; + } + return 0; +} + +int guest_physmap_unpin_range(struct domain *d, + xen_pfn_t gpfn, + unsigned int order) +{ + int i; + struct page_info *page; + xen_pfn_t mfn; + + for ( i = 0; i < (1UL << order); i++ ) + { + mfn = gmfn_to_mfn(d, gpfn + i); + page = mfn_to_page(mfn); + if ( !page ) + return -EINVAL; + if ( !test_and_clear_bit(_PGC_p2m_pinned, &page->count_info) ) + return -EINVAL; + } + return 0; +} + int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn, unsigned int order) @@ -217,6 +260,7 @@ static int create_p2m_entries(struct domain *d, lpae_t *first = NULL, *second = NULL, *third = NULL; paddr_t addr; unsigned long cur_first_offset = ~0, cur_second_offset = ~0; + struct page_info *page; spin_lock(&p2m->lock); @@ -228,6 +272,8 @@ static int create_p2m_entries(struct domain *d, for(addr = start_gpaddr; addr < end_gpaddr; addr += PAGE_SIZE) { + page = NULL; + if ( !first[first_table_offset(addr)].p2m.valid ) { rc = p2m_create_table(d, &first[first_table_offset(addr)]); @@ -268,11 +314,20 @@ static int create_p2m_entries(struct domain *d, flush = third[third_table_offset(addr)].p2m.valid; + if ( flush ) + page = mfn_to_page(third[third_table_offset(addr)].p2m.base); + if ( page && test_bit(_PGC_p2m_pinned, &page->count_info) ) + { + rc = -EINVAL; + gdprintk(XENLOG_WARNING, "cannot change p2m mapping for paddr=%"PRIpaddr + " domid=%d, the page is pinned\n", addr, d->domain_id); + goto out; + } + /* Allocate a new RAM page and attach */ switch (op) { case ALLOCATE: { - struct page_info *page; lpae_t pte; rc = -ENOMEM; diff --git a/xen/include/asm-arm/mm.h b/xen/include/asm-arm/mm.h index b7a9871..06b5aad 100644 --- a/xen/include/asm-arm/mm.h +++ b/xen/include/asm-arm/mm.h @@ -99,6 +99,9 @@ struct page_info /* Page is Xen heap? */ #define _PGC_xen_heap PG_shift(2) #define PGC_xen_heap PG_mask(1, 2) +/* The page belong to a guest and it has been pinned. */ +#define _PGC_p2m_pinned PG_shift(3) +#define PGC_p2m_pinned PG_mask(1, 3) /* ... */ /* Page is broken? */ #define _PGC_broken PG_shift(7) @@ -335,6 +338,10 @@ void free_init_memory(void); int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn, unsigned int order); +int guest_physmap_pin_range(struct domain *d, xen_pfn_t gpfn, + unsigned int order); +int guest_physmap_unpin_range(struct domain *d, xen_pfn_t gpfn, + unsigned int order); extern void put_page_type(struct page_info *page); static inline void put_page_and_type(struct page_info *page) diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h index 43583b2..b08a722 100644 --- a/xen/include/asm-x86/p2m.h +++ b/xen/include/asm-x86/p2m.h @@ -492,6 +492,18 @@ void guest_physmap_remove_page(struct domain *d, /* Set a p2m range as populate-on-demand */ int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn, unsigned int order); +static inline int guest_physmap_pin_range(struct domain *d, + xen_pfn_t gpfn, + unsigned int order) +{ + return -ENOSYS; +} +static inline int guest_physmap_unpin_range(struct domain *d, + xen_pfn_t gpfn, + unsigned int order) +{ + return -ENOSYS; +} /* Change types across all p2m entries in a domain */ void p2m_change_entry_type_global(struct domain *d, -- 1.7.2.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |