From 057b33e4720690585764e99213b1819fee2f2f48 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Thu, 4 Oct 2007 10:26:21 +0100 Subject: [PATCH] Allow iomem permissions to be set up through grant table ops. Signed-off-by: Kieran Mansley --- xen/arch/x86/mm.c | 11 ++++- xen/common/grant_table.c | 95 +++++++++++++++++++++++++++------------- xen/include/asm-x86/mm.h | 3 ++ 3 files changed, 77 insertions(+), 32 deletions(-) diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 53c01dc1b4..ecd41cf4a6 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -597,6 +597,14 @@ get_##level##_linear_pagetable( \ return 1; \ } + +int iomem_page_test(unsigned long mfn, struct page_info *page) +{ + return unlikely(!mfn_valid(mfn)) || + unlikely(page_get_owner(page) == dom_io); +} + + int get_page_from_l1e( l1_pgentry_t l1e, struct domain *d) @@ -614,8 +622,7 @@ get_page_from_l1e( return 0; } - if ( unlikely(!mfn_valid(mfn)) || - unlikely(page_get_owner(page) == dom_io) ) + if ( iomem_page_test(mfn, page) ) { /* DOMID_IO reverts to caller for privilege checks. */ if ( d == dom_io ) diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 18b464b47b..440699ab6f 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -198,6 +198,7 @@ __gnttab_map_grant_ref( int handle; unsigned long frame = 0; int rc = GNTST_okay; + int is_iomem = 0; struct active_grant_entry *act; struct grant_mapping *mt; grant_entry_t *sha; @@ -328,34 +329,52 @@ __gnttab_map_grant_ref( spin_unlock(&rd->grant_table->lock); - if ( unlikely(!mfn_valid(frame)) || - unlikely(!((op->flags & GNTMAP_readonly) ? - get_page(mfn_to_page(frame), rd) : - get_page_and_type(mfn_to_page(frame), rd, - PGT_writable_page))) ) - { - if ( !rd->is_dying ) - gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame); - rc = GNTST_general_error; - goto undo_out; - } + if ( op->flags & GNTMAP_host_map ) + { + /* Could be an iomem page for setting up permission */ + if( iomem_page_test(frame, mfn_to_page(frame)) ) { + is_iomem = 1; + if ( iomem_permit_access(ld, frame, frame) ) { + gdprintk(XENLOG_WARNING, + "Could not permit access to grant frame %lx as iomem\n", + frame); + rc = GNTST_general_error; + goto undo_out; + } + } + } - if ( op->flags & GNTMAP_host_map ) + if (!is_iomem ) { - rc = create_grant_host_mapping(op->host_addr, frame, op->flags); - if ( rc != GNTST_okay ) + if ( unlikely(!mfn_valid(frame)) || + unlikely(!((op->flags & GNTMAP_readonly) ? + get_page(mfn_to_page(frame), rd) : + get_page_and_type(mfn_to_page(frame), rd, + PGT_writable_page)))) { - if ( !(op->flags & GNTMAP_readonly) ) - put_page_type(mfn_to_page(frame)); - put_page(mfn_to_page(frame)); + if ( !rd->is_dying ) + gdprintk(XENLOG_WARNING, "Could not pin grant frame %lx\n", frame); + rc = GNTST_general_error; goto undo_out; } - - if ( op->flags & GNTMAP_device_map ) + + if ( op->flags & GNTMAP_host_map ) { - (void)get_page(mfn_to_page(frame), rd); - if ( !(op->flags & GNTMAP_readonly) ) - get_page_type(mfn_to_page(frame), PGT_writable_page); + rc = create_grant_host_mapping(op->host_addr, frame, op->flags); + if ( rc != GNTST_okay ) + { + if ( !(op->flags & GNTMAP_readonly) ) + put_page_type(mfn_to_page(frame)); + put_page(mfn_to_page(frame)); + goto undo_out; + } + + if ( op->flags & GNTMAP_device_map ) + { + (void)get_page(mfn_to_page(frame), rd); + if ( !(op->flags & GNTMAP_readonly) ) + get_page_type(mfn_to_page(frame), PGT_writable_page); + } } } @@ -483,7 +502,8 @@ __gnttab_unmap_common( { if ( unlikely(op->frame != act->frame) ) PIN_FAIL(unmap_out, GNTST_general_error, - "Bad frame number doesn't match gntref.\n"); + "Bad frame number doesn't match gntref. (%lx != %lx)\n", + op->frame, act->frame); if ( op->flags & GNTMAP_device_map ) { ASSERT(act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask)); @@ -495,12 +515,21 @@ __gnttab_unmap_common( } } - if ( (op->host_addr != 0) && (op->flags & GNTMAP_host_map) ) + if ( op->flags & GNTMAP_host_map ) { - if ( (rc = replace_grant_host_mapping(op->host_addr, - op->frame, op->new_addr, - op->flags)) < 0 ) - goto unmap_out; + if ( (op->host_addr != 0) ) + { + if ( (rc = replace_grant_host_mapping(op->host_addr, + op->frame, op->new_addr, + op->flags)) < 0 ) + goto unmap_out; + } + else if ( iomem_page_test(op->frame, mfn_to_page(op->frame)) && + iomem_access_permitted(ld, op->frame, op->frame) ) + { + if ( (rc = iomem_deny_access(ld, op->frame, op->frame)) < 0 ) + goto unmap_out; + } ASSERT(act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)); op->map->flags &= ~GNTMAP_host_map; @@ -508,7 +537,7 @@ __gnttab_unmap_common( act->pin -= GNTPIN_hstr_inc; else act->pin -= GNTPIN_hstw_inc; - } + } /* If just unmapped a writable mapping, mark as dirtied */ if ( !(op->flags & GNTMAP_readonly) ) @@ -1577,6 +1606,7 @@ gnttab_release_mappings( struct domain *rd; struct active_grant_entry *act; struct grant_entry *sha; + int rc; BUG_ON(!d->is_dying); @@ -1634,7 +1664,12 @@ gnttab_release_mappings( { BUG_ON(!(act->pin & GNTPIN_hstw_mask)); act->pin -= GNTPIN_hstw_inc; - gnttab_release_put_page_and_type(mfn_to_page(act->frame)); + + if ( iomem_page_test(act->frame, mfn_to_page(act->frame)) && + iomem_access_permitted(rd, act->frame, act->frame) ) + rc = iomem_deny_access(rd, act->frame, act->frame); + else + gnttab_release_put_page_and_type(mfn_to_page(act->frame)); } if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 ) diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h index 3d6bec348a..b6106577f8 100644 --- a/xen/include/asm-x86/mm.h +++ b/xen/include/asm-x86/mm.h @@ -197,6 +197,9 @@ static inline int get_page(struct page_info *page, return 1; } +/* Decide whether this page looks like iomem or real memory */ +int iomem_page_test(unsigned long mfn, struct page_info *page); + void put_page_type(struct page_info *page); int get_page_type(struct page_info *page, unsigned long type); int get_page_from_l1e(l1_pgentry_t l1e, struct domain *d); -- 2.39.5