[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Move arch-specific portions of grant-table implementation
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID 944cf29d126d9cdd84f033da9c0f8b1c843b1361 # Parent 6d9ea03c1baa19dfefbbb6ccc7ab43cff2383206 Move arch-specific portions of grant-table implementation out of common code. Ready for use by ia64. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r 6d9ea03c1baa -r 944cf29d126d xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Wed Nov 23 12:38:34 2005 +++ b/xen/arch/ia64/Makefile Wed Nov 23 12:50:14 2005 @@ -10,7 +10,7 @@ extable.o linuxextable.o sort.o xenirq.o xentime.o \ regionreg.o entry.o unaligned.o privop.o vcpu.o \ irq_ia64.o irq_lsapic.o vhpt.o xenasm.o hyperprivop.o dom_fw.o \ - grant_table.o sn_console.o # ia64_ksyms.o + sn_console.o # ia64_ksyms.o OBJS += vmx_init.o vmx_virt.o vmx_vcpu.o vmx_process.o vmx_vsa.o vmx_ivt.o\ vmx_phy_mode.o vmx_utility.o vmx_interrupt.o vmx_entry.o vmmu.o \ diff -r 6d9ea03c1baa -r 944cf29d126d xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Wed Nov 23 12:38:34 2005 +++ b/xen/arch/x86/mm.c Wed Nov 23 12:50:14 2005 @@ -2306,7 +2306,7 @@ } -int update_grant_pte_mapping( +static int create_grant_pte_mapping( unsigned long pte_addr, l1_pgentry_t _nl1e, struct vcpu *v) { int rc = GNTST_okay; @@ -2368,7 +2368,7 @@ return rc; } -int clear_grant_pte_mapping( +static int destroy_grant_pte_mapping( unsigned long addr, unsigned long frame, struct domain *d) { int rc = GNTST_okay; @@ -2445,7 +2445,7 @@ } -int update_grant_va_mapping( +static int create_grant_va_mapping( unsigned long va, l1_pgentry_t _nl1e, struct vcpu *v) { l1_pgentry_t *pl1e, ol1e; @@ -2475,7 +2475,8 @@ return GNTST_okay; } -int clear_grant_va_mapping(unsigned long addr, unsigned long frame) +static int destroy_grant_va_mapping( + unsigned long addr, unsigned long frame) { l1_pgentry_t *pl1e, ol1e; @@ -2508,6 +2509,74 @@ return 0; } +int create_grant_host_mapping( + unsigned long addr, unsigned long frame, unsigned int flags) +{ + l1_pgentry_t pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS); + + if ( (flags & GNTMAP_application_map) ) + l1e_add_flags(pte,_PAGE_USER); + if ( !(flags & GNTMAP_readonly) ) + l1e_add_flags(pte,_PAGE_RW); + + if ( flags & GNTMAP_contains_pte ) + return create_grant_pte_mapping(addr, pte, current); + return create_grant_va_mapping(addr, pte, current); +} + +int destroy_grant_host_mapping( + unsigned long addr, unsigned long frame, unsigned int flags) +{ + if ( flags & GNTMAP_contains_pte ) + return destroy_grant_pte_mapping(addr, frame, current->domain); + return destroy_grant_va_mapping(addr, frame); +} + +int steal_page_for_grant_transfer( + struct domain *d, struct pfn_info *page) +{ + u32 _d, _nd, x, y; + + spin_lock(&d->page_alloc_lock); + + /* + * The tricky bit: atomically release ownership while there is just one + * benign reference to the page (PGC_allocated). If that reference + * disappears then the deallocation routine will safely spin. + */ + _d = pickle_domptr(d); + _nd = page->u.inuse._domain; + y = page->count_info; + do { + x = y; + if (unlikely((x & (PGC_count_mask|PGC_allocated)) != + (1 | PGC_allocated)) || unlikely(_nd != _d)) { + DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p," + " caf=%08x, taf=%" PRtype_info "\n", + (void *) page_to_pfn(page), + d, d->domain_id, unpickle_domptr(_nd), x, + page->u.inuse.type_info); + spin_unlock(&d->page_alloc_lock); + return -1; + } + __asm__ __volatile__( + LOCK_PREFIX "cmpxchg8b %2" + : "=d" (_nd), "=a" (y), + "=m" (*(volatile u64 *)(&page->count_info)) + : "0" (_d), "1" (x), "c" (NULL), "b" (x) ); + } while (unlikely(_nd != _d) || unlikely(y != x)); + + /* + * Unlink from 'd'. At least one reference remains (now anonymous), so + * noone else is spinning to try to delete this page from 'd'. + */ + d->tot_pages--; + list_del(&page->list); + + spin_unlock(&d->page_alloc_lock); + + return 0; +} int do_update_va_mapping(unsigned long va, u64 val64, unsigned long flags) diff -r 6d9ea03c1baa -r 944cf29d126d xen/common/Makefile --- a/xen/common/Makefile Wed Nov 23 12:38:34 2005 +++ b/xen/common/Makefile Wed Nov 23 12:50:14 2005 @@ -1,9 +1,5 @@ include $(BASEDIR)/Rules.mk - -ifeq ($(TARGET_ARCH),ia64) -OBJS := $(subst grant_table.o,,$(OBJS)) -endif ifneq ($(perfc),y) OBJS := $(subst perfc.o,,$(OBJS)) diff -r 6d9ea03c1baa -r 944cf29d126d xen/common/grant_table.c --- a/xen/common/grant_table.c Wed Nov 23 12:38:34 2005 +++ b/xen/common/grant_table.c Wed Nov 23 12:50:14 2005 @@ -330,20 +330,7 @@ if ( dev_hst_ro_flags & GNTMAP_host_map ) { - /* Write update into the pagetable. */ - l1_pgentry_t pte; - pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS); - - if ( (dev_hst_ro_flags & GNTMAP_application_map) ) - l1e_add_flags(pte,_PAGE_USER); - if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) - l1e_add_flags(pte,_PAGE_RW); - - if ( dev_hst_ro_flags & GNTMAP_contains_pte ) - rc = update_grant_pte_mapping(addr, pte, led); - else - rc = update_grant_va_mapping(addr, pte, led); - + rc = create_grant_host_mapping(addr, frame, dev_hst_ro_flags); if ( rc < 0 ) { /* Failure: undo and abort. */ @@ -488,16 +475,8 @@ (flags & GNTMAP_host_map) && ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0)) { - if ( flags & GNTMAP_contains_pte ) - { - if ( (rc = clear_grant_pte_mapping(addr, frame, ld)) < 0 ) - goto unmap_out; - } - else - { - if ( (rc = clear_grant_va_mapping(addr, frame)) < 0 ) - goto unmap_out; - } + if ( (rc = destroy_grant_host_mapping(addr, frame, flags)) < 0 ) + goto unmap_out; map->ref_and_flags &= ~GNTMAP_host_map; @@ -512,9 +491,8 @@ } /* If just unmapped a writable mapping, mark as dirtied */ - if ( unlikely(shadow_mode_log_dirty(rd)) && - !(flags & GNTMAP_readonly) ) - mark_dirty(rd, frame); + if ( !(flags & GNTMAP_readonly) ) + gnttab_log_dirty(rd, frame); /* If the last writable mapping has been removed, put_page_type */ if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) && @@ -599,9 +577,8 @@ ASSERT(d->grant_table != NULL); (void)put_user(GNTST_okay, &uop->status); for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user( - (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, - &uop->frame_list[i]); + (void)put_user(gnttab_shared_mfn(d, d->grant_table, i), + &uop->frame_list[i]); } put_domain(d); @@ -698,7 +675,6 @@ struct domain *d = current->domain; struct domain *e; struct pfn_info *page; - u32 _d, _nd, x, y; int i; grant_entry_t *sha; gnttab_transfer_t gop; @@ -723,46 +699,11 @@ continue; } - spin_lock(&d->page_alloc_lock); - - /* - * The tricky bit: atomically release ownership while - * there is just one benign reference to the page - * (PGC_allocated). If that reference disappears then the - * deallocation routine will safely spin. - */ - _d = pickle_domptr(d); - _nd = page->u.inuse._domain; - y = page->count_info; - do { - x = y; - if (unlikely((x & (PGC_count_mask|PGC_allocated)) != - (1 | PGC_allocated)) || unlikely(_nd != _d)) { - DPRINTK("gnttab_transfer: Bad page %p: ed=%p(%u), sd=%p," - " caf=%08x, taf=%" PRtype_info "\n", - (void *) page_to_pfn(page), - d, d->domain_id, unpickle_domptr(_nd), x, - page->u.inuse.type_info); - spin_unlock(&d->page_alloc_lock); - (void)__put_user(GNTST_bad_page, &uop[i].status); - continue; - } - __asm__ __volatile__( - LOCK_PREFIX "cmpxchg8b %2" - : "=d" (_nd), "=a" (y), - "=m" (*(volatile u64 *)(&page->count_info)) - : "0" (_d), "1" (x), "c" (NULL), "b" (x) ); - } while (unlikely(_nd != _d) || unlikely(y != x)); - - /* - * Unlink from 'd'. At least one reference remains (now - * anonymous), so noone else is spinning to try to delete - * this page from 'd'. - */ - d->tot_pages--; - list_del(&page->list); - - spin_unlock(&d->page_alloc_lock); + if ( steal_page_for_grant_transfer(d, page) < 0 ) + { + (void)__put_user(GNTST_bad_page, &uop[i].status); + continue; + } /* Find the target domain. */ if ( unlikely((e = find_domain_by_id(gop.domid)) == NULL) ) @@ -991,14 +932,7 @@ memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE); for ( i = 0; i < NR_GRANT_FRAMES; i++ ) - { - SHARE_PFN_WITH_DOMAIN( - virt_to_page((char *)t->shared + (i * PAGE_SIZE)), - d); - set_pfn_from_mfn( - (virt_to_phys(t->shared) >> PAGE_SHIFT) + i, - INVALID_M2P_ENTRY); - } + gnttab_create_shared_mfn(d, t, i); /* Okay, install the structure. */ wmb(); /* avoid races with lock-free access to d->grant_table */ diff -r 6d9ea03c1baa -r 944cf29d126d xen/include/asm-x86/mm.h --- a/xen/include/asm-x86/mm.h Wed Nov 23 12:38:34 2005 +++ b/xen/include/asm-x86/mm.h Wed Nov 23 12:50:14 2005 @@ -381,16 +381,4 @@ extern int __sync_lazy_execstate(void); -/* - * Caller must own d's BIGLOCK, is responsible for flushing the TLB, and must - * hold a reference to the page. - */ -int update_grant_va_mapping( - unsigned long va, l1_pgentry_t _nl1e, struct vcpu *v); -int update_grant_pte_mapping( - unsigned long pte_addr, l1_pgentry_t _nl1e, struct vcpu *v); -int clear_grant_va_mapping(unsigned long addr, unsigned long frame); -int clear_grant_pte_mapping( - unsigned long addr, unsigned long frame, struct domain *d); - #endif /* __ASM_X86_MM_H__ */ diff -r 6d9ea03c1baa -r 944cf29d126d xen/include/xen/grant_table.h --- a/xen/include/xen/grant_table.h Wed Nov 23 12:38:34 2005 +++ b/xen/include/xen/grant_table.h Wed Nov 23 12:50:14 2005 @@ -4,7 +4,7 @@ * Mechanism for granting foreign access to page frames, and receiving * page-ownership transfers. * - * Copyright (c) 2004 K A Fraser + * Copyright (c) 2004-2005 K A Fraser * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -21,11 +21,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef __XEN_GRANT_H__ -#define __XEN_GRANT_H__ +#ifndef __XEN_GRANT_TABLE_H__ +#define __XEN_GRANT_TABLE_H__ #include <xen/config.h> #include <public/grant_table.h> +#include <asm/grant_table.h> /* Active grant entry - used for shadowing GTF_permit_access grants. */ typedef struct { @@ -51,7 +52,6 @@ #define GNTPIN_devr_inc (1 << GNTPIN_devr_shift) #define GNTPIN_devr_mask (0xFFU << GNTPIN_devr_shift) -#define ORDER_GRANT_FRAMES 2 #define NR_GRANT_FRAMES (1U << ORDER_GRANT_FRAMES) #define NR_GRANT_ENTRIES \ ((NR_GRANT_FRAMES << PAGE_SHIFT) / sizeof(grant_entry_t)) @@ -107,4 +107,4 @@ gnttab_release_mappings( struct domain *d); -#endif /* __XEN_GRANT_H__ */ +#endif /* __XEN_GRANT_TABLE_H__ */ diff -r 6d9ea03c1baa -r 944cf29d126d xen/include/asm-ia64/grant_table.h --- /dev/null Wed Nov 23 12:38:34 2005 +++ b/xen/include/asm-ia64/grant_table.h Wed Nov 23 12:50:14 2005 @@ -0,0 +1,26 @@ +/****************************************************************************** + * include/asm-ia64/grant_table.h + */ + +#ifndef __ASM_GRANT_TABLE_H__ +#define __ASM_GRANT_TABLE_H__ + +#define ORDER_GRANT_FRAMES 0 + +#define create_grant_host_mapping(a, f, fl) 0 +#define destroy_grant_host_mapping(a, f, fl) 0 + +#define steal_page_for_grant_transfer(d, p) 0 + +#define gnttab_create_shared_mfn(d, t, i) ((void)0) + +#define gnttab_shared_mfn(d, t, i) \ + ( ((d) == dom0) ? \ + ((virt_to_phys((t)shared) >> PAGE_SHIFT) + (i)) : \ + (map_domain_page((d), 1UL<<40, virt_to_phys((t)->shared)), \ + 1UL << (40 - PAGE_SHIFT)) \ + ) + +#define gnttab_log_dirty(d, f) ((void)0) + +#endif /* __ASM_GRANT_TABLE_H__ */ diff -r 6d9ea03c1baa -r 944cf29d126d xen/include/asm-x86/grant_table.h --- /dev/null Wed Nov 23 12:38:34 2005 +++ b/xen/include/asm-x86/grant_table.h Wed Nov 23 12:50:14 2005 @@ -0,0 +1,42 @@ +/****************************************************************************** + * include/asm-x86/grant_table.h + * + * Copyright (c) 2004-2005 K A Fraser + */ + +#ifndef __ASM_GRANT_TABLE_H__ +#define __ASM_GRANT_TABLE_H__ + +#define ORDER_GRANT_FRAMES 2 + +/* + * Caller must own caller's BIGLOCK, is responsible for flushing the TLB, and + * must hold a reference to the page. + */ +int create_grant_host_mapping( + unsigned long addr, unsigned long frame, unsigned int flags); +int destroy_grant_host_mapping( + unsigned long addr, unsigned long frame, unsigned int flags); + +int steal_page_for_grant_transfer( + struct domain *d, struct pfn_info *page); + +#define gnttab_create_shared_mfn(d, t, i) \ + do { \ + SHARE_PFN_WITH_DOMAIN( \ + virt_to_page((char *)(t)->shared + ((i) * PAGE_SIZE)), (d)); \ + set_pfn_from_mfn( \ + (virt_to_phys((t)->shared) >> PAGE_SHIFT) + (i), \ + INVALID_M2P_ENTRY); \ + } while ( 0 ) + +#define gnttab_shared_mfn(d, t, i) \ + ((virt_to_phys((t)->shared) >> PAGE_SHIFT) + (i)) + +#define gnttab_log_dirty(d, f) \ + do { \ + if ( unlikely(shadow_mode_log_dirty((d))) ) \ + mark_dirty((d), (f)); \ + } while ( 0 ) + +#endif /* __ASM_GRANT_TABLE_H__ */ diff -r 6d9ea03c1baa -r 944cf29d126d xen/arch/ia64/xen/grant_table.c --- a/xen/arch/ia64/xen/grant_table.c Wed Nov 23 12:38:34 2005 +++ /dev/null Wed Nov 23 12:50:14 2005 @@ -1,1354 +0,0 @@ -// temporarily in arch/ia64 until can merge into common/grant_table.c -/****************************************************************************** - * common/grant_table.c - * - * Mechanism for granting foreign access to page frames, and receiving - * page-ownership transfers. - * - * Copyright (c) 2005 Christopher Clark - * Copyright (c) 2004 K A Fraser - * Copyright (c) 2005 Andrew Warfield - * Modifications by Geoffrey Lefebvre are (c) Intel Research Cambridge - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define GRANT_DEBUG 0 -#define GRANT_DEBUG_VERBOSE 0 - -#include <xen/config.h> -#include <xen/lib.h> -#include <xen/sched.h> -#include <xen/shadow.h> -#include <xen/mm.h> -#ifdef __ia64__ -#define __addr_ok(a) 1 // FIXME-ia64: a variant of access_ok?? -// FIXME-ia64: these belong in an asm/grant_table.h... PAGE_SIZE different -#undef ORDER_GRANT_FRAMES -//#undef NUM_GRANT_FRAMES -#define ORDER_GRANT_FRAMES 0 -//#define NUM_GRANT_FRAMES (1U << ORDER_GRANT_FRAMES) -#endif -#include <acm/acm_hooks.h> - -#if defined(CONFIG_X86_64) -#define GRANT_PTE_FLAGS (_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER) -#else -#define GRANT_PTE_FLAGS (_PAGE_PRESENT|_PAGE_ACCESSED|_PAGE_DIRTY) -#endif - -#define PIN_FAIL(_lbl, _rc, _f, _a...) \ - do { \ - DPRINTK( _f, ## _a ); \ - rc = (_rc); \ - goto _lbl; \ - } while ( 0 ) - -static inline int -get_maptrack_handle( - grant_table_t *t) -{ - unsigned int h; - if ( unlikely((h = t->maptrack_head) == (t->maptrack_limit - 1)) ) - return -1; - t->maptrack_head = t->maptrack[h].ref_and_flags >> MAPTRACK_REF_SHIFT; - t->map_count++; - return h; -} - -static inline void -put_maptrack_handle( - grant_table_t *t, int handle) -{ - t->maptrack[handle].ref_and_flags = t->maptrack_head << MAPTRACK_REF_SHIFT; - t->maptrack_head = handle; - t->map_count--; -} - -static int -__gnttab_activate_grant_ref( - struct domain *mapping_d, /* IN */ - struct vcpu *mapping_ed, - struct domain *granting_d, - grant_ref_t ref, - u16 dev_hst_ro_flags, - u64 addr, - unsigned long *pframe ) /* OUT */ -{ - domid_t sdom; - u16 sflags; - active_grant_entry_t *act; - grant_entry_t *sha; - s16 rc = 1; - unsigned long frame = 0; - int retries = 0; - - /* - * Objectives of this function: - * . Make the record ( granting_d, ref ) active, if not already. - * . Update shared grant entry of owner, indicating frame is mapped. - * . Increment the owner act->pin reference counts. - * . get_page on shared frame if new mapping. - * . get_page_type if this is first RW mapping of frame. - * . Add PTE to virtual address space of mapping_d, if necessary. - * Returns: - * . -ve: error - * . 1: ok - * . 0: ok and TLB invalidate of host_addr needed. - * - * On success, *pframe contains mfn. - */ - - /* - * We bound the number of times we retry CMPXCHG on memory locations that - * we share with a guest OS. The reason is that the guest can modify that - * location at a higher rate than we can read-modify-CMPXCHG, so the guest - * could cause us to livelock. There are a few cases where it is valid for - * the guest to race our updates (e.g., to change the GTF_readonly flag), - * so we allow a few retries before failing. - */ - - act = &granting_d->grant_table->active[ref]; - sha = &granting_d->grant_table->shared[ref]; - - spin_lock(&granting_d->grant_table->lock); - - if ( act->pin == 0 ) - { - /* CASE 1: Activating a previously inactive entry. */ - - sflags = sha->flags; - sdom = sha->domid; - - /* This loop attempts to set the access (reading/writing) flags - * in the grant table entry. It tries a cmpxchg on the field - * up to five times, and then fails under the assumption that - * the guest is misbehaving. */ - for ( ; ; ) - { - u32 scombo, prev_scombo, new_scombo; - - if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) || - unlikely(sdom != mapping_d->domain_id) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", - sflags, sdom, mapping_d->domain_id); - - /* Merge two 16-bit values into a 32-bit combined update. */ - /* NB. Endianness! */ - prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; - - new_scombo = scombo | GTF_reading; - if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) - { - new_scombo |= GTF_writing; - if ( unlikely(sflags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - } - - /* NB. prev_scombo is updated in place to seen value. */ - if ( unlikely(cmpxchg_user((u32 *)&sha->flags, - prev_scombo, - new_scombo)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Fault while modifying shared flags and domid.\n"); - - /* Did the combined update work (did we see what we expected?). */ - if ( likely(prev_scombo == scombo) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - /* Didn't see what we expected. Split out the seen flags & dom. */ - /* NB. Endianness! */ - sflags = (u16)prev_scombo; - sdom = (u16)(prev_scombo >> 16); - } - - /* rmb(); */ /* not on x86 */ - - frame = __gpfn_to_mfn_foreign(granting_d, sha->frame); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( unlikely(!pfn_valid(frame)) || - unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ? - get_page(&frame_table[frame], granting_d) : - get_page_and_type(&frame_table[frame], granting_d, - PGT_writable_page))) ) - { - clear_bit(_GTF_writing, &sha->flags); - clear_bit(_GTF_reading, &sha->flags); - PIN_FAIL(unlock_out, GNTST_general_error, - "Could not pin the granted frame (%lx)!\n", frame); - } -#endif - - if ( dev_hst_ro_flags & GNTMAP_device_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_devr_inc : GNTPIN_devw_inc; - if ( dev_hst_ro_flags & GNTMAP_host_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_hstr_inc : GNTPIN_hstw_inc; - act->domid = sdom; - act->frame = frame; - } - else - { - /* CASE 2: Active modications to an already active entry. */ - - /* - * A cheesy check for possible pin-count overflow. - * A more accurate check cannot be done with a single comparison. - */ - if ( (act->pin & 0x80808080U) != 0 ) - PIN_FAIL(unlock_out, ENOSPC, - "Risk of counter overflow %08x\n", act->pin); - - frame = act->frame; - - if ( !(dev_hst_ro_flags & GNTMAP_readonly) && - !((sflags = sha->flags) & GTF_writing) ) - { - for ( ; ; ) - { - u16 prev_sflags; - - if ( unlikely(sflags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - - prev_sflags = sflags; - - /* NB. prev_sflags is updated in place to seen value. */ - if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags, - prev_sflags | GTF_writing)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Fault while modifying shared flags.\n"); - - if ( likely(prev_sflags == sflags) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - sflags = prev_sflags; - } - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( unlikely(!get_page_type(&frame_table[frame], - PGT_writable_page)) ) - { - clear_bit(_GTF_writing, &sha->flags); - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a unwritable page.\n"); - } -#endif - } - - if ( dev_hst_ro_flags & GNTMAP_device_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_devr_inc : GNTPIN_devw_inc; - - if ( dev_hst_ro_flags & GNTMAP_host_map ) - act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? - GNTPIN_hstr_inc : GNTPIN_hstw_inc; - } - - /* - * At this point: - * act->pin updated to reference count mappings. - * sha->flags updated to indicate to granting domain mapping done. - * frame contains the mfn. - */ - - spin_unlock(&granting_d->grant_table->lock); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( (addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) ) - { - /* Write update into the pagetable. */ - l1_pgentry_t pte; - pte = l1e_from_pfn(frame, GRANT_PTE_FLAGS); - - if ( (dev_hst_ro_flags & GNTMAP_application_map) ) - l1e_add_flags(pte,_PAGE_USER); - if ( !(dev_hst_ro_flags & GNTMAP_readonly) ) - l1e_add_flags(pte,_PAGE_RW); - - if ( dev_hst_ro_flags & GNTMAP_contains_pte ) - rc = update_grant_pte_mapping(addr, pte, mapping_d, mapping_ed); - else - rc = update_grant_va_mapping(addr, pte, mapping_d, mapping_ed); - - /* IMPORTANT: rc indicates the degree of TLB flush that is required. - * GNTST_flush_one (1) or GNTST_flush_all (2). This is done in the - * outer gnttab_map_grant_ref. */ - if ( rc < 0 ) - { - /* Failure: undo and abort. */ - - spin_lock(&granting_d->grant_table->lock); - - if ( dev_hst_ro_flags & GNTMAP_readonly ) - { - act->pin -= GNTPIN_hstr_inc; - } - else - { - act->pin -= GNTPIN_hstw_inc; - if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - } - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); - } - - spin_unlock(&granting_d->grant_table->lock); - } - - } -#endif - - *pframe = frame; - return rc; - - unlock_out: - spin_unlock(&granting_d->grant_table->lock); - return rc; -} - -/* - * Returns 0 if TLB flush / invalidate required by caller. - * va will indicate the address to be invalidated. - * - * addr is _either_ a host virtual address, or the address of the pte to - * update, as indicated by the GNTMAP_contains_pte flag. - */ -static int -__gnttab_map_grant_ref( - gnttab_map_grant_ref_t *uop, - unsigned long *va) -{ - domid_t dom; - grant_ref_t ref; - struct domain *ld, *rd; - struct vcpu *led; - u16 dev_hst_ro_flags; - int handle; - u64 addr; - unsigned long frame = 0; - int rc; - - led = current; - ld = led->domain; - - /* Bitwise-OR avoids short-circuiting which screws control flow. */ - if ( unlikely(__get_user(dom, &uop->dom) | - __get_user(ref, &uop->ref) | - __get_user(addr, &uop->host_addr) | - __get_user(dev_hst_ro_flags, &uop->flags)) ) - { - DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n"); - return -EFAULT; /* don't set status */ - } - - if ( (dev_hst_ro_flags & GNTMAP_host_map) && - ( (addr == 0) || - (!(dev_hst_ro_flags & GNTMAP_contains_pte) && - unlikely(!__addr_ok(addr))) ) ) - { - DPRINTK("Bad virtual address (%"PRIx64") or flags (%"PRIx16").\n", - addr, dev_hst_ro_flags); - (void)__put_user(GNTST_bad_virt_addr, &uop->handle); - return GNTST_bad_gntref; - } - - if ( unlikely(ref >= NR_GRANT_ENTRIES) || - unlikely((dev_hst_ro_flags & - (GNTMAP_device_map|GNTMAP_host_map)) == 0) ) - { - DPRINTK("Bad ref (%d) or flags (%x).\n", ref, dev_hst_ro_flags); - (void)__put_user(GNTST_bad_gntref, &uop->handle); - return GNTST_bad_gntref; - } - - if (acm_pre_grant_map_ref(dom)) { - (void)__put_user(GNTST_permission_denied, &uop->handle); - return GNTST_permission_denied; - } - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - DPRINTK("Could not find domain %d\n", dom); - (void)__put_user(GNTST_bad_domain, &uop->handle); - return GNTST_bad_domain; - } - - /* Get a maptrack handle. */ - if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) ) - { - int i; - grant_mapping_t *new_mt; - grant_table_t *lgt = ld->grant_table; - - if ( (lgt->maptrack_limit << 1) > MAPTRACK_MAX_ENTRIES ) - { - put_domain(rd); - DPRINTK("Maptrack table is at maximum size.\n"); - (void)__put_user(GNTST_no_device_space, &uop->handle); - return GNTST_no_device_space; - } - - /* Grow the maptrack table. */ - new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1); - if ( new_mt == NULL ) - { - put_domain(rd); - DPRINTK("No more map handles available.\n"); - (void)__put_user(GNTST_no_device_space, &uop->handle); - return GNTST_no_device_space; - } - - memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order); - for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ ) - new_mt[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; - - free_xenheap_pages(lgt->maptrack, lgt->maptrack_order); - lgt->maptrack = new_mt; - lgt->maptrack_order += 1; - lgt->maptrack_limit <<= 1; - - DPRINTK("Doubled maptrack size\n"); - handle = get_maptrack_handle(ld->grant_table); - } - -#if GRANT_DEBUG_VERBOSE - DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n", - ref, dom, dev_hst_ro_flags); -#endif - - if ( 0 <= ( rc = __gnttab_activate_grant_ref( ld, led, rd, ref, - dev_hst_ro_flags, - addr, &frame))) - { - /* - * Only make the maptrack live _after_ writing the pte, in case we - * overwrite the same frame number, causing a maptrack walk to find it - */ - ld->grant_table->maptrack[handle].domid = dom; - - ld->grant_table->maptrack[handle].ref_and_flags - = (ref << MAPTRACK_REF_SHIFT) | - (dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK); - - (void)__put_user((u64)frame << PAGE_SHIFT, &uop->dev_bus_addr); - - if ( ( dev_hst_ro_flags & GNTMAP_host_map ) && - !( dev_hst_ro_flags & GNTMAP_contains_pte) ) - *va = addr; - - (void)__put_user(handle, &uop->handle); - } - else - { - (void)__put_user(rc, &uop->handle); - put_maptrack_handle(ld->grant_table, handle); - } - - put_domain(rd); - return rc; -} - -static long -gnttab_map_grant_ref( - gnttab_map_grant_ref_t *uop, unsigned int count) -{ - int i, rc, flush = 0; - unsigned long va = 0; - - for ( i = 0; i < count; i++ ) - if ( (rc =__gnttab_map_grant_ref(&uop[i], &va)) >= 0 ) - flush += rc; - -#ifdef __ia64__ -// FIXME-ia64: probably need to do something here to avoid stale mappings? -#else - if ( flush == 1 ) - flush_tlb_one_mask(current->domain->cpumask, va); - else if ( flush != 0 ) - flush_tlb_mask(current->domain->cpumask); -#endif - - return 0; -} - -static int -__gnttab_unmap_grant_ref( - gnttab_unmap_grant_ref_t *uop, - unsigned long *va) -{ - domid_t dom; - grant_ref_t ref; - u16 handle; - struct domain *ld, *rd; - active_grant_entry_t *act; - grant_entry_t *sha; - grant_mapping_t *map; - u16 flags; - s16 rc = 1; - u64 addr, dev_bus_addr; - unsigned long frame; - - ld = current->domain; - - /* Bitwise-OR avoids short-circuiting which screws control flow. */ - if ( unlikely(__get_user(addr, &uop->host_addr) | - __get_user(dev_bus_addr, &uop->dev_bus_addr) | - __get_user(handle, &uop->handle)) ) - { - DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n"); - return -EFAULT; /* don't set status */ - } - - frame = (unsigned long)(dev_bus_addr >> PAGE_SHIFT); - - map = &ld->grant_table->maptrack[handle]; - - if ( unlikely(handle >= ld->grant_table->maptrack_limit) || - unlikely(!(map->ref_and_flags & MAPTRACK_GNTMAP_MASK)) ) - { - DPRINTK("Bad handle (%d).\n", handle); - (void)__put_user(GNTST_bad_handle, &uop->status); - return GNTST_bad_handle; - } - - dom = map->domid; - ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; - flags = map->ref_and_flags & MAPTRACK_GNTMAP_MASK; - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - DPRINTK("Could not find domain %d\n", dom); - (void)__put_user(GNTST_bad_domain, &uop->status); - return GNTST_bad_domain; - } - -#if GRANT_DEBUG_VERBOSE - DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n", - ref, dom, handle); -#endif - - act = &rd->grant_table->active[ref]; - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - - if ( frame == 0 ) - { - frame = act->frame; - } - else - { - if ( unlikely(frame != act->frame) ) - PIN_FAIL(unmap_out, GNTST_general_error, - "Bad frame number doesn't match gntref.\n"); - if ( flags & GNTMAP_device_map ) - act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc - : GNTPIN_devw_inc; - - map->ref_and_flags &= ~GNTMAP_device_map; - (void)__put_user(0, &uop->dev_bus_addr); - - /* Frame is now unmapped for device access. */ - } - - if ( (addr != 0) && - (flags & GNTMAP_host_map) && - ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0)) - { -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - if ( flags & GNTMAP_contains_pte ) - { - if ( (rc = clear_grant_pte_mapping(addr, frame, ld)) < 0 ) - goto unmap_out; - } - else - { - if ( (rc = clear_grant_va_mapping(addr, frame)) < 0 ) - goto unmap_out; - } -#endif - - map->ref_and_flags &= ~GNTMAP_host_map; - - act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc - : GNTPIN_hstw_inc; - - rc = 0; - if ( !( flags & GNTMAP_contains_pte) ) - *va = addr; - } - - if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0) - { - map->ref_and_flags = 0; - put_maptrack_handle(ld->grant_table, handle); - } - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? I think not and then -// this can probably be macro-ized into nothingness -#else - /* If just unmapped a writable mapping, mark as dirtied */ - if ( unlikely(shadow_mode_log_dirty(rd)) && - !( flags & GNTMAP_readonly ) ) - mark_dirty(rd, frame); -#endif - - /* If the last writable mapping has been removed, put_page_type */ - if ( ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask) ) == 0) && - ( !( flags & GNTMAP_readonly ) ) ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - - if ( act->pin == 0 ) - { - act->frame = 0xdeadbeef; - clear_bit(_GTF_reading, &sha->flags); - put_page(&frame_table[frame]); - } - - unmap_out: - (void)__put_user(rc, &uop->status); - spin_unlock(&rd->grant_table->lock); - put_domain(rd); - return rc; -} - -static long -gnttab_unmap_grant_ref( - gnttab_unmap_grant_ref_t *uop, unsigned int count) -{ - int i, flush = 0; - unsigned long va = 0; - - for ( i = 0; i < count; i++ ) - if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 ) - flush++; - -#ifdef __ia64__ -// FIXME-ia64: probably need to do something here to avoid stale mappings? -#else - if ( flush == 1 ) - flush_tlb_one_mask(current->domain->cpumask, va); - else if ( flush != 0 ) - flush_tlb_mask(current->domain->cpumask); -#endif - - return 0; -} - -static long -gnttab_setup_table( - gnttab_setup_table_t *uop, unsigned int count) -{ - gnttab_setup_table_t op; - struct domain *d; - int i; - - if ( count != 1 ) - return -EINVAL; - - if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) - { - DPRINTK("Fault while reading gnttab_setup_table_t.\n"); - return -EFAULT; - } - - if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) ) - { - DPRINTK("Xen only supports up to %d grant-table frames per domain.\n", - NR_GRANT_FRAMES); - (void)put_user(GNTST_general_error, &uop->status); - return 0; - } - - if ( op.dom == DOMID_SELF ) - { - op.dom = current->domain->domain_id; - } - else if ( unlikely(!IS_PRIV(current->domain)) ) - { - (void)put_user(GNTST_permission_denied, &uop->status); - return 0; - } - - if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) - { - DPRINTK("Bad domid %d.\n", op.dom); - (void)put_user(GNTST_bad_domain, &uop->status); - return 0; - } - - if ( op.nr_frames <= NR_GRANT_FRAMES ) - { - ASSERT(d->grant_table != NULL); - (void)put_user(GNTST_okay, &uop->status); -#ifdef __ia64__ - if (d == dom0) { - for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user( - (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, - &uop->frame_list[i]); - } else { - /* IA64 hack - need to map it somewhere */ - unsigned long addr = (1UL << 40); - map_domain_page(d, addr, virt_to_phys(d->grant_table->shared)); - (void)put_user(addr >> PAGE_SHIFT, &uop->frame_list[0]); - } -#else - for ( i = 0; i < op.nr_frames; i++ ) - (void)put_user( - (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i, - &uop->frame_list[i]); -#endif - } - - put_domain(d); - return 0; -} - -#if GRANT_DEBUG -static int -gnttab_dump_table(gnttab_dump_table_t *uop) -{ - grant_table_t *gt; - gnttab_dump_table_t op; - struct domain *d; - u32 shared_mfn; - active_grant_entry_t *act; - grant_entry_t sha_copy; - grant_mapping_t *maptrack; - int i; - - - if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) ) - { - DPRINTK("Fault while reading gnttab_dump_table_t.\n"); - return -EFAULT; - } - - if ( op.dom == DOMID_SELF ) - { - op.dom = current->domain->domain_id; - } - - if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) ) - { - DPRINTK("Bad domid %d.\n", op.dom); - (void)put_user(GNTST_bad_domain, &uop->status); - return 0; - } - - ASSERT(d->grant_table != NULL); - gt = d->grant_table; - (void)put_user(GNTST_okay, &uop->status); - - shared_mfn = virt_to_phys(d->grant_table->shared); - - DPRINTK("Grant table for dom (%hu) MFN (%x)\n", - op.dom, shared_mfn); - - ASSERT(d->grant_table->active != NULL); - ASSERT(d->grant_table->shared != NULL); - ASSERT(d->grant_table->maptrack != NULL); - - for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) - { - sha_copy = gt->shared[i]; - - if ( sha_copy.flags ) - { - DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) " - "dom:(%hu) frame:(%x)\n", - op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame); - } - } - - spin_lock(>->lock); - - for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) - { - act = >->active[i]; - - if ( act->pin ) - { - DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) " - "dom:(%hu) frame:(%lx)\n", - op.dom, i, act->pin, act->domid, act->frame); - } - } - - for ( i = 0; i < gt->maptrack_limit; i++ ) - { - maptrack = >->maptrack[i]; - - if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK ) - { - DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) " - "dom:(%hu)\n", - op.dom, i, - maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT, - maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK, - maptrack->domid); - } - } - - spin_unlock(>->lock); - - put_domain(d); - return 0; -} -#endif - -static long -gnttab_transfer(gnttab_transfer_t *uop, unsigned int count) -{ - struct domain *d = current->domain; - struct domain *e; - struct pfn_info *page; - u32 _d, _nd, x, y; - int i; - int result = GNTST_okay; - -#ifdef __ia64__ -//FIXME-IA64: not support for now? - return GNTST_general_error; -#else - for (i = 0; i < count; i++) { - gnttab_transfer_t *gop = &uop[i]; -#if GRANT_DEBUG - printk("gnttab_transfer: i=%d mfn=%lx domid=%d gref=%08x\n", - i, gop->mfn, gop->domid, gop->handle); -#endif - page = &frame_table[gop->mfn]; - - if (unlikely(IS_XEN_HEAP_FRAME(page))) { - printk("gnttab_transfer: xen heap frame mfn=%lx\n", - (unsigned long) gop->mfn); - gop->status = GNTST_bad_virt_addr; - continue; - } - if (unlikely(!pfn_valid(page_to_pfn(page)))) { - printk("gnttab_transfer: invalid pfn for mfn=%lx\n", - (unsigned long) gop->mfn); - gop->status = GNTST_bad_virt_addr; - continue; - } - if (unlikely((e = find_domain_by_id(gop->domid)) == NULL)) { - printk("gnttab_transfer: can't find domain %d\n", gop->domid); - gop->status = GNTST_bad_domain; - continue; - } - - spin_lock(&d->page_alloc_lock); - - /* - * The tricky bit: atomically release ownership while - * there is just one benign reference to the page - * (PGC_allocated). If that reference disappears then the - * deallocation routine will safely spin. - */ - _d = pickle_domptr(d); - _nd = page->u.inuse._domain; - y = page->count_info; - do { - x = y; - if (unlikely((x & (PGC_count_mask|PGC_allocated)) != - (1 | PGC_allocated)) || unlikely(_nd != _d)) { - printk("gnttab_transfer: Bad page values %p: ed=%p(%u), sd=%p," - " caf=%08x, taf=%" PRtype_info "\n", - (void *) page_to_pfn(page), - d, d->domain_id, unpickle_domptr(_nd), x, - page->u.inuse.type_info); - spin_unlock(&d->page_alloc_lock); - put_domain(e); - return 0; - } - __asm__ __volatile__( - LOCK_PREFIX "cmpxchg8b %2" - : "=d" (_nd), "=a" (y), - "=m" (*(volatile u64 *)(&page->count_info)) - : "0" (_d), "1" (x), "c" (NULL), "b" (x) ); - } while (unlikely(_nd != _d) || unlikely(y != x)); - - /* - * Unlink from 'd'. At least one reference remains (now - * anonymous), so noone else is spinning to try to delete - * this page from 'd'. - */ - d->tot_pages--; - list_del(&page->list); - - spin_unlock(&d->page_alloc_lock); - - spin_lock(&e->page_alloc_lock); - - /* - * Check that 'e' will accept the page and has reservation - * headroom. Also, a domain mustn't have PGC_allocated - * pages when it is dying. - */ -#ifdef GRANT_DEBUG - if (unlikely(e->tot_pages >= e->max_pages)) { - printk("gnttab_dontate: no headroom tot_pages=%d max_pages=%d\n", - e->tot_pages, e->max_pages); - spin_unlock(&e->page_alloc_lock); - put_domain(e); - result = GNTST_general_error; - break; - } - if (unlikely(test_bit(DOMFLAGS_DYING, &e->domain_flags))) { - printk("gnttab_transfer: target domain is dying\n"); - spin_unlock(&e->page_alloc_lock); - put_domain(e); - result = GNTST_general_error; - break; - } - if (unlikely(!gnttab_prepare_for_transfer(e, d, gop->ref))) { - printk("gnttab_transfer: gnttab_prepare_for_transfer fails\n"); - spin_unlock(&e->page_alloc_lock); - put_domain(e); - result = GNTST_general_error; - break; - } -#else - ASSERT(e->tot_pages <= e->max_pages); - if (unlikely(test_bit(DOMFLAGS_DYING, &e->domain_flags)) || - unlikely(e->tot_pages == e->max_pages) || - unlikely(!gnttab_prepare_for_transfer(e, d, gop->ref))) { - printk("gnttab_transfer: Transferee has no reservation headroom (%d," - "%d) or provided a bad grant ref (%08x) or is dying (%p)\n", - e->tot_pages, e->max_pages, gop->ref, e->d_flags); - spin_unlock(&e->page_alloc_lock); - put_domain(e); - result = GNTST_general_error; - break; - } -#endif - /* Okay, add the page to 'e'. */ - if (unlikely(e->tot_pages++ == 0)) { - get_knownalive_domain(e); - } - list_add_tail(&page->list, &e->page_list); - page_set_owner(page, e); - - spin_unlock(&e->page_alloc_lock); - - /* - * Transfer is all done: tell the guest about its new page - * frame. - */ - gnttab_notify_transfer(e, d, gop->ref, gop->mfn); - - put_domain(e); - - gop->status = GNTST_okay; - } - return result; -#endif -} - -long -do_grant_table_op( - unsigned int cmd, void *uop, unsigned int count) -{ - long rc; - struct domain *d = current->domain; - - if ( count > 512 ) - return -EINVAL; - - LOCK_BIGLOCK(d); - -#ifndef __ia64__ - sync_pagetable_state(d); -#endif - - rc = -EFAULT; - switch ( cmd ) - { - case GNTTABOP_map_grant_ref: - if ( unlikely(!array_access_ok( - uop, count, sizeof(gnttab_map_grant_ref_t))) ) - goto out; - rc = gnttab_map_grant_ref((gnttab_map_grant_ref_t *)uop, count); - break; - case GNTTABOP_unmap_grant_ref: - if ( unlikely(!array_access_ok( - uop, count, sizeof(gnttab_unmap_grant_ref_t))) ) - goto out; - rc = gnttab_unmap_grant_ref((gnttab_unmap_grant_ref_t *)uop, - count); - break; - case GNTTABOP_setup_table: - rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count); - break; -#if GRANT_DEBUG - case GNTTABOP_dump_table: - rc = gnttab_dump_table((gnttab_dump_table_t *)uop); - break; -#endif - case GNTTABOP_transfer: - if (unlikely(!array_access_ok(uop, count, - sizeof(gnttab_transfer_t)))) - goto out; - rc = gnttab_transfer(uop, count); - break; - default: - rc = -ENOSYS; - break; - } - - out: - UNLOCK_BIGLOCK(d); - - return rc; -} - -int -gnttab_prepare_for_transfer( - struct domain *rd, struct domain *ld, grant_ref_t ref) -{ - grant_table_t *rgt; - grant_entry_t *sha; - domid_t sdom; - u16 sflags; - u32 scombo, prev_scombo; - int retries = 0; - unsigned long target_pfn; - -#if GRANT_DEBUG_VERBOSE - DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n", - rd->domain_id, ld->domain_id, ref); -#endif - - if ( unlikely((rgt = rd->grant_table) == NULL) || - unlikely(ref >= NR_GRANT_ENTRIES) ) - { - DPRINTK("Dom %d has no g.t., or ref is bad (%d).\n", - rd->domain_id, ref); - return 0; - } - - spin_lock(&rgt->lock); - - sha = &rgt->shared[ref]; - - sflags = sha->flags; - sdom = sha->domid; - - for ( ; ; ) - { - target_pfn = sha->frame; - - if ( unlikely(target_pfn >= max_page ) ) - { - DPRINTK("Bad pfn (%lx)\n", target_pfn); - goto fail; - } - - if ( unlikely(sflags != GTF_accept_transfer) || - unlikely(sdom != ld->domain_id) ) - { - DPRINTK("Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", - sflags, sdom, ld->domain_id); - goto fail; - } - - /* Merge two 16-bit values into a 32-bit combined update. */ - /* NB. Endianness! */ - prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags; - - /* NB. prev_scombo is updated in place to seen value. */ - if ( unlikely(cmpxchg_user((u32 *)&sha->flags, prev_scombo, - prev_scombo | GTF_transfer_committed)) ) - { - DPRINTK("Fault while modifying shared flags and domid.\n"); - goto fail; - } - - /* Did the combined update work (did we see what we expected?). */ - if ( likely(prev_scombo == scombo) ) - break; - - if ( retries++ == 4 ) - { - DPRINTK("Shared grant entry is unstable.\n"); - goto fail; - } - - /* Didn't see what we expected. Split out the seen flags & dom. */ - /* NB. Endianness! */ - sflags = (u16)prev_scombo; - sdom = (u16)(prev_scombo >> 16); - } - - spin_unlock(&rgt->lock); - return 1; - - fail: - spin_unlock(&rgt->lock); - return 0; -} - -void -gnttab_notify_transfer( - struct domain *rd, struct domain *ld, grant_ref_t ref, unsigned long frame) -{ - grant_entry_t *sha; - unsigned long pfn; - -#if GRANT_DEBUG_VERBOSE - DPRINTK("gnttab_notify_transfer rd(%hu) ld(%hu) ref(%hu).\n", - rd->domain_id, ld->domain_id, ref); -#endif - - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - -#ifdef __ia64__ -// FIXME-ia64: any error checking need to be done here? -#else - pfn = sha->frame; - - if ( unlikely(pfn >= max_page ) ) - DPRINTK("Bad pfn (%lx)\n", pfn); - else - { - machine_to_phys_mapping[frame] = pfn; - - if ( unlikely(shadow_mode_log_dirty(ld))) - mark_dirty(ld, frame); - - if (shadow_mode_translate(ld)) - __phys_to_machine_mapping[pfn] = frame; - } -#endif - sha->frame = __mfn_to_gpfn(rd, frame); - sha->domid = rd->domain_id; - wmb(); - sha->flags = ( GTF_accept_transfer | GTF_transfer_completed ); - - spin_unlock(&rd->grant_table->lock); - - return; -} - -int -grant_table_create( - struct domain *d) -{ - grant_table_t *t; - int i; - - if ( (t = xmalloc(grant_table_t)) == NULL ) - goto no_mem; - - /* Simple stuff. */ - memset(t, 0, sizeof(*t)); - spin_lock_init(&t->lock); - - /* Active grant table. */ - if ( (t->active = xmalloc_array(active_grant_entry_t, NR_GRANT_ENTRIES)) - == NULL ) - goto no_mem; - memset(t->active, 0, sizeof(active_grant_entry_t) * NR_GRANT_ENTRIES); - - /* Tracking of mapped foreign frames table */ - if ( (t->maptrack = alloc_xenheap_page()) == NULL ) - goto no_mem; - t->maptrack_order = 0; - t->maptrack_limit = PAGE_SIZE / sizeof(grant_mapping_t); - memset(t->maptrack, 0, PAGE_SIZE); - for ( i = 0; i < t->maptrack_limit; i++ ) - t->maptrack[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT; - - /* Shared grant table. */ - t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES); - if ( t->shared == NULL ) - goto no_mem; - memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE); - -#ifdef __ia64__ -// I don't think there's anything to do here on ia64?... -#else - for ( i = 0; i < NR_GRANT_FRAMES; i++ ) - { - SHARE_PFN_WITH_DOMAIN( - virt_to_page((char *)(t->shared)+(i*PAGE_SIZE)), d); - machine_to_phys_mapping[(virt_to_phys(t->shared) >> PAGE_SHIFT) + i] = - INVALID_M2P_ENTRY; - } -#endif - - /* Okay, install the structure. */ - wmb(); /* avoid races with lock-free access to d->grant_table */ - d->grant_table = t; - return 0; - - no_mem: - if ( t != NULL ) - { - xfree(t->active); - free_xenheap_page(t->maptrack); - xfree(t); - } - return -ENOMEM; -} - -void -gnttab_release_mappings( - struct domain *ld) -{ - grant_table_t *gt = ld->grant_table; - grant_mapping_t *map; - domid_t dom; - grant_ref_t ref; - u16 handle; - struct domain *ld, *rd; - unsigned long frame; - active_grant_entry_t *act; - grant_entry_t *sha; - - for ( handle = 0; handle < gt->maptrack_limit; handle++ ) - { - map = >->maptrack[handle]; - - if ( map->ref_and_flags & GNTMAP_device_map ) - { - dom = map->domid; - ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT; - - DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n", - handle, ref, - map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom); - - if ( unlikely((rd = find_domain_by_id(dom)) == NULL) || - unlikely(ld == rd) ) - { - if ( rd != NULL ) - put_domain(rd); - - printk(KERN_WARNING "Grant release: No dom%d\n", dom); - continue; - } - - act = &rd->grant_table->active[ref]; - sha = &rd->grant_table->shared[ref]; - - spin_lock(&rd->grant_table->lock); - - if ( act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask) ) - { - frame = act->frame; - - if ( ( (act->pin & GNTPIN_hstw_mask) == 0 ) && - ( (act->pin & GNTPIN_devw_mask) > 0 ) ) - { - clear_bit(_GTF_writing, &sha->flags); - put_page_type(&frame_table[frame]); - } - - act->pin &= ~(GNTPIN_devw_mask | GNTPIN_devr_mask); - - if ( act->pin == 0 ) - { - clear_bit(_GTF_reading, &sha->flags); - map->ref_and_flags = 0; - put_page(&frame_table[frame]); - } - else - map->ref_and_flags &= ~GNTMAP_device_map; - } - - spin_unlock(&rd->grant_table->lock); - - put_domain(rd); - } - } -} - - -void -grant_table_destroy( - struct domain *d) -{ - grant_table_t *t; - - if ( (t = d->grant_table) != NULL ) - { - /* Free memory relating to this grant table. */ - d->grant_table = NULL; - free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES); - free_xenheap_page(t->maptrack); - xfree(t->active); - xfree(t); - } -} - -void -grant_table_init( - void) -{ - /* Nothing. */ -} - -/* - * Local variables: - * mode: C - * c-set-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |