direct-io.hg

changeset 5495:bb1b5a578752

bitkeeper revision 1.1713.2.8 (42b33f1feaANIdB6dfv8W846UquAHA)

Add preliminary grant table support (in arch/ia64 and turned
off for CONFIG_VTI for now)
author djm@kirby.fc.hp.com
date Fri Jun 17 21:22:39 2005 +0000 (2005-06-17)
parents 9ae40d2e6c1d
children ef4d0fa7f7c0
files .rootkeys xen/arch/ia64/Makefile xen/arch/ia64/grant_table.c xen/arch/ia64/hypercall.c xen/arch/ia64/xenmisc.c xen/include/asm-ia64/mm.h
line diff
     1.1 --- a/.rootkeys	Fri Jun 17 18:28:39 2005 +0000
     1.2 +++ b/.rootkeys	Fri Jun 17 21:22:39 2005 +0000
     1.3 @@ -1102,6 +1102,7 @@ 421098b26C_0yoypoHqjDcJA9UrG_g xen/arch/
     1.4  421098b2PHgzf_Gg4R65YRNi_QzMKQ xen/arch/ia64/dom0_ops.c
     1.5  421098b2O7jsNfzQXA1v3rbAc1QhpA xen/arch/ia64/dom_fw.c
     1.6  421098b2ZlaBcyiuuPr3WpzaSDwg6Q xen/arch/ia64/domain.c
     1.7 +42b33bb9GLR-tzcaHalk8fz9cgK0aA xen/arch/ia64/grant_table.c
     1.8  42a08294zRikvZk_CR1iVojHjcVFZw xen/arch/ia64/hpsimserial.c
     1.9  4239e98a_HX-FCIcXtVqY0BbrDqVug xen/arch/ia64/hypercall.c
    1.10  4295e18f42gf1T-8W97A3KSlBaY1tA xen/arch/ia64/hyperprivop.S
     2.1 --- a/xen/arch/ia64/Makefile	Fri Jun 17 18:28:39 2005 +0000
     2.2 +++ b/xen/arch/ia64/Makefile	Fri Jun 17 21:22:39 2005 +0000
     2.3 @@ -10,7 +10,7 @@ OBJS = xensetup.o setup.o time.o irq.o i
     2.4  	extable.o linuxextable.o xenirq.o xentime.o \
     2.5  	regionreg.o entry.o unaligned.o privop.o vcpu.o \
     2.6  	irq_ia64.o irq_lsapic.o vhpt.o xenasm.o hyperprivop.o dom_fw.o \
     2.7 -	sn_console.o
     2.8 +	grant_table.o sn_console.o
     2.9  
    2.10  ifeq ($(CONFIG_VTI),y)
    2.11  OBJS += vmx_init.o vmx_virt.o vmx_vcpu.o vmx_process.o vmx_vsa.o vmx_ivt.o \
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/xen/arch/ia64/grant_table.c	Fri Jun 17 21:22:39 2005 +0000
     3.3 @@ -0,0 +1,1294 @@
     3.4 +#ifndef CONFIG_VTI
     3.5 +// temporarily in arch/ia64 until can merge into common/grant_table.c
     3.6 +/******************************************************************************
     3.7 + * common/grant_table.c
     3.8 + * 
     3.9 + * Mechanism for granting foreign access to page frames, and receiving
    3.10 + * page-ownership transfers.
    3.11 + * 
    3.12 + * Copyright (c) 2005 Christopher Clark
    3.13 + * Copyright (c) 2004 K A Fraser
    3.14 + * 
    3.15 + * This program is free software; you can redistribute it and/or modify
    3.16 + * it under the terms of the GNU General Public License as published by
    3.17 + * the Free Software Foundation; either version 2 of the License, or
    3.18 + * (at your option) any later version.
    3.19 + * 
    3.20 + * This program is distributed in the hope that it will be useful,
    3.21 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.22 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.23 + * GNU General Public License for more details.
    3.24 + * 
    3.25 + * You should have received a copy of the GNU General Public License
    3.26 + * along with this program; if not, write to the Free Software
    3.27 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    3.28 + */
    3.29 +
    3.30 +#define GRANT_DEBUG 0
    3.31 +#define GRANT_DEBUG_VERBOSE 0
    3.32 +
    3.33 +#include <xen/config.h>
    3.34 +#include <xen/lib.h>
    3.35 +#include <xen/sched.h>
    3.36 +#include <xen/shadow.h>
    3.37 +#include <xen/mm.h>
    3.38 +#ifdef __ia64__
    3.39 +#define __addr_ok(a) 1	// FIXME-ia64: a variant of access_ok??
    3.40 +// FIXME-ia64: need to implement real cmpxchg_user on ia64
    3.41 +#define cmpxchg_user(_p,_o,_n) ((*_p == _o) ? ((*_p = _n), 0) : ((_o = *_p), 0))
    3.42 +// FIXME-ia64: the following are meaningless on ia64? move to some header file
    3.43 +#define put_page(x) do { } while (0)
    3.44 +#define put_page_type(x) do { } while (0)
    3.45 +// FIXME-ia64: these belong in an asm/grant_table.h... PAGE_SIZE different
    3.46 +#undef ORDER_GRANT_FRAMES
    3.47 +//#undef NUM_GRANT_FRAMES
    3.48 +#define ORDER_GRANT_FRAMES 0
    3.49 +//#define NUM_GRANT_FRAMES  (1U << ORDER_GRANT_FRAMES)
    3.50 +#endif
    3.51 +
    3.52 +#define PIN_FAIL(_lbl, _rc, _f, _a...)   \
    3.53 +    do {                           \
    3.54 +        DPRINTK( _f, ## _a );      \
    3.55 +        rc = (_rc);                \
    3.56 +        goto _lbl;                 \
    3.57 +    } while ( 0 )
    3.58 +
    3.59 +static inline int
    3.60 +get_maptrack_handle(
    3.61 +    grant_table_t *t)
    3.62 +{
    3.63 +    unsigned int h;
    3.64 +    if ( unlikely((h = t->maptrack_head) == t->maptrack_limit) )
    3.65 +        return -1;
    3.66 +    t->maptrack_head = t->maptrack[h].ref_and_flags >> MAPTRACK_REF_SHIFT;
    3.67 +    t->map_count++;
    3.68 +    return h;
    3.69 +}
    3.70 +
    3.71 +static inline void
    3.72 +put_maptrack_handle(
    3.73 +    grant_table_t *t, int handle)
    3.74 +{
    3.75 +    t->maptrack[handle].ref_and_flags = t->maptrack_head << MAPTRACK_REF_SHIFT;
    3.76 +    t->maptrack_head = handle;
    3.77 +    t->map_count--;
    3.78 +}
    3.79 +
    3.80 +static int
    3.81 +__gnttab_activate_grant_ref(
    3.82 +    struct domain          *mapping_d,          /* IN */
    3.83 +    struct vcpu     *mapping_ed,
    3.84 +    struct domain          *granting_d,
    3.85 +    grant_ref_t             ref,
    3.86 +    u16                     dev_hst_ro_flags,
    3.87 +    unsigned long           host_virt_addr,
    3.88 +    unsigned long          *pframe )            /* OUT */
    3.89 +{
    3.90 +    domid_t               sdom;
    3.91 +    u16                   sflags;
    3.92 +    active_grant_entry_t *act;
    3.93 +    grant_entry_t        *sha;
    3.94 +    s16                   rc = 1;
    3.95 +    unsigned long         frame = 0;
    3.96 +    int                   retries = 0;
    3.97 +
    3.98 +    /*
    3.99 +     * Objectives of this function:
   3.100 +     * . Make the record ( granting_d, ref ) active, if not already.
   3.101 +     * . Update shared grant entry of owner, indicating frame is mapped.
   3.102 +     * . Increment the owner act->pin reference counts.
   3.103 +     * . get_page on shared frame if new mapping.
   3.104 +     * . get_page_type if this is first RW mapping of frame.
   3.105 +     * . Add PTE to virtual address space of mapping_d, if necessary.
   3.106 +     * Returns:
   3.107 +     * .  -ve: error
   3.108 +     * .    1: ok
   3.109 +     * .    0: ok and TLB invalidate of host_virt_addr needed.
   3.110 +     *
   3.111 +     * On success, *pframe contains mfn.
   3.112 +     */
   3.113 +
   3.114 +    /*
   3.115 +     * We bound the number of times we retry CMPXCHG on memory locations that
   3.116 +     * we share with a guest OS. The reason is that the guest can modify that
   3.117 +     * location at a higher rate than we can read-modify-CMPXCHG, so the guest
   3.118 +     * could cause us to livelock. There are a few cases where it is valid for
   3.119 +     * the guest to race our updates (e.g., to change the GTF_readonly flag),
   3.120 +     * so we allow a few retries before failing.
   3.121 +     */
   3.122 +
   3.123 +    act = &granting_d->grant_table->active[ref];
   3.124 +    sha = &granting_d->grant_table->shared[ref];
   3.125 +
   3.126 +    spin_lock(&granting_d->grant_table->lock);
   3.127 +
   3.128 +    if ( act->pin == 0 )
   3.129 +    {
   3.130 +        /* CASE 1: Activating a previously inactive entry. */
   3.131 +
   3.132 +        sflags = sha->flags;
   3.133 +        sdom   = sha->domid;
   3.134 +
   3.135 +        for ( ; ; )
   3.136 +        {
   3.137 +            u32 scombo, prev_scombo, new_scombo;
   3.138 +
   3.139 +            if ( unlikely((sflags & GTF_type_mask) != GTF_permit_access) ||
   3.140 +                 unlikely(sdom != mapping_d->domain_id) )
   3.141 +                PIN_FAIL(unlock_out, GNTST_general_error,
   3.142 +                         "Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
   3.143 +                        sflags, sdom, mapping_d->domain_id);
   3.144 +
   3.145 +            /* Merge two 16-bit values into a 32-bit combined update. */
   3.146 +            /* NB. Endianness! */
   3.147 +            prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags;
   3.148 +
   3.149 +            new_scombo = scombo | GTF_reading;
   3.150 +            if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
   3.151 +            {
   3.152 +                new_scombo |= GTF_writing;
   3.153 +                if ( unlikely(sflags & GTF_readonly) )
   3.154 +                    PIN_FAIL(unlock_out, GNTST_general_error,
   3.155 +                             "Attempt to write-pin a r/o grant entry.\n");
   3.156 +            }
   3.157 +
   3.158 +            /* NB. prev_scombo is updated in place to seen value. */
   3.159 +            if ( unlikely(cmpxchg_user((u32 *)&sha->flags,
   3.160 +                                       prev_scombo,
   3.161 +                                       new_scombo)) )
   3.162 +                PIN_FAIL(unlock_out, GNTST_general_error,
   3.163 +                         "Fault while modifying shared flags and domid.\n");
   3.164 +
   3.165 +            /* Did the combined update work (did we see what we expected?). */
   3.166 +            if ( likely(prev_scombo == scombo) )
   3.167 +                break;
   3.168 +
   3.169 +            if ( retries++ == 4 )
   3.170 +                PIN_FAIL(unlock_out, GNTST_general_error,
   3.171 +                         "Shared grant entry is unstable.\n");
   3.172 +
   3.173 +            /* Didn't see what we expected. Split out the seen flags & dom. */
   3.174 +            /* NB. Endianness! */
   3.175 +            sflags = (u16)prev_scombo;
   3.176 +            sdom   = (u16)(prev_scombo >> 16);
   3.177 +        }
   3.178 +
   3.179 +        /* rmb(); */ /* not on x86 */
   3.180 +
   3.181 +        frame = __gpfn_to_mfn_foreign(granting_d, sha->frame);
   3.182 +
   3.183 +#ifdef __ia64__
   3.184 +// FIXME-ia64: any error checking need to be done here?
   3.185 +#else
   3.186 +        if ( unlikely(!pfn_valid(frame)) ||
   3.187 +             unlikely(!((dev_hst_ro_flags & GNTMAP_readonly) ?
   3.188 +                        get_page(&frame_table[frame], granting_d) :
   3.189 +                        get_page_and_type(&frame_table[frame], granting_d,
   3.190 +                                          PGT_writable_page))) )
   3.191 +        {
   3.192 +            clear_bit(_GTF_writing, &sha->flags);
   3.193 +            clear_bit(_GTF_reading, &sha->flags);
   3.194 +            PIN_FAIL(unlock_out, GNTST_general_error,
   3.195 +                     "Could not pin the granted frame (%lx)!\n", frame);
   3.196 +        }
   3.197 +#endif
   3.198 +
   3.199 +        if ( dev_hst_ro_flags & GNTMAP_device_map )
   3.200 +            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   3.201 +                GNTPIN_devr_inc : GNTPIN_devw_inc;
   3.202 +        if ( dev_hst_ro_flags & GNTMAP_host_map )
   3.203 +            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   3.204 +                GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   3.205 +        act->domid = sdom;
   3.206 +        act->frame = frame;
   3.207 +    }
   3.208 +    else 
   3.209 +    {
   3.210 +        /* CASE 2: Active modications to an already active entry. */
   3.211 +
   3.212 +        /*
   3.213 +         * A cheesy check for possible pin-count overflow.
   3.214 +         * A more accurate check cannot be done with a single comparison.
   3.215 +         */
   3.216 +        if ( (act->pin & 0x80808080U) != 0 )
   3.217 +            PIN_FAIL(unlock_out, ENOSPC,
   3.218 +                     "Risk of counter overflow %08x\n", act->pin);
   3.219 +
   3.220 +        frame = act->frame;
   3.221 +
   3.222 +        if ( !(dev_hst_ro_flags & GNTMAP_readonly) && 
   3.223 +             !((sflags = sha->flags) & GTF_writing) )
   3.224 +        {
   3.225 +            for ( ; ; )
   3.226 +            {
   3.227 +                u16 prev_sflags;
   3.228 +                
   3.229 +                if ( unlikely(sflags & GTF_readonly) )
   3.230 +                    PIN_FAIL(unlock_out, GNTST_general_error,
   3.231 +                             "Attempt to write-pin a r/o grant entry.\n");
   3.232 +
   3.233 +                prev_sflags = sflags;
   3.234 +
   3.235 +                /* NB. prev_sflags is updated in place to seen value. */
   3.236 +                if ( unlikely(cmpxchg_user(&sha->flags, prev_sflags, 
   3.237 +                                           prev_sflags | GTF_writing)) )
   3.238 +                    PIN_FAIL(unlock_out, GNTST_general_error,
   3.239 +                         "Fault while modifying shared flags.\n");
   3.240 +
   3.241 +                if ( likely(prev_sflags == sflags) )
   3.242 +                    break;
   3.243 +
   3.244 +                if ( retries++ == 4 )
   3.245 +                    PIN_FAIL(unlock_out, GNTST_general_error,
   3.246 +                             "Shared grant entry is unstable.\n");
   3.247 +
   3.248 +                sflags = prev_sflags;
   3.249 +            }
   3.250 +
   3.251 +#ifdef __ia64__
   3.252 +// FIXME-ia64: any error checking need to be done here?
   3.253 +#else
   3.254 +            if ( unlikely(!get_page_type(&frame_table[frame],
   3.255 +                                         PGT_writable_page)) )
   3.256 +            {
   3.257 +                clear_bit(_GTF_writing, &sha->flags);
   3.258 +                PIN_FAIL(unlock_out, GNTST_general_error,
   3.259 +                         "Attempt to write-pin a unwritable page.\n");
   3.260 +            }
   3.261 +#endif
   3.262 +        }
   3.263 +
   3.264 +        if ( dev_hst_ro_flags & GNTMAP_device_map )
   3.265 +            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ? 
   3.266 +                GNTPIN_devr_inc : GNTPIN_devw_inc;
   3.267 +
   3.268 +        if ( dev_hst_ro_flags & GNTMAP_host_map )
   3.269 +            act->pin += (dev_hst_ro_flags & GNTMAP_readonly) ?
   3.270 +                GNTPIN_hstr_inc : GNTPIN_hstw_inc;
   3.271 +    }
   3.272 +
   3.273 +    /*
   3.274 +     * At this point:
   3.275 +     * act->pin updated to reflect mapping.
   3.276 +     * sha->flags updated to indicate to granting domain mapping done.
   3.277 +     * frame contains the mfn.
   3.278 +     */
   3.279 +
   3.280 +    spin_unlock(&granting_d->grant_table->lock);
   3.281 +
   3.282 +#ifdef __ia64__
   3.283 +// FIXME-ia64: any error checking need to be done here?
   3.284 +#else
   3.285 +    if ( (host_virt_addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) )
   3.286 +    {
   3.287 +        /* Write update into the pagetable. */
   3.288 +        l1_pgentry_t pte;
   3.289 +        pte = l1e_from_pfn(frame, _PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY);
   3.290 +        if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
   3.291 +            l1e_add_flags(pte,_PAGE_RW);
   3.292 +        rc = update_grant_va_mapping( host_virt_addr, pte, 
   3.293 +                       mapping_d, mapping_ed );
   3.294 +
   3.295 +        /*
   3.296 +         * IMPORTANT: (rc == 0) => must flush / invalidate entry in TLB.
   3.297 +         * This is done in the outer gnttab_map_grant_ref.
   3.298 +         */
   3.299 +
   3.300 +        if ( rc < 0 )
   3.301 +        {
   3.302 +            /* Failure: undo and abort. */
   3.303 +
   3.304 +            spin_lock(&granting_d->grant_table->lock);
   3.305 +
   3.306 +            if ( dev_hst_ro_flags & GNTMAP_readonly )
   3.307 +            {
   3.308 +                act->pin -= GNTPIN_hstr_inc;
   3.309 +            }
   3.310 +            else
   3.311 +            {
   3.312 +                act->pin -= GNTPIN_hstw_inc;
   3.313 +                if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
   3.314 +                {
   3.315 +                    clear_bit(_GTF_writing, &sha->flags);
   3.316 +                    put_page_type(&frame_table[frame]);
   3.317 +                }
   3.318 +            }
   3.319 +
   3.320 +            if ( act->pin == 0 )
   3.321 +            {
   3.322 +                clear_bit(_GTF_reading, &sha->flags);
   3.323 +                put_page(&frame_table[frame]);
   3.324 +            }
   3.325 +
   3.326 +            spin_unlock(&granting_d->grant_table->lock);
   3.327 +        }
   3.328 +
   3.329 +    }
   3.330 +#endif
   3.331 +
   3.332 +    *pframe = frame;
   3.333 +    return rc;
   3.334 +
   3.335 + unlock_out:
   3.336 +    spin_unlock(&granting_d->grant_table->lock);
   3.337 +    return rc;
   3.338 +}
   3.339 +
   3.340 +/*
   3.341 + * Returns 0 if TLB flush / invalidate required by caller.
   3.342 + * va will indicate the address to be invalidated.
   3.343 + */
   3.344 +static int
   3.345 +__gnttab_map_grant_ref(
   3.346 +    gnttab_map_grant_ref_t *uop,
   3.347 +    unsigned long *va)
   3.348 +{
   3.349 +    domid_t               dom;
   3.350 +    grant_ref_t           ref;
   3.351 +    struct domain        *ld, *rd;
   3.352 +    struct vcpu   *led;
   3.353 +    u16                   dev_hst_ro_flags;
   3.354 +    int                   handle;
   3.355 +    unsigned long         frame = 0, host_virt_addr;
   3.356 +    int                   rc;
   3.357 +
   3.358 +    led = current;
   3.359 +    ld = led->domain;
   3.360 +
   3.361 +    /* Bitwise-OR avoids short-circuiting which screws control flow. */
   3.362 +    if ( unlikely(__get_user(dom, &uop->dom) |
   3.363 +                  __get_user(ref, &uop->ref) |
   3.364 +                  __get_user(host_virt_addr, &uop->host_virt_addr) |
   3.365 +                  __get_user(dev_hst_ro_flags, &uop->flags)) )
   3.366 +    {
   3.367 +        DPRINTK("Fault while reading gnttab_map_grant_ref_t.\n");
   3.368 +        return -EFAULT; /* don't set status */
   3.369 +    }
   3.370 +
   3.371 +
   3.372 +    if ( ((host_virt_addr != 0) || (dev_hst_ro_flags & GNTMAP_host_map)) &&
   3.373 +         unlikely(!__addr_ok(host_virt_addr)))
   3.374 +    {
   3.375 +        DPRINTK("Bad virtual address (%lx) or flags (%x).\n",
   3.376 +                host_virt_addr, dev_hst_ro_flags);
   3.377 +        (void)__put_user(GNTST_bad_virt_addr, &uop->handle);
   3.378 +        return GNTST_bad_gntref;
   3.379 +    }
   3.380 +
   3.381 +    if ( unlikely(ref >= NR_GRANT_ENTRIES) ||
   3.382 +         unlikely((dev_hst_ro_flags &
   3.383 +                   (GNTMAP_device_map|GNTMAP_host_map)) == 0) )
   3.384 +    {
   3.385 +        DPRINTK("Bad ref (%d) or flags (%x).\n", ref, dev_hst_ro_flags);
   3.386 +        (void)__put_user(GNTST_bad_gntref, &uop->handle);
   3.387 +        return GNTST_bad_gntref;
   3.388 +    }
   3.389 +
   3.390 +    if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
   3.391 +         unlikely(ld == rd) )
   3.392 +    {
   3.393 +        if ( rd != NULL )
   3.394 +            put_domain(rd);
   3.395 +        DPRINTK("Could not find domain %d\n", dom);
   3.396 +        (void)__put_user(GNTST_bad_domain, &uop->handle);
   3.397 +        return GNTST_bad_domain;
   3.398 +    }
   3.399 +
   3.400 +    /* Get a maptrack handle. */
   3.401 +    if ( unlikely((handle = get_maptrack_handle(ld->grant_table)) == -1) )
   3.402 +    {
   3.403 +        int              i;
   3.404 +        grant_mapping_t *new_mt;
   3.405 +        grant_table_t   *lgt      = ld->grant_table;
   3.406 +
   3.407 +        /* Grow the maptrack table. */
   3.408 +        new_mt = alloc_xenheap_pages(lgt->maptrack_order + 1);
   3.409 +        if ( new_mt == NULL )
   3.410 +        {
   3.411 +            put_domain(rd);
   3.412 +            DPRINTK("No more map handles available\n");
   3.413 +            (void)__put_user(GNTST_no_device_space, &uop->handle);
   3.414 +            return GNTST_no_device_space;
   3.415 +        }
   3.416 +
   3.417 +        memcpy(new_mt, lgt->maptrack, PAGE_SIZE << lgt->maptrack_order);
   3.418 +        for ( i = lgt->maptrack_limit; i < (lgt->maptrack_limit << 1); i++ )
   3.419 +            new_mt[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT;
   3.420 +
   3.421 +        free_xenheap_pages(lgt->maptrack, lgt->maptrack_order);
   3.422 +        lgt->maptrack          = new_mt;
   3.423 +        lgt->maptrack_order   += 1;
   3.424 +        lgt->maptrack_limit  <<= 1;
   3.425 +
   3.426 +        printk("Doubled maptrack size\n");
   3.427 +        handle = get_maptrack_handle(ld->grant_table);
   3.428 +    }
   3.429 +
   3.430 +#if GRANT_DEBUG_VERBOSE
   3.431 +    DPRINTK("Mapping grant ref (%hu) for domain (%hu) with flags (%x)\n",
   3.432 +            ref, dom, dev_hst_ro_flags);
   3.433 +#endif
   3.434 +
   3.435 +    if ( 0 <= ( rc = __gnttab_activate_grant_ref( ld, led, rd, ref,
   3.436 +                                                  dev_hst_ro_flags,
   3.437 +                                                  host_virt_addr, &frame)))
   3.438 +    {
   3.439 +        /*
   3.440 +         * Only make the maptrack live _after_ writing the pte, in case we 
   3.441 +         * overwrite the same frame number, causing a maptrack walk to find it
   3.442 +         */
   3.443 +        ld->grant_table->maptrack[handle].domid = dom;
   3.444 +
   3.445 +        ld->grant_table->maptrack[handle].ref_and_flags
   3.446 +            = (ref << MAPTRACK_REF_SHIFT) |
   3.447 +              (dev_hst_ro_flags & MAPTRACK_GNTMAP_MASK);
   3.448 +
   3.449 +        (void)__put_user(frame, &uop->dev_bus_addr);
   3.450 +
   3.451 +        if ( dev_hst_ro_flags & GNTMAP_host_map )
   3.452 +            *va = host_virt_addr;
   3.453 +
   3.454 +        (void)__put_user(handle, &uop->handle);
   3.455 +    }
   3.456 +    else
   3.457 +    {
   3.458 +        (void)__put_user(rc, &uop->handle);
   3.459 +        put_maptrack_handle(ld->grant_table, handle);
   3.460 +    }
   3.461 +
   3.462 +    put_domain(rd);
   3.463 +    return rc;
   3.464 +}
   3.465 +
   3.466 +static long
   3.467 +gnttab_map_grant_ref(
   3.468 +    gnttab_map_grant_ref_t *uop, unsigned int count)
   3.469 +{
   3.470 +    int i, flush = 0;
   3.471 +    unsigned long va = 0;
   3.472 +
   3.473 +    for ( i = 0; i < count; i++ )
   3.474 +        if ( __gnttab_map_grant_ref(&uop[i], &va) == 0 )
   3.475 +            flush++;
   3.476 +
   3.477 +#ifdef __ia64__
   3.478 +// FIXME-ia64: probably need to do something here to avoid stale mappings?
   3.479 +#else
   3.480 +    if ( flush == 1 )
   3.481 +        flush_tlb_one_mask(current->domain->cpumask, va);
   3.482 +    else if ( flush != 0 ) 
   3.483 +        flush_tlb_mask(current->domain->cpumask);
   3.484 +#endif
   3.485 +
   3.486 +    return 0;
   3.487 +}
   3.488 +
   3.489 +static int
   3.490 +__gnttab_unmap_grant_ref(
   3.491 +    gnttab_unmap_grant_ref_t *uop,
   3.492 +    unsigned long *va)
   3.493 +{
   3.494 +    domid_t        dom;
   3.495 +    grant_ref_t    ref;
   3.496 +    u16            handle;
   3.497 +    struct domain *ld, *rd;
   3.498 +
   3.499 +    active_grant_entry_t *act;
   3.500 +    grant_entry_t *sha;
   3.501 +    grant_mapping_t *map;
   3.502 +    u16            flags;
   3.503 +    s16            rc = 1;
   3.504 +    unsigned long  frame, virt;
   3.505 +
   3.506 +    ld = current->domain;
   3.507 +
   3.508 +    /* Bitwise-OR avoids short-circuiting which screws control flow. */
   3.509 +    if ( unlikely(__get_user(virt, &uop->host_virt_addr) |
   3.510 +                  __get_user(frame, &uop->dev_bus_addr) |
   3.511 +                  __get_user(handle, &uop->handle)) )
   3.512 +    {
   3.513 +        DPRINTK("Fault while reading gnttab_unmap_grant_ref_t.\n");
   3.514 +        return -EFAULT; /* don't set status */
   3.515 +    }
   3.516 +
   3.517 +    map = &ld->grant_table->maptrack[handle];
   3.518 +
   3.519 +    if ( unlikely(handle >= ld->grant_table->maptrack_limit) ||
   3.520 +         unlikely(!(map->ref_and_flags & MAPTRACK_GNTMAP_MASK)) )
   3.521 +    {
   3.522 +        DPRINTK("Bad handle (%d).\n", handle);
   3.523 +        (void)__put_user(GNTST_bad_handle, &uop->status);
   3.524 +        return GNTST_bad_handle;
   3.525 +    }
   3.526 +
   3.527 +    dom   = map->domid;
   3.528 +    ref   = map->ref_and_flags >> MAPTRACK_REF_SHIFT;
   3.529 +    flags = map->ref_and_flags & MAPTRACK_GNTMAP_MASK;
   3.530 +
   3.531 +    if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
   3.532 +         unlikely(ld == rd) )
   3.533 +    {
   3.534 +        if ( rd != NULL )
   3.535 +            put_domain(rd);
   3.536 +        DPRINTK("Could not find domain %d\n", dom);
   3.537 +        (void)__put_user(GNTST_bad_domain, &uop->status);
   3.538 +        return GNTST_bad_domain;
   3.539 +    }
   3.540 +
   3.541 +#if GRANT_DEBUG_VERBOSE
   3.542 +    DPRINTK("Unmapping grant ref (%hu) for domain (%hu) with handle (%hu)\n",
   3.543 +            ref, dom, handle);
   3.544 +#endif
   3.545 +
   3.546 +    act = &rd->grant_table->active[ref];
   3.547 +    sha = &rd->grant_table->shared[ref];
   3.548 +
   3.549 +    spin_lock(&rd->grant_table->lock);
   3.550 +
   3.551 +    if ( frame == 0 )
   3.552 +    {
   3.553 +        frame = act->frame;
   3.554 +    }
   3.555 +    else if ( frame == GNTUNMAP_DEV_FROM_VIRT )
   3.556 +    {
   3.557 +        if ( !( flags & GNTMAP_device_map ) )
   3.558 +            PIN_FAIL(unmap_out, GNTST_bad_dev_addr,
   3.559 +                     "Bad frame number: frame not mapped for dev access.\n");
   3.560 +        frame = act->frame;
   3.561 +
   3.562 +        /* Frame will be unmapped for device access below if virt addr okay. */
   3.563 +    }
   3.564 +    else
   3.565 +    {
   3.566 +        if ( unlikely(frame != act->frame) )
   3.567 +            PIN_FAIL(unmap_out, GNTST_general_error,
   3.568 +                     "Bad frame number doesn't match gntref.\n");
   3.569 +        if ( flags & GNTMAP_device_map )
   3.570 +            act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc
   3.571 +                                                  : GNTPIN_devw_inc;
   3.572 +
   3.573 +        map->ref_and_flags &= ~GNTMAP_device_map;
   3.574 +        (void)__put_user(0, &uop->dev_bus_addr);
   3.575 +
   3.576 +        /* Frame is now unmapped for device access. */
   3.577 +    }
   3.578 +
   3.579 +#ifdef __ia64__
   3.580 +// FIXME-ia64: any error checking need to be done here?
   3.581 +#else
   3.582 +    if ( (virt != 0) &&
   3.583 +         (flags & GNTMAP_host_map) &&
   3.584 +         ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0))
   3.585 +    {
   3.586 +        l1_pgentry_t   *pl1e;
   3.587 +        unsigned long   _ol1e;
   3.588 +
   3.589 +        pl1e = &linear_pg_table[l1_linear_offset(virt)];
   3.590 +
   3.591 +        if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
   3.592 +        {
   3.593 +            DPRINTK("Could not find PTE entry for address %lx\n", virt);
   3.594 +            rc = -EINVAL;
   3.595 +            goto unmap_out;
   3.596 +        }
   3.597 +
   3.598 +        /*
   3.599 +         * Check that the virtual address supplied is actually mapped to 
   3.600 +         * act->frame.
   3.601 +         */
   3.602 +        if ( unlikely((_ol1e >> PAGE_SHIFT) != frame ))
   3.603 +        {
   3.604 +            DPRINTK("PTE entry %lx for address %lx doesn't match frame %lx\n",
   3.605 +                    _ol1e, virt, frame);
   3.606 +            rc = -EINVAL;
   3.607 +            goto unmap_out;
   3.608 +        }
   3.609 +
   3.610 +        /* Delete pagetable entry. */
   3.611 +        if ( unlikely(__put_user(0, (unsigned long *)pl1e)))
   3.612 +        {
   3.613 +            DPRINTK("Cannot delete PTE entry at %p for virtual address %lx\n",
   3.614 +                    pl1e, virt);
   3.615 +            rc = -EINVAL;
   3.616 +            goto unmap_out;
   3.617 +        }
   3.618 +
   3.619 +        map->ref_and_flags &= ~GNTMAP_host_map;
   3.620 +
   3.621 +        act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc
   3.622 +                                              : GNTPIN_hstw_inc;
   3.623 +
   3.624 +        if ( frame == GNTUNMAP_DEV_FROM_VIRT )
   3.625 +        {
   3.626 +            act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_devr_inc
   3.627 +                                                  : GNTPIN_devw_inc;
   3.628 +
   3.629 +            map->ref_and_flags &= ~GNTMAP_device_map;
   3.630 +            (void)__put_user(0, &uop->dev_bus_addr);
   3.631 +        }
   3.632 +
   3.633 +        rc = 0;
   3.634 +        *va = virt;
   3.635 +    }
   3.636 +#endif
   3.637 +
   3.638 +    if ( (map->ref_and_flags & (GNTMAP_device_map|GNTMAP_host_map)) == 0)
   3.639 +    {
   3.640 +        map->ref_and_flags = 0;
   3.641 +        put_maptrack_handle(ld->grant_table, handle);
   3.642 +    }
   3.643 +
   3.644 +#ifdef __ia64__
   3.645 +// FIXME-ia64: any error checking need to be done here?  I think not and then
   3.646 +//  this can probably be macro-ized into nothingness
   3.647 +#else
   3.648 +    /* If just unmapped a writable mapping, mark as dirtied */
   3.649 +    if ( unlikely(shadow_mode_log_dirty(rd)) &&
   3.650 +        !( flags & GNTMAP_readonly ) )
   3.651 +         mark_dirty(rd, frame);
   3.652 +#endif
   3.653 +
   3.654 +    /* If the last writable mapping has been removed, put_page_type */
   3.655 +    if ( ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask) ) == 0) &&
   3.656 +         ( !( flags & GNTMAP_readonly ) ) )
   3.657 +    {
   3.658 +        clear_bit(_GTF_writing, &sha->flags);
   3.659 +        put_page_type(&frame_table[frame]);
   3.660 +    }
   3.661 +
   3.662 +    if ( act->pin == 0 )
   3.663 +    {
   3.664 +        clear_bit(_GTF_reading, &sha->flags);
   3.665 +        put_page(&frame_table[frame]);
   3.666 +    }
   3.667 +
   3.668 + unmap_out:
   3.669 +    (void)__put_user(rc, &uop->status);
   3.670 +    spin_unlock(&rd->grant_table->lock);
   3.671 +    put_domain(rd);
   3.672 +    return rc;
   3.673 +}
   3.674 +
   3.675 +static long
   3.676 +gnttab_unmap_grant_ref(
   3.677 +    gnttab_unmap_grant_ref_t *uop, unsigned int count)
   3.678 +{
   3.679 +    int i, flush = 0;
   3.680 +    unsigned long va = 0;
   3.681 +
   3.682 +    for ( i = 0; i < count; i++ )
   3.683 +        if ( __gnttab_unmap_grant_ref(&uop[i], &va) == 0 )
   3.684 +            flush++;
   3.685 +
   3.686 +#ifdef __ia64__
   3.687 +// FIXME-ia64: probably need to do something here to avoid stale mappings?
   3.688 +#else
   3.689 +    if ( flush == 1 )
   3.690 +        flush_tlb_one_mask(current->domain->cpumask, va);
   3.691 +    else if ( flush != 0 ) 
   3.692 +        flush_tlb_mask(current->domain->cpumask);
   3.693 +#endif
   3.694 +
   3.695 +    return 0;
   3.696 +}
   3.697 +
   3.698 +static long 
   3.699 +gnttab_setup_table(
   3.700 +    gnttab_setup_table_t *uop, unsigned int count)
   3.701 +{
   3.702 +    gnttab_setup_table_t  op;
   3.703 +    struct domain        *d;
   3.704 +    int                   i;
   3.705 +
   3.706 +    if ( count != 1 )
   3.707 +        return -EINVAL;
   3.708 +
   3.709 +    if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
   3.710 +    {
   3.711 +        DPRINTK("Fault while reading gnttab_setup_table_t.\n");
   3.712 +        return -EFAULT;
   3.713 +    }
   3.714 +
   3.715 +    if ( unlikely(op.nr_frames > NR_GRANT_FRAMES) )
   3.716 +    {
   3.717 +        DPRINTK("Xen only supports up to %d grant-table frames per domain.\n",
   3.718 +                NR_GRANT_FRAMES);
   3.719 +        (void)put_user(GNTST_general_error, &uop->status);
   3.720 +        return 0;
   3.721 +    }
   3.722 +
   3.723 +    if ( op.dom == DOMID_SELF )
   3.724 +    {
   3.725 +        op.dom = current->domain->domain_id;
   3.726 +    }
   3.727 +    else if ( unlikely(!IS_PRIV(current->domain)) )
   3.728 +    {
   3.729 +        (void)put_user(GNTST_permission_denied, &uop->status);
   3.730 +        return 0;
   3.731 +    }
   3.732 +
   3.733 +    if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
   3.734 +    {
   3.735 +        DPRINTK("Bad domid %d.\n", op.dom);
   3.736 +        (void)put_user(GNTST_bad_domain, &uop->status);
   3.737 +        return 0;
   3.738 +    }
   3.739 +
   3.740 +    if ( op.nr_frames <= NR_GRANT_FRAMES )
   3.741 +    {
   3.742 +        ASSERT(d->grant_table != NULL);
   3.743 +        (void)put_user(GNTST_okay, &uop->status);
   3.744 +        for ( i = 0; i < op.nr_frames; i++ )
   3.745 +            (void)put_user(
   3.746 +                (virt_to_phys(d->grant_table->shared) >> PAGE_SHIFT) + i,
   3.747 +                &uop->frame_list[i]);
   3.748 +    }
   3.749 +
   3.750 +    put_domain(d);
   3.751 +    return 0;
   3.752 +}
   3.753 +
   3.754 +#if GRANT_DEBUG
   3.755 +static int
   3.756 +gnttab_dump_table(gnttab_dump_table_t *uop)
   3.757 +{
   3.758 +    grant_table_t        *gt;
   3.759 +    gnttab_dump_table_t   op;
   3.760 +    struct domain        *d;
   3.761 +    u32                   shared_mfn;
   3.762 +    active_grant_entry_t *act;
   3.763 +    grant_entry_t         sha_copy;
   3.764 +    grant_mapping_t      *maptrack;
   3.765 +    int                   i;
   3.766 +
   3.767 +
   3.768 +    if ( unlikely(copy_from_user(&op, uop, sizeof(op)) != 0) )
   3.769 +    {
   3.770 +        DPRINTK("Fault while reading gnttab_dump_table_t.\n");
   3.771 +        return -EFAULT;
   3.772 +    }
   3.773 +
   3.774 +    if ( op.dom == DOMID_SELF )
   3.775 +    {
   3.776 +        op.dom = current->domain->domain_id;
   3.777 +    }
   3.778 +
   3.779 +    if ( unlikely((d = find_domain_by_id(op.dom)) == NULL) )
   3.780 +    {
   3.781 +        DPRINTK("Bad domid %d.\n", op.dom);
   3.782 +        (void)put_user(GNTST_bad_domain, &uop->status);
   3.783 +        return 0;
   3.784 +    }
   3.785 +
   3.786 +    ASSERT(d->grant_table != NULL);
   3.787 +    gt = d->grant_table;
   3.788 +    (void)put_user(GNTST_okay, &uop->status);
   3.789 +
   3.790 +    shared_mfn = virt_to_phys(d->grant_table->shared);
   3.791 +
   3.792 +    DPRINTK("Grant table for dom (%hu) MFN (%x)\n",
   3.793 +            op.dom, shared_mfn);
   3.794 +
   3.795 +    ASSERT(d->grant_table->active != NULL);
   3.796 +    ASSERT(d->grant_table->shared != NULL);
   3.797 +    ASSERT(d->grant_table->maptrack != NULL);
   3.798 +
   3.799 +    for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
   3.800 +    {
   3.801 +        sha_copy =  gt->shared[i];
   3.802 +
   3.803 +        if ( sha_copy.flags )
   3.804 +        {
   3.805 +            DPRINTK("Grant: dom (%hu) SHARED (%d) flags:(%hx) "
   3.806 +                    "dom:(%hu) frame:(%lx)\n",
   3.807 +                    op.dom, i, sha_copy.flags, sha_copy.domid, sha_copy.frame);
   3.808 +        }
   3.809 +    }
   3.810 +
   3.811 +    spin_lock(&gt->lock);
   3.812 +
   3.813 +    for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
   3.814 +    {
   3.815 +        act = &gt->active[i];
   3.816 +
   3.817 +        if ( act->pin )
   3.818 +        {
   3.819 +            DPRINTK("Grant: dom (%hu) ACTIVE (%d) pin:(%x) "
   3.820 +                    "dom:(%hu) frame:(%lx)\n",
   3.821 +                    op.dom, i, act->pin, act->domid, act->frame);
   3.822 +        }
   3.823 +    }
   3.824 +
   3.825 +    for ( i = 0; i < gt->maptrack_limit; i++ )
   3.826 +    {
   3.827 +        maptrack = &gt->maptrack[i];
   3.828 +
   3.829 +        if ( maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK )
   3.830 +        {
   3.831 +            DPRINTK("Grant: dom (%hu) MAP (%d) ref:(%hu) flags:(%x) "
   3.832 +                    "dom:(%hu)\n",
   3.833 +                    op.dom, i,
   3.834 +                    maptrack->ref_and_flags >> MAPTRACK_REF_SHIFT,
   3.835 +                    maptrack->ref_and_flags & MAPTRACK_GNTMAP_MASK,
   3.836 +                    maptrack->domid);
   3.837 +        }
   3.838 +    }
   3.839 +
   3.840 +    spin_unlock(&gt->lock);
   3.841 +
   3.842 +    put_domain(d);
   3.843 +    return 0;
   3.844 +}
   3.845 +#endif
   3.846 +
   3.847 +long 
   3.848 +do_grant_table_op(
   3.849 +    unsigned int cmd, void *uop, unsigned int count)
   3.850 +{
   3.851 +    long rc;
   3.852 +
   3.853 +    if ( count > 512 )
   3.854 +        return -EINVAL;
   3.855 +
   3.856 +    LOCK_BIGLOCK(current->domain);
   3.857 +
   3.858 +    rc = -EFAULT;
   3.859 +    switch ( cmd )
   3.860 +    {
   3.861 +    case GNTTABOP_map_grant_ref:
   3.862 +        if ( unlikely(!array_access_ok(
   3.863 +            uop, count, sizeof(gnttab_map_grant_ref_t))) )
   3.864 +            goto out;
   3.865 +        rc = gnttab_map_grant_ref((gnttab_map_grant_ref_t *)uop, count);
   3.866 +        break;
   3.867 +    case GNTTABOP_unmap_grant_ref:
   3.868 +        if ( unlikely(!array_access_ok(
   3.869 +            uop, count, sizeof(gnttab_unmap_grant_ref_t))) )
   3.870 +            goto out;
   3.871 +        rc = gnttab_unmap_grant_ref((gnttab_unmap_grant_ref_t *)uop, count);
   3.872 +        break;
   3.873 +    case GNTTABOP_setup_table:
   3.874 +        rc = gnttab_setup_table((gnttab_setup_table_t *)uop, count);
   3.875 +        break;
   3.876 +#if GRANT_DEBUG
   3.877 +    case GNTTABOP_dump_table:
   3.878 +        rc = gnttab_dump_table((gnttab_dump_table_t *)uop);
   3.879 +        break;
   3.880 +#endif
   3.881 +    default:
   3.882 +        rc = -ENOSYS;
   3.883 +        break;
   3.884 +    }
   3.885 +
   3.886 +out:
   3.887 +    UNLOCK_BIGLOCK(current->domain);
   3.888 +
   3.889 +    return rc;
   3.890 +}
   3.891 +
   3.892 +int
   3.893 +gnttab_check_unmap(
   3.894 +    struct domain *rd, struct domain *ld, unsigned long frame, int readonly)
   3.895 +{
   3.896 +    /* Called when put_page is invoked on a page belonging to a foreign domain.
   3.897 +     * Instead of decrementing the frame table ref count, locate the grant
   3.898 +     * table entry, if any, and if found, decrement that count.
   3.899 +     * Called a _lot_ at domain creation because pages mapped by priv domains
   3.900 +     * also traverse this.
   3.901 +     */
   3.902 +
   3.903 +    /* Note: If the same frame is mapped multiple times, and then one of
   3.904 +     *       the ptes is overwritten, which maptrack handle gets invalidated?
   3.905 +     * Advice: Don't do it. Explicitly unmap.
   3.906 +     */
   3.907 +
   3.908 +    unsigned int handle, ref, refcount;
   3.909 +    grant_table_t        *lgt, *rgt;
   3.910 +    active_grant_entry_t *act;
   3.911 +    grant_mapping_t      *map;
   3.912 +    int found = 0;
   3.913 +
   3.914 +    lgt = ld->grant_table;
   3.915 +
   3.916 +#if GRANT_DEBUG_VERBOSE
   3.917 +    if ( ld->domain_id != 0 )
   3.918 +    {
   3.919 +        DPRINTK("Foreign unref rd(%d) ld(%d) frm(%x) flgs(%x).\n",
   3.920 +                rd->domain_id, ld->domain_id, frame, readonly);
   3.921 +    }
   3.922 +#endif
   3.923 +
   3.924 +    /* Fast exit if we're not mapping anything using grant tables */
   3.925 +    if ( lgt->map_count == 0 )
   3.926 +        return 0;
   3.927 +
   3.928 +    if ( get_domain(rd) == 0 )
   3.929 +    {
   3.930 +        DPRINTK("gnttab_check_unmap: couldn't get_domain rd(%d)\n",
   3.931 +                rd->domain_id);
   3.932 +        return 0;
   3.933 +    }
   3.934 +
   3.935 +    rgt = rd->grant_table;
   3.936 +
   3.937 +    for ( handle = 0; handle < lgt->maptrack_limit; handle++ )
   3.938 +    {
   3.939 +        map = &lgt->maptrack[handle];
   3.940 +
   3.941 +        if ( ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK ) &&
   3.942 +             ( readonly ? 1 : (!(map->ref_and_flags & GNTMAP_readonly))))
   3.943 +        {
   3.944 +            ref = (map->ref_and_flags >> MAPTRACK_REF_SHIFT);
   3.945 +            act = &rgt->active[ref];
   3.946 +
   3.947 +            spin_lock(&rgt->lock);
   3.948 +
   3.949 +            if ( act->frame != frame )
   3.950 +            {
   3.951 +                spin_unlock(&rgt->lock);
   3.952 +                continue;
   3.953 +            }
   3.954 +
   3.955 +            refcount = act->pin & ( readonly ? GNTPIN_hstr_mask
   3.956 +                                             : GNTPIN_hstw_mask );
   3.957 +            if ( refcount == 0 )
   3.958 +            {
   3.959 +                spin_unlock(&rgt->lock);
   3.960 +                continue;
   3.961 +            }
   3.962 +
   3.963 +            /* gotcha */
   3.964 +            DPRINTK("Grant unref rd(%d) ld(%d) frm(%lx) flgs(%x).\n",
   3.965 +                    rd->domain_id, ld->domain_id, frame, readonly);
   3.966 +
   3.967 +            if ( readonly )
   3.968 +                act->pin -= GNTPIN_hstr_inc;
   3.969 +            else
   3.970 +            {
   3.971 +                act->pin -= GNTPIN_hstw_inc;
   3.972 +
   3.973 +                /* any more granted writable mappings? */
   3.974 +                if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
   3.975 +                {
   3.976 +                    clear_bit(_GTF_writing, &rgt->shared[ref].flags);
   3.977 +                    put_page_type(&frame_table[frame]);
   3.978 +                }
   3.979 +            }
   3.980 +
   3.981 +            if ( act->pin == 0 )
   3.982 +            {
   3.983 +                clear_bit(_GTF_reading, &rgt->shared[ref].flags);
   3.984 +                put_page(&frame_table[frame]);
   3.985 +            }
   3.986 +            spin_unlock(&rgt->lock);
   3.987 +
   3.988 +            clear_bit(GNTMAP_host_map, &map->ref_and_flags);
   3.989 +
   3.990 +            if ( !(map->ref_and_flags & GNTMAP_device_map) )
   3.991 +                put_maptrack_handle(lgt, handle);
   3.992 +
   3.993 +            found = 1;
   3.994 +            break;
   3.995 +        }
   3.996 +    }
   3.997 +    put_domain(rd);
   3.998 +
   3.999 +    return found;
  3.1000 +}
  3.1001 +
  3.1002 +int 
  3.1003 +gnttab_prepare_for_transfer(
  3.1004 +    struct domain *rd, struct domain *ld, grant_ref_t ref)
  3.1005 +{
  3.1006 +    grant_table_t *rgt;
  3.1007 +    grant_entry_t *sha;
  3.1008 +    domid_t        sdom;
  3.1009 +    u16            sflags;
  3.1010 +    u32            scombo, prev_scombo;
  3.1011 +    int            retries = 0;
  3.1012 +    unsigned long  target_pfn;
  3.1013 +
  3.1014 +    DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n",
  3.1015 +            rd->domain_id, ld->domain_id, ref);
  3.1016 +
  3.1017 +    if ( unlikely((rgt = rd->grant_table) == NULL) ||
  3.1018 +         unlikely(ref >= NR_GRANT_ENTRIES) )
  3.1019 +    {
  3.1020 +        DPRINTK("Dom %d has no g.t., or ref is bad (%d).\n",
  3.1021 +                rd->domain_id, ref);
  3.1022 +        return 0;
  3.1023 +    }
  3.1024 +
  3.1025 +    spin_lock(&rgt->lock);
  3.1026 +
  3.1027 +    sha = &rgt->shared[ref];
  3.1028 +    
  3.1029 +    sflags = sha->flags;
  3.1030 +    sdom   = sha->domid;
  3.1031 +
  3.1032 +    for ( ; ; )
  3.1033 +    {
  3.1034 +        target_pfn = sha->frame;
  3.1035 +
  3.1036 +        if ( unlikely(target_pfn >= max_page ) )
  3.1037 +        {
  3.1038 +            DPRINTK("Bad pfn (%lx)\n", target_pfn);
  3.1039 +            goto fail;
  3.1040 +        }
  3.1041 +
  3.1042 +        if ( unlikely(sflags != GTF_accept_transfer) ||
  3.1043 +             unlikely(sdom != ld->domain_id) )
  3.1044 +        {
  3.1045 +            DPRINTK("Bad flags (%x) or dom (%d). (NB. expected dom %d)\n",
  3.1046 +                    sflags, sdom, ld->domain_id);
  3.1047 +            goto fail;
  3.1048 +        }
  3.1049 +
  3.1050 +        /* Merge two 16-bit values into a 32-bit combined update. */
  3.1051 +        /* NB. Endianness! */
  3.1052 +        prev_scombo = scombo = ((u32)sdom << 16) | (u32)sflags;
  3.1053 +
  3.1054 +        /* NB. prev_scombo is updated in place to seen value. */
  3.1055 +        if ( unlikely(cmpxchg_user((u32 *)&sha->flags, prev_scombo, 
  3.1056 +                                   prev_scombo | GTF_transfer_committed)) )
  3.1057 +        {
  3.1058 +            DPRINTK("Fault while modifying shared flags and domid.\n");
  3.1059 +            goto fail;
  3.1060 +        }
  3.1061 +
  3.1062 +        /* Did the combined update work (did we see what we expected?). */
  3.1063 +        if ( likely(prev_scombo == scombo) )
  3.1064 +            break;
  3.1065 +
  3.1066 +        if ( retries++ == 4 )
  3.1067 +        {
  3.1068 +            DPRINTK("Shared grant entry is unstable.\n");
  3.1069 +            goto fail;
  3.1070 +        }
  3.1071 +
  3.1072 +        /* Didn't see what we expected. Split out the seen flags & dom. */
  3.1073 +        /* NB. Endianness! */
  3.1074 +        sflags = (u16)prev_scombo;
  3.1075 +        sdom   = (u16)(prev_scombo >> 16);
  3.1076 +    }
  3.1077 +
  3.1078 +    spin_unlock(&rgt->lock);
  3.1079 +    return 1;
  3.1080 +
  3.1081 + fail:
  3.1082 +    spin_unlock(&rgt->lock);
  3.1083 +    return 0;
  3.1084 +}
  3.1085 +
  3.1086 +void 
  3.1087 +gnttab_notify_transfer(
  3.1088 +    struct domain *rd, struct domain *ld, grant_ref_t ref, unsigned long frame)
  3.1089 +{
  3.1090 +    grant_entry_t  *sha;
  3.1091 +    unsigned long   pfn;
  3.1092 +
  3.1093 +    DPRINTK("gnttab_notify_transfer rd(%hu) ld(%hu) ref(%hu).\n",
  3.1094 +            rd->domain_id, ld->domain_id, ref);
  3.1095 +
  3.1096 +    sha = &rd->grant_table->shared[ref];
  3.1097 +
  3.1098 +    spin_lock(&rd->grant_table->lock);
  3.1099 +
  3.1100 +#ifdef __ia64__
  3.1101 +// FIXME-ia64: any error checking need to be done here?
  3.1102 +#else
  3.1103 +    pfn = sha->frame;
  3.1104 +
  3.1105 +    if ( unlikely(pfn >= max_page ) )
  3.1106 +        DPRINTK("Bad pfn (%lx)\n", pfn);
  3.1107 +    else
  3.1108 +    {
  3.1109 +        machine_to_phys_mapping[frame] = pfn;
  3.1110 +
  3.1111 +        if ( unlikely(shadow_mode_log_dirty(ld)))
  3.1112 +             mark_dirty(ld, frame);
  3.1113 +
  3.1114 +        if (shadow_mode_translate(ld))
  3.1115 +            __phys_to_machine_mapping[pfn] = frame;
  3.1116 +    }
  3.1117 +#endif
  3.1118 +    sha->frame = __mfn_to_gpfn(rd, frame);
  3.1119 +    sha->domid = rd->domain_id;
  3.1120 +    wmb();
  3.1121 +    sha->flags = ( GTF_accept_transfer | GTF_transfer_completed );
  3.1122 +
  3.1123 +    spin_unlock(&rd->grant_table->lock);
  3.1124 +
  3.1125 +    return;
  3.1126 +}
  3.1127 +
  3.1128 +int 
  3.1129 +grant_table_create(
  3.1130 +    struct domain *d)
  3.1131 +{
  3.1132 +    grant_table_t *t;
  3.1133 +    int            i;
  3.1134 +
  3.1135 +    if ( (t = xmalloc(grant_table_t)) == NULL )
  3.1136 +        goto no_mem;
  3.1137 +
  3.1138 +    /* Simple stuff. */
  3.1139 +    memset(t, 0, sizeof(*t));
  3.1140 +    spin_lock_init(&t->lock);
  3.1141 +
  3.1142 +    /* Active grant table. */
  3.1143 +    if ( (t->active = xmalloc_array(active_grant_entry_t, NR_GRANT_ENTRIES))
  3.1144 +         == NULL )
  3.1145 +        goto no_mem;
  3.1146 +    memset(t->active, 0, sizeof(active_grant_entry_t) * NR_GRANT_ENTRIES);
  3.1147 +
  3.1148 +    /* Tracking of mapped foreign frames table */
  3.1149 +    if ( (t->maptrack = alloc_xenheap_page()) == NULL )
  3.1150 +        goto no_mem;
  3.1151 +    t->maptrack_order = 0;
  3.1152 +    t->maptrack_limit = PAGE_SIZE / sizeof(grant_mapping_t);
  3.1153 +    memset(t->maptrack, 0, PAGE_SIZE);
  3.1154 +    for ( i = 0; i < t->maptrack_limit; i++ )
  3.1155 +        t->maptrack[i].ref_and_flags = (i+1) << MAPTRACK_REF_SHIFT;
  3.1156 +
  3.1157 +    /* Shared grant table. */
  3.1158 +    t->shared = alloc_xenheap_pages(ORDER_GRANT_FRAMES);
  3.1159 +    if ( t->shared == NULL )
  3.1160 +        goto no_mem;
  3.1161 +    memset(t->shared, 0, NR_GRANT_FRAMES * PAGE_SIZE);
  3.1162 +
  3.1163 +#ifdef __ia64__
  3.1164 +// I don't think there's anything to do here on ia64?...
  3.1165 +#else
  3.1166 +    for ( i = 0; i < NR_GRANT_FRAMES; i++ )
  3.1167 +    {
  3.1168 +        SHARE_PFN_WITH_DOMAIN(
  3.1169 +            virt_to_page((char *)(t->shared)+(i*PAGE_SIZE)), d);
  3.1170 +        machine_to_phys_mapping[(virt_to_phys(t->shared) >> PAGE_SHIFT) + i] =
  3.1171 +            INVALID_M2P_ENTRY;
  3.1172 +    }
  3.1173 +#endif
  3.1174 +
  3.1175 +    /* Okay, install the structure. */
  3.1176 +    wmb(); /* avoid races with lock-free access to d->grant_table */
  3.1177 +    d->grant_table = t;
  3.1178 +    return 0;
  3.1179 +
  3.1180 + no_mem:
  3.1181 +    if ( t != NULL )
  3.1182 +    {
  3.1183 +        xfree(t->active);
  3.1184 +        if ( t->maptrack != NULL )
  3.1185 +            free_xenheap_page(t->maptrack);
  3.1186 +        xfree(t);
  3.1187 +    }
  3.1188 +    return -ENOMEM;
  3.1189 +}
  3.1190 +
  3.1191 +void
  3.1192 +gnttab_release_dev_mappings(grant_table_t *gt)
  3.1193 +{
  3.1194 +    grant_mapping_t        *map;
  3.1195 +    domid_t                 dom;
  3.1196 +    grant_ref_t             ref;
  3.1197 +    u16                     handle;
  3.1198 +    struct domain          *ld, *rd;
  3.1199 +    unsigned long           frame;
  3.1200 +    active_grant_entry_t   *act;
  3.1201 +    grant_entry_t          *sha;
  3.1202 +
  3.1203 +    ld = current->domain;
  3.1204 +
  3.1205 +    for ( handle = 0; handle < gt->maptrack_limit; handle++ )
  3.1206 +    {
  3.1207 +        map = &gt->maptrack[handle];
  3.1208 +
  3.1209 +        if ( map->ref_and_flags & GNTMAP_device_map )
  3.1210 +        {
  3.1211 +            dom = map->domid;
  3.1212 +            ref = map->ref_and_flags >> MAPTRACK_REF_SHIFT;
  3.1213 +
  3.1214 +            DPRINTK("Grant release (%hu) ref:(%hu) flags:(%x) dom:(%hu)\n",
  3.1215 +                    handle, ref,
  3.1216 +                    map->ref_and_flags & MAPTRACK_GNTMAP_MASK, dom);
  3.1217 +
  3.1218 +            if ( unlikely((rd = find_domain_by_id(dom)) == NULL) ||
  3.1219 +                 unlikely(ld == rd) )
  3.1220 +            {
  3.1221 +                if ( rd != NULL )
  3.1222 +                    put_domain(rd);
  3.1223 +
  3.1224 +                printk(KERN_WARNING "Grant release: No dom%d\n", dom);
  3.1225 +                continue;
  3.1226 +            }
  3.1227 +
  3.1228 +            act = &rd->grant_table->active[ref];
  3.1229 +            sha = &rd->grant_table->shared[ref];
  3.1230 +
  3.1231 +            spin_lock(&rd->grant_table->lock);
  3.1232 +
  3.1233 +            if ( act->pin & (GNTPIN_devw_mask | GNTPIN_devr_mask) )
  3.1234 +            {
  3.1235 +                frame = act->frame;
  3.1236 +
  3.1237 +                if ( ( (act->pin & GNTPIN_hstw_mask) == 0 ) &&
  3.1238 +                     ( (act->pin & GNTPIN_devw_mask) >  0 ) )
  3.1239 +                {
  3.1240 +                    clear_bit(_GTF_writing, &sha->flags);
  3.1241 +                    put_page_type(&frame_table[frame]);
  3.1242 +                }
  3.1243 +
  3.1244 +                act->pin &= ~(GNTPIN_devw_mask | GNTPIN_devr_mask);
  3.1245 +
  3.1246 +                if ( act->pin == 0 )
  3.1247 +                {
  3.1248 +                    clear_bit(_GTF_reading, &sha->flags);
  3.1249 +                    map->ref_and_flags = 0;
  3.1250 +                    put_page(&frame_table[frame]);
  3.1251 +                }
  3.1252 +                else
  3.1253 +                    map->ref_and_flags &= ~GNTMAP_device_map;
  3.1254 +            }
  3.1255 +
  3.1256 +            spin_unlock(&rd->grant_table->lock);
  3.1257 +
  3.1258 +            put_domain(rd);
  3.1259 +        }
  3.1260 +    }
  3.1261 +}
  3.1262 +
  3.1263 +
  3.1264 +void
  3.1265 +grant_table_destroy(
  3.1266 +    struct domain *d)
  3.1267 +{
  3.1268 +    grant_table_t *t;
  3.1269 +
  3.1270 +    if ( (t = d->grant_table) != NULL )
  3.1271 +    {
  3.1272 +        /* Free memory relating to this grant table. */
  3.1273 +        d->grant_table = NULL;
  3.1274 +        free_xenheap_pages(t->shared, ORDER_GRANT_FRAMES);
  3.1275 +        free_xenheap_page(t->maptrack);
  3.1276 +        xfree(t->active);
  3.1277 +        xfree(t);
  3.1278 +    }
  3.1279 +}
  3.1280 +
  3.1281 +void
  3.1282 +grant_table_init(
  3.1283 +    void)
  3.1284 +{
  3.1285 +    /* Nothing. */
  3.1286 +}
  3.1287 +#endif
  3.1288 +
  3.1289 +/*
  3.1290 + * Local variables:
  3.1291 + * mode: C
  3.1292 + * c-set-style: "BSD"
  3.1293 + * c-basic-offset: 4
  3.1294 + * tab-width: 4
  3.1295 + * indent-tabs-mode: nil
  3.1296 + * End:
  3.1297 + */
     4.1 --- a/xen/arch/ia64/hypercall.c	Fri Jun 17 18:28:39 2005 +0000
     4.2 +++ b/xen/arch/ia64/hypercall.c	Fri Jun 17 21:22:39 2005 +0000
     4.3 @@ -149,6 +149,12 @@ ia64_hypercall (struct pt_regs *regs)
     4.4  		regs->r8 = do_event_channel_op(regs->r14);
     4.5  		break;
     4.6  
     4.7 +#ifndef CONFIG_VTI
     4.8 +	    case __HYPERVISOR_grant_table_op:
     4.9 +		regs->r8 = do_grant_table_op(regs->r14, regs->r15, regs->r16);
    4.10 +		break;
    4.11 +#endif
    4.12 +
    4.13  	    case __HYPERVISOR_console_io:
    4.14  		regs->r8 = do_console_io(regs->r14, regs->r15, regs->r16);
    4.15  		break;
     5.1 --- a/xen/arch/ia64/xenmisc.c	Fri Jun 17 18:28:39 2005 +0000
     5.2 +++ b/xen/arch/ia64/xenmisc.c	Fri Jun 17 21:22:39 2005 +0000
     5.3 @@ -62,8 +62,10 @@ void sync_lazy_execstate_cpu(unsigned in
     5.4  void sync_lazy_execstate_mask(cpumask_t mask) {}
     5.5  void sync_lazy_execstate_all(void) {}
     5.6  
     5.7 +#ifdef CONFIG_VTI
     5.8  int grant_table_create(struct domain *d) { return 0; }
     5.9  void grant_table_destroy(struct domain *d) { return; }
    5.10 +#endif
    5.11  
    5.12  struct pt_regs *guest_cpu_user_regs(void) { return ia64_task_regs(current); }
    5.13  
    5.14 @@ -72,6 +74,35 @@ void raise_actimer_softirq(void)
    5.15  	raise_softirq(AC_TIMER_SOFTIRQ);
    5.16  }
    5.17  
    5.18 +#ifndef CONFIG_VTI
    5.19 +unsigned long
    5.20 +__gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
    5.21 +{
    5.22 +	if (d == dom0)
    5.23 +		return(gpfn);
    5.24 +	else {
    5.25 +		unsigned long pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT);
    5.26 +		if (!pte) {
    5.27 +printk("__gpfn_to_mfn_foreign: bad gpfn. spinning...\n");
    5.28 +while(1);
    5.29 +			return 0;
    5.30 +		}
    5.31 +		return ((pte & _PFN_MASK) >> PAGE_SHIFT);
    5.32 +	}
    5.33 +}
    5.34 +
    5.35 +u32
    5.36 +__mfn_to_gpfn(struct domain *d, unsigned long frame)
    5.37 +{
    5.38 +	// FIXME: is this right?
    5.39 +if ((frame << PAGE_SHIFT) & _PAGE_PPN_MASK) {
    5.40 +printk("__mfn_to_gpfn: bad frame. spinning...\n");
    5.41 +while(1);
    5.42 +}
    5.43 +	return frame;
    5.44 +}
    5.45 +#endif
    5.46 +
    5.47  unsigned long __hypercall_create_continuation(
    5.48  	unsigned int op, unsigned int nr_args, ...)
    5.49  {
     6.1 --- a/xen/include/asm-ia64/mm.h	Fri Jun 17 18:28:39 2005 +0000
     6.2 +++ b/xen/include/asm-ia64/mm.h	Fri Jun 17 21:22:39 2005 +0000
     6.3 @@ -132,6 +132,7 @@ void add_to_domain_alloc_list(unsigned l
     6.4  
     6.5  static inline void put_page(struct pfn_info *page)
     6.6  {
     6.7 +#ifdef CONFIG_VTI	// doesn't work with non-VTI in grant tables yet
     6.8      u32 nx, x, y = page->count_info;
     6.9  
    6.10      do {
    6.11 @@ -142,12 +143,14 @@ static inline void put_page(struct pfn_i
    6.12  
    6.13      if (unlikely((nx & PGC_count_mask) == 0))
    6.14  	free_domheap_page(page);
    6.15 +#endif
    6.16  }
    6.17  
    6.18  /* count_info and ownership are checked atomically. */
    6.19  static inline int get_page(struct pfn_info *page,
    6.20                             struct domain *domain)
    6.21  {
    6.22 +#if 0
    6.23      u64 x, nx, y = *((u64*)&page->count_info);
    6.24      u32 _domain = pickle_domptr(domain);
    6.25  
    6.26 @@ -164,7 +167,7 @@ static inline int get_page(struct pfn_in
    6.27  	}
    6.28      }
    6.29      while(unlikely(y = cmpxchg(&page->count_info, x, nx)) != x);
    6.30 -
    6.31 +#endif
    6.32      return 1;
    6.33  }
    6.34