[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Add a new type of grant copy operation.
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Node ID 247fc1245b217d33d299abfe88d10fa3ddb6a026 # Parent 4ee64035c0a3def8034ac3ed89b954eb985246a4 [XEN] Add a new type of grant copy operation. Based on an original patch from Rolf Neugebauer at Intel. Signed-off-by: Steven Smith <ssmith@xxxxxxxxxxxxx> Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- xen/common/grant_table.c | 221 +++++++++++++++++++++++++++++++++++++++ xen/include/public/grant_table.h | 47 ++++++++ 2 files changed, 267 insertions(+), 1 deletion(-) diff -r 4ee64035c0a3 -r 247fc1245b21 xen/common/grant_table.c --- a/xen/common/grant_table.c Thu Aug 10 11:36:27 2006 +0100 +++ b/xen/common/grant_table.c Thu Aug 10 11:54:15 2006 +0100 @@ -704,6 +704,218 @@ gnttab_transfer( return 0; } +/* Undo __acquire_grant_for_copy. Again, this has no effect on page + type and reference counts. */ +static void +__release_grant_for_copy( + struct domain *rd, unsigned long gref, int readonly) +{ + grant_entry_t *const sha = &rd->grant_table->shared[gref]; + struct active_grant_entry *const act = &rd->grant_table->active[gref]; + const unsigned long r_frame = act->frame; + + if ( !readonly ) + gnttab_log_dirty(rd, r_frame); + + spin_lock(&rd->grant_table->lock); + if ( readonly ) + act->pin -= GNTPIN_hstr_inc; + else + act->pin -= GNTPIN_hstw_inc; + + if ( !(act->pin & GNTPIN_hstw_mask) && !readonly ) + clear_bit(_GTF_writing, &sha->flags); + + if ( !act->pin ) + clear_bit(_GTF_reading, &sha->flags); + spin_unlock(&rd->grant_table->lock); +} + +/* Grab a frame number from a grant entry and update the flags and pin + count as appropriate. Note that this does *not* update the page + type or reference counts. */ +static int +__acquire_grant_for_copy( + struct domain *rd, unsigned long gref, int readonly, + unsigned long *frame) +{ + grant_entry_t *sha; + struct active_grant_entry *act; + s16 rc = GNTST_okay; + int retries = 0; + u16 sflags; + domid_t sdom; + + if ( unlikely(gref >= NR_GRANT_ENTRIES) ) + PIN_FAIL(error_out, GNTST_bad_gntref, + "Bad grant reference %ld\n", gref); + + act = &rd->grant_table->active[gref]; + sha = &rd->grant_table->shared[gref]; + + spin_lock(&rd->grant_table->lock); + + if ( !act->pin || + (!readonly && !(act->pin & GNTPIN_hstw_mask)) ) + { + sflags = sha->flags; + sdom = sha->domid; + + for ( ; ; ) + { + u32 scombo; + u32 prev_scombo; + u32 new_scombo; + + if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access || + sdom != current->domain->domain_id ) ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n", + sflags, sdom, current->domain->domain_id); + scombo = ((u32)sdom << 16) | (u32)sflags; + new_scombo = scombo | GTF_reading; + if ( !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"); + } + prev_scombo = cmpxchg((u32 *)&sha->flags, scombo, new_scombo); + if ( likely(prev_scombo == scombo) ) + break; + + if ( retries++ == 4 ) + PIN_FAIL(unlock_out, GNTST_general_error, + "Shared grant entry is unstable.\n"); + sflags = (u16)prev_scombo; + sdom = (u16)(prev_scombo >> 16); + } + + if ( !act->pin ) + { + act->domid = sdom; + act->frame = gmfn_to_mfn(rd, sha->frame); + } + } + else if ( (act->pin & 0x80808080U) != 0 ) + PIN_FAIL(unlock_out, ENOSPC, + "Risk of counter overflow %08x\n", act->pin); + + act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc; + + *frame = act->frame; + + unlock_out: + spin_unlock(&rd->grant_table->lock); + error_out: + return rc; +} + +static void +__gnttab_copy( + struct gnttab_copy *op) +{ + struct domain *sd = NULL, *dd = NULL; + unsigned long s_frame, d_frame; + void *sp, *dp; + s16 rc = GNTST_okay; + int have_d_grant = 0, have_s_grant = 0; + + if ( ((op->source.offset + op->len) > PAGE_SIZE) || + ((op->dest.offset + op->len) > PAGE_SIZE) ) + PIN_FAIL(error_out, GNTST_bad_copy_arg, "copy beyond page area.\n"); + + if ( op->source.domid == DOMID_SELF ) + { + sd = current->domain; + get_knownalive_domain(sd); + } + else if ( (sd = find_domain_by_id(op->source.domid)) == NULL ) + { + PIN_FAIL(error_out, GNTST_bad_domain, + "couldn't find %d\n", op->source.domid); + } + + if ( op->dest.domid == DOMID_SELF ) + { + dd = current->domain; + get_knownalive_domain(dd); + } + else if ( (dd = find_domain_by_id(op->dest.domid)) == NULL ) + { + PIN_FAIL(error_out, GNTST_bad_domain, + "couldn't find %d\n", op->dest.domid); + } + + if ( op->flags & GNTCOPY_source_gref ) + { + rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame); + if ( rc != GNTST_okay ) + goto error_out; + have_s_grant = 1; + } + else + { + s_frame = gmfn_to_mfn(sd, op->source.u.gmfn); + } + if ( !get_page(mfn_to_page(s_frame), sd) ) + PIN_FAIL(error_out, GNTST_general_error, + "could not get source frame %lx.\n", s_frame); + + if ( op->flags & GNTCOPY_dest_gref ) + { + rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame); + if ( rc != GNTST_okay ) + goto error_out; + have_d_grant = 1; + } + else + { + d_frame = gmfn_to_mfn(sd, op->dest.u.gmfn); + } + if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) ) + PIN_FAIL(error_out, GNTST_general_error, + "could not get source frame %lx.\n", d_frame); + + sp = map_domain_page(s_frame); + dp = map_domain_page(d_frame); + + memcpy(dp + op->dest.offset, sp + op->source.offset, op->len); + + unmap_domain_page(dp); + unmap_domain_page(sp); + + error_out: + if ( have_s_grant ) + __release_grant_for_copy(sd, op->source.u.ref, 1); + if ( have_d_grant ) + __release_grant_for_copy(dd, op->dest.u.ref, 0); + if ( sd ) + put_domain(sd); + if ( dd ) + put_domain(dd); + op->status = rc; +} + +static long +gnttab_copy( + XEN_GUEST_HANDLE(gnttab_copy_t) uop, unsigned int count) +{ + int i; + struct gnttab_copy op; + + for ( i = 0; i < count; i++ ) + { + if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) ) + return -EFAULT; + __gnttab_copy(&op); + if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) ) + return -EFAULT; + } + return 0; +} + long do_grant_table_op( unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count) @@ -754,6 +966,15 @@ do_grant_table_op( rc = gnttab_transfer(transfer, count); break; } + case GNTTABOP_copy: + { + XEN_GUEST_HANDLE(gnttab_copy_t) copy = + guest_handle_cast(uop, gnttab_copy_t); + if ( unlikely(!guest_handle_okay(copy, count)) ) + goto out; + rc = gnttab_copy(copy, count); + break; + } default: rc = -ENOSYS; break; diff -r 4ee64035c0a3 -r 247fc1245b21 xen/include/public/grant_table.h --- a/xen/include/public/grant_table.h Thu Aug 10 11:36:27 2006 +0100 +++ b/xen/include/public/grant_table.h Thu Aug 10 11:54:15 2006 +0100 @@ -248,6 +248,49 @@ struct gnttab_transfer { }; typedef struct gnttab_transfer gnttab_transfer_t; DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t); + + +/* + * GNTTABOP_copy: Hypervisor based copy + * source and destinations can be eithers MFNs or, for foreign domains, + * grant references. the foreign domain has to grant read/write access + * in its grant table. + * + * The flags specify what type source and destinations are (either MFN + * or grant reference). + * + * Note that this can also be used to copy data between two domains + * via a third party if the source and destination domains had previously + * grant appropriate access to their pages to the third party. + * + * source_offset specifies an offset in the source frame, dest_offset + * the offset in the target frame and len specifies the number of + * bytes to be copied. + */ + +#define _GNTCOPY_source_gref (0) +#define GNTCOPY_source_gref (1<<_GNTCOPY_source_gref) +#define _GNTCOPY_dest_gref (1) +#define GNTCOPY_dest_gref (1<<_GNTCOPY_dest_gref) + +#define GNTTABOP_copy 5 +typedef struct gnttab_copy { + /* IN parameters. */ + struct { + union { + grant_ref_t ref; + xen_pfn_t gmfn; + } u; + domid_t domid; + uint16_t offset; + } source, dest; + uint16_t len; + uint16_t flags; /* GNTCOPY_* */ + /* OUT parameters. */ + int16_t status; +} gnttab_copy_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t); + /* * Bitfield values for update_pin_status.flags. @@ -290,6 +333,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_ #define GNTST_no_device_space (-7) /* Out of space in I/O MMU. */ #define GNTST_permission_denied (-8) /* Not enough privilege for operation. */ #define GNTST_bad_page (-9) /* Specified page was invalid for op. */ +#define GNTST_bad_copy_arg (-10) /* copy arguments cross page boundary */ #define GNTTABOP_error_msgs { \ "okay", \ @@ -301,7 +345,8 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_ "invalid device address", \ "no spare translation slot in the I/O MMU", \ "permission denied", \ - "bad page" \ + "bad page", \ + "copy arguments cross page boundary" \ } #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |