ia64/xen-unstable

changeset 11079:247fc1245b21

[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@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Aug 10 11:54:15 2006 +0100 (2006-08-10)
parents 4ee64035c0a3
children 8cca42e2610a
files xen/common/grant_table.c xen/include/public/grant_table.h
line diff
     1.1 --- a/xen/common/grant_table.c	Thu Aug 10 11:36:27 2006 +0100
     1.2 +++ b/xen/common/grant_table.c	Thu Aug 10 11:54:15 2006 +0100
     1.3 @@ -704,6 +704,218 @@ gnttab_transfer(
     1.4      return 0;
     1.5  }
     1.6  
     1.7 +/* Undo __acquire_grant_for_copy.  Again, this has no effect on page
     1.8 +   type and reference counts. */
     1.9 +static void
    1.10 +__release_grant_for_copy(
    1.11 +    struct domain *rd, unsigned long gref, int readonly)
    1.12 +{
    1.13 +    grant_entry_t *const sha = &rd->grant_table->shared[gref];
    1.14 +    struct active_grant_entry *const act = &rd->grant_table->active[gref];
    1.15 +    const unsigned long r_frame = act->frame;
    1.16 +
    1.17 +    if ( !readonly )
    1.18 +        gnttab_log_dirty(rd, r_frame);
    1.19 +
    1.20 +    spin_lock(&rd->grant_table->lock);
    1.21 +    if ( readonly )
    1.22 +        act->pin -= GNTPIN_hstr_inc;
    1.23 +    else
    1.24 +        act->pin -= GNTPIN_hstw_inc;
    1.25 +
    1.26 +    if ( !(act->pin & GNTPIN_hstw_mask) && !readonly )
    1.27 +        clear_bit(_GTF_writing, &sha->flags);
    1.28 +
    1.29 +    if ( !act->pin )
    1.30 +        clear_bit(_GTF_reading, &sha->flags);
    1.31 +    spin_unlock(&rd->grant_table->lock);
    1.32 +}
    1.33 +
    1.34 +/* Grab a frame number from a grant entry and update the flags and pin
    1.35 +   count as appropriate.  Note that this does *not* update the page
    1.36 +   type or reference counts. */
    1.37 +static int
    1.38 +__acquire_grant_for_copy(
    1.39 +    struct domain *rd, unsigned long gref, int readonly,
    1.40 +    unsigned long *frame)
    1.41 +{
    1.42 +    grant_entry_t *sha;
    1.43 +    struct active_grant_entry *act;
    1.44 +    s16 rc = GNTST_okay;
    1.45 +    int retries = 0;
    1.46 +    u16 sflags;
    1.47 +    domid_t sdom;
    1.48 +
    1.49 +    if ( unlikely(gref >= NR_GRANT_ENTRIES) )
    1.50 +        PIN_FAIL(error_out, GNTST_bad_gntref,
    1.51 +                 "Bad grant reference %ld\n", gref);
    1.52 +    
    1.53 +    act = &rd->grant_table->active[gref];
    1.54 +    sha = &rd->grant_table->shared[gref];
    1.55 +
    1.56 +    spin_lock(&rd->grant_table->lock);
    1.57 +    
    1.58 +    if ( !act->pin ||
    1.59 +         (!readonly && !(act->pin & GNTPIN_hstw_mask)) )
    1.60 +    {
    1.61 +        sflags = sha->flags;
    1.62 +        sdom = sha->domid;
    1.63 +
    1.64 +        for ( ; ; )
    1.65 +        {
    1.66 +            u32 scombo;
    1.67 +            u32 prev_scombo;
    1.68 +            u32 new_scombo;
    1.69 +
    1.70 +            if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access ||
    1.71 +                          sdom != current->domain->domain_id ) )
    1.72 +                PIN_FAIL(unlock_out, GNTST_general_error,
    1.73 +                         "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
    1.74 +                         sflags, sdom, current->domain->domain_id);
    1.75 +            scombo = ((u32)sdom << 16) | (u32)sflags;
    1.76 +            new_scombo = scombo | GTF_reading;
    1.77 +            if ( !readonly )
    1.78 +            {
    1.79 +                new_scombo |= GTF_writing;
    1.80 +                if ( unlikely(sflags & GTF_readonly) )
    1.81 +                    PIN_FAIL(unlock_out, GNTST_general_error,
    1.82 +                             "Attempt to write-pin a r/o grant entry.\n");
    1.83 +            }
    1.84 +            prev_scombo = cmpxchg((u32 *)&sha->flags, scombo, new_scombo);
    1.85 +            if ( likely(prev_scombo == scombo) )
    1.86 +                break;
    1.87 +
    1.88 +            if ( retries++ == 4 )
    1.89 +                PIN_FAIL(unlock_out, GNTST_general_error,
    1.90 +                         "Shared grant entry is unstable.\n");
    1.91 +            sflags = (u16)prev_scombo;
    1.92 +            sdom = (u16)(prev_scombo >> 16);
    1.93 +        }
    1.94 +
    1.95 +        if ( !act->pin )
    1.96 +        {
    1.97 +            act->domid = sdom;
    1.98 +            act->frame = gmfn_to_mfn(rd, sha->frame);
    1.99 +        }
   1.100 +    }
   1.101 +    else if ( (act->pin & 0x80808080U) != 0 )
   1.102 +        PIN_FAIL(unlock_out, ENOSPC,
   1.103 +                 "Risk of counter overflow %08x\n", act->pin);
   1.104 +
   1.105 +    act->pin += readonly ? GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   1.106 +
   1.107 +    *frame = act->frame;
   1.108 +
   1.109 + unlock_out:
   1.110 +    spin_unlock(&rd->grant_table->lock);
   1.111 + error_out:
   1.112 +    return rc;
   1.113 +}
   1.114 +
   1.115 +static void
   1.116 +__gnttab_copy(
   1.117 +    struct gnttab_copy *op)
   1.118 +{
   1.119 +    struct domain *sd = NULL, *dd = NULL;
   1.120 +    unsigned long s_frame, d_frame;
   1.121 +    void *sp, *dp;
   1.122 +    s16 rc = GNTST_okay;
   1.123 +    int have_d_grant = 0, have_s_grant = 0;
   1.124 +
   1.125 +    if ( ((op->source.offset + op->len) > PAGE_SIZE) ||
   1.126 +         ((op->dest.offset + op->len) > PAGE_SIZE) )
   1.127 +        PIN_FAIL(error_out, GNTST_bad_copy_arg, "copy beyond page area.\n");
   1.128 +
   1.129 +    if ( op->source.domid == DOMID_SELF )
   1.130 +    {
   1.131 +        sd = current->domain;
   1.132 +        get_knownalive_domain(sd);
   1.133 +    }
   1.134 +    else if ( (sd = find_domain_by_id(op->source.domid)) == NULL )
   1.135 +    {
   1.136 +        PIN_FAIL(error_out, GNTST_bad_domain,
   1.137 +                 "couldn't find %d\n", op->source.domid);
   1.138 +    }
   1.139 +
   1.140 +    if ( op->dest.domid == DOMID_SELF )
   1.141 +    {
   1.142 +        dd = current->domain;
   1.143 +        get_knownalive_domain(dd);
   1.144 +    }
   1.145 +    else if ( (dd = find_domain_by_id(op->dest.domid)) == NULL )
   1.146 +    {
   1.147 +        PIN_FAIL(error_out, GNTST_bad_domain,
   1.148 +                 "couldn't find %d\n", op->dest.domid);
   1.149 +    }
   1.150 +
   1.151 +    if ( op->flags & GNTCOPY_source_gref )
   1.152 +    {
   1.153 +        rc = __acquire_grant_for_copy(sd, op->source.u.ref, 1, &s_frame);
   1.154 +        if ( rc != GNTST_okay )
   1.155 +            goto error_out;
   1.156 +        have_s_grant = 1;
   1.157 +    }
   1.158 +    else
   1.159 +    {
   1.160 +        s_frame = gmfn_to_mfn(sd, op->source.u.gmfn);
   1.161 +    }
   1.162 +    if ( !get_page(mfn_to_page(s_frame), sd) )
   1.163 +        PIN_FAIL(error_out, GNTST_general_error,
   1.164 +                 "could not get source frame %lx.\n", s_frame);
   1.165 +
   1.166 +    if ( op->flags & GNTCOPY_dest_gref )
   1.167 +    {
   1.168 +        rc = __acquire_grant_for_copy(dd, op->dest.u.ref, 0, &d_frame);
   1.169 +        if ( rc != GNTST_okay )
   1.170 +            goto error_out;
   1.171 +        have_d_grant = 1;
   1.172 +    }
   1.173 +    else
   1.174 +    {
   1.175 +        d_frame = gmfn_to_mfn(sd, op->dest.u.gmfn);
   1.176 +    }
   1.177 +    if ( !get_page_and_type(mfn_to_page(d_frame), dd, PGT_writable_page) )
   1.178 +        PIN_FAIL(error_out, GNTST_general_error,
   1.179 +                 "could not get source frame %lx.\n", d_frame);
   1.180 +
   1.181 +    sp = map_domain_page(s_frame);
   1.182 +    dp = map_domain_page(d_frame);
   1.183 +
   1.184 +    memcpy(dp + op->dest.offset, sp + op->source.offset, op->len);
   1.185 +
   1.186 +    unmap_domain_page(dp);
   1.187 +    unmap_domain_page(sp);
   1.188 +
   1.189 + error_out:
   1.190 +    if ( have_s_grant )
   1.191 +        __release_grant_for_copy(sd, op->source.u.ref, 1);
   1.192 +    if ( have_d_grant )
   1.193 +        __release_grant_for_copy(dd, op->dest.u.ref, 0);
   1.194 +    if ( sd )
   1.195 +        put_domain(sd);
   1.196 +    if ( dd )
   1.197 +        put_domain(dd);
   1.198 +    op->status = rc;
   1.199 +}
   1.200 +
   1.201 +static long
   1.202 +gnttab_copy(
   1.203 +    XEN_GUEST_HANDLE(gnttab_copy_t) uop, unsigned int count)
   1.204 +{
   1.205 +    int i;
   1.206 +    struct gnttab_copy op;
   1.207 +
   1.208 +    for ( i = 0; i < count; i++ )
   1.209 +    {
   1.210 +        if ( unlikely(__copy_from_guest_offset(&op, uop, i, 1)) )
   1.211 +            return -EFAULT;
   1.212 +        __gnttab_copy(&op);
   1.213 +        if ( unlikely(__copy_to_guest_offset(uop, i, &op, 1)) )
   1.214 +            return -EFAULT;
   1.215 +    }
   1.216 +    return 0;
   1.217 +}
   1.218 +
   1.219  long
   1.220  do_grant_table_op(
   1.221      unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count)
   1.222 @@ -754,6 +966,15 @@ do_grant_table_op(
   1.223          rc = gnttab_transfer(transfer, count);
   1.224          break;
   1.225      }
   1.226 +    case GNTTABOP_copy:
   1.227 +    {
   1.228 +        XEN_GUEST_HANDLE(gnttab_copy_t) copy =
   1.229 +            guest_handle_cast(uop, gnttab_copy_t);
   1.230 +        if ( unlikely(!guest_handle_okay(copy, count)) )
   1.231 +            goto out;
   1.232 +        rc = gnttab_copy(copy, count);
   1.233 +        break;
   1.234 +    }
   1.235      default:
   1.236          rc = -ENOSYS;
   1.237          break;
     2.1 --- a/xen/include/public/grant_table.h	Thu Aug 10 11:36:27 2006 +0100
     2.2 +++ b/xen/include/public/grant_table.h	Thu Aug 10 11:54:15 2006 +0100
     2.3 @@ -249,6 +249,49 @@ struct gnttab_transfer {
     2.4  typedef struct gnttab_transfer gnttab_transfer_t;
     2.5  DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_t);
     2.6  
     2.7 +
     2.8 +/*
     2.9 + * GNTTABOP_copy: Hypervisor based copy
    2.10 + * source and destinations can be eithers MFNs or, for foreign domains,
    2.11 + * grant references. the foreign domain has to grant read/write access
    2.12 + * in its grant table.
    2.13 + *
    2.14 + * The flags specify what type source and destinations are (either MFN
    2.15 + * or grant reference).
    2.16 + *
    2.17 + * Note that this can also be used to copy data between two domains
    2.18 + * via a third party if the source and destination domains had previously
    2.19 + * grant appropriate access to their pages to the third party.
    2.20 + *
    2.21 + * source_offset specifies an offset in the source frame, dest_offset
    2.22 + * the offset in the target frame and  len specifies the number of
    2.23 + * bytes to be copied.
    2.24 + */
    2.25 +
    2.26 +#define _GNTCOPY_source_gref      (0)
    2.27 +#define GNTCOPY_source_gref       (1<<_GNTCOPY_source_gref)
    2.28 +#define _GNTCOPY_dest_gref        (1)
    2.29 +#define GNTCOPY_dest_gref         (1<<_GNTCOPY_dest_gref)
    2.30 +
    2.31 +#define GNTTABOP_copy                 5
    2.32 +typedef struct gnttab_copy {
    2.33 +    /* IN parameters. */
    2.34 +    struct {
    2.35 +        union {
    2.36 +            grant_ref_t ref;
    2.37 +            xen_pfn_t   gmfn;
    2.38 +        } u;
    2.39 +        domid_t  domid;
    2.40 +        uint16_t offset;
    2.41 +    } source, dest;
    2.42 +    uint16_t      len;
    2.43 +    uint16_t      flags;          /* GNTCOPY_* */
    2.44 +    /* OUT parameters. */
    2.45 +    int16_t       status;
    2.46 +} gnttab_copy_t;
    2.47 +DEFINE_XEN_GUEST_HANDLE(gnttab_copy_t);
    2.48 +
    2.49 +
    2.50  /*
    2.51   * Bitfield values for update_pin_status.flags.
    2.52   */
    2.53 @@ -290,6 +333,7 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_
    2.54  #define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
    2.55  #define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
    2.56  #define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
    2.57 +#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
    2.58  
    2.59  #define GNTTABOP_error_msgs {                   \
    2.60      "okay",                                     \
    2.61 @@ -301,7 +345,8 @@ DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_
    2.62      "invalid device address",                   \
    2.63      "no spare translation slot in the I/O MMU", \
    2.64      "permission denied",                        \
    2.65 -    "bad page"                                  \
    2.66 +    "bad page",                                 \
    2.67 +    "copy arguments cross page boundary"        \
    2.68  }
    2.69  
    2.70  #endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */