ChangeSet 1.1713.2.8, 2005/06/17 15:22:39-06:00, djm@xxxxxxxxxxxxxxx
Add preliminary grant table support (in arch/ia64 and turned
off for CONFIG_VTI for now)
arch/ia64/Makefile | 2
arch/ia64/grant_table.c | 1294 ++++++++++++++++++++++++++++++++++++++++++++++++
arch/ia64/hypercall.c | 6
arch/ia64/xenmisc.c | 31 +
include/asm-ia64/mm.h | 5
5 files changed, 1336 insertions(+), 2 deletions(-)
diff -Nru a/xen/arch/ia64/Makefile b/xen/arch/ia64/Makefile
--- a/xen/arch/ia64/Makefile 2005-06-23 07:03:29 -04:00
+++ b/xen/arch/ia64/Makefile 2005-06-23 07:03:29 -04:00
@@ -10,7 +10,7 @@
extable.o linuxextable.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 \
- sn_console.o
+ grant_table.o sn_console.o
ifeq ($(CONFIG_VTI),y)
OBJS += vmx_init.o vmx_virt.o vmx_vcpu.o vmx_process.o vmx_vsa.o vmx_ivt.o \
diff -Nru a/xen/arch/ia64/grant_table.c b/xen/arch/ia64/grant_table.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/xen/arch/ia64/grant_table.c 2005-06-23 07:03:29 -04:00
@@ -0,0 +1,1294 @@
+#ifndef CONFIG_VTI
+// 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
+ *
+ * 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: need to implement real cmpxchg_user on ia64
+#define cmpxchg_user(_p,_o,_n) ((*_p == _o) ? ((*_p = _n), 0) : ((_o = *_p),
0))
+// FIXME-ia64: the following are meaningless on ia64? move to some header file
+#define put_page(x) do { } while (0)
+#define put_page_type(x) do { } while (0)
+// 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
+
+#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) )
+ 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,
+ unsigned long host_virt_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_virt_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;
+
+ 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 reflect mapping.
+ * 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 ( (host_virt_addr != 0) && (dev_hst_ro_flags & GNTMAP_host_map) )
+ {
+ /* Write update into the pagetable. */
+ l1_pgentry_t pte;
+ pte = l1e_from_pfn(frame, _PAGE_PRESENT | _PAGE_ACCESSED |
_PAGE_DIRTY);
+ if ( !(dev_hst_ro_flags & GNTMAP_readonly) )
+ l1e_add_flags(pte,_PAGE_RW);
+ rc = update_grant_va_mapping( host_virt_addr, pte,
+ mapping_d, mapping_ed );
+
+ /*
+ * IMPORTANT: (rc == 0) => must flush / invalidate entry in TLB.
+ * 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.
+ */
+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;
+ unsigned long frame = 0, host_virt_addr;
+ 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(host_virt_addr, &uop->host_virt_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 ( ((host_virt_addr != 0) || (dev_hst_ro_flags & GNTMAP_host_map)) &&
+ unlikely(!__addr_ok(host_virt_addr)))
+ {
+ DPRINTK("Bad virtual address (%lx) or flags (%x).\n",
+ host_virt_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 ( 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;
+
+ /* 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;
+
+ printk("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,
+ host_virt_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(frame, &uop->dev_bus_addr);
+
+ if ( dev_hst_ro_flags & GNTMAP_host_map )
+ *va = host_virt_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, flush = 0;
+ unsigned long va = 0;
+
+ for ( i = 0; i < count; i++ )
+ if ( __gnttab_map_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 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;
+ unsigned long frame, virt;
+
+ ld = current->domain;
+
+ /* Bitwise-OR avoids short-circuiting which screws control flow. */
+ if ( unlikely(__get_user(virt, &uop->host_virt_addr) |
+ __get_user(frame, &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 */
+ }
+
+ 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 ( frame == GNTUNMAP_DEV_FROM_VIRT )
+ {
+ if ( !( flags & GNTMAP_device_map ) )
+ PIN_FAIL(unmap_out, GNTST_bad_dev_addr,
+ "Bad frame number: frame not mapped for dev access.\n");
+ frame = act->frame;
+
+ /* Frame will be unmapped for device access below if virt addr okay. */
+ }
+ 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. */
+ }
+
+#ifdef __ia64__
+// FIXME-ia64: any error checking need to be done here?
+#else
+ if ( (virt != 0) &&
+ (flags & GNTMAP_host_map) &&
+ ((act->pin & (GNTPIN_hstw_mask | GNTPIN_hstr_mask)) > 0))
+ {
+ l1_pgentry_t *pl1e;
+ unsigned long _ol1e;
+
+ pl1e = &linear_pg_table[l1_linear_offset(virt)];
+
+ if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
+ {
+ DPRINTK("Could not find PTE entry for address %lx\n", virt);
+ rc = -EINVAL;
+ goto unmap_out;
+ }
+
+ /*
+ * Check that the virtual address supplied is actually mapped to
+ * act->frame.
+ */
+ if ( unlikely((_ol1e >> PAGE_SHIFT) != frame ))
+ {
+ DPRINTK("PTE entry %lx for address %lx doesn't match frame %lx\n",
+ _ol1e, virt, frame);
+ rc = -EINVAL;
+ goto unmap_out;
+ }
+
+ /* Delete pagetable entry. */
+ if ( unlikely(__put_user(0, (unsigned long *)pl1e)))
+ {
+ DPRINTK("Cannot delete PTE entry at %p for virtual address %lx\n",
+ pl1e, virt);
+ rc = -EINVAL;
+ goto unmap_out;
+ }
+
+ map->ref_and_flags &= ~GNTMAP_host_map;
+
+ act->pin -= (flags & GNTMAP_readonly) ? GNTPIN_hstr_inc
+ : GNTPIN_hstw_inc;
+
+ if ( frame == GNTUNMAP_DEV_FROM_VIRT )
+ {
+ 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);
+ }
+
+ rc = 0;
+ *va = virt;
+ }
+#endif
+
+ 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 )
+ {
+ 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);
+ 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]);
+ }
+
+ 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:(%lx)\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
+
+long
+do_grant_table_op(
+ unsigned int cmd, void *uop, unsigned int count)
+{
+ long rc;
+
+ if ( count > 512 )
+ return -EINVAL;
+
+ LOCK_BIGLOCK(current->domain);
+
+ 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
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+
+out:
+ UNLOCK_BIGLOCK(current->domain);
+
+ return rc;
+}
+
+int
+gnttab_check_unmap(
+ struct domain *rd, struct domain *ld, unsigned long frame, int readonly)
+{
+ /* Called when put_page is invoked on a page belonging to a foreign domain.
+ * Instead of decrementing the frame table ref count, locate the grant
+ * table entry, if any, and if found, decrement that count.
+ * Called a _lot_ at domain creation because pages mapped by priv domains
+ * also traverse this.
+ */
+
+ /* Note: If the same frame is mapped multiple times, and then one of
+ * the ptes is overwritten, which maptrack handle gets invalidated?
+ * Advice: Don't do it. Explicitly unmap.
+ */
+
+ unsigned int handle, ref, refcount;
+ grant_table_t *lgt, *rgt;
+ active_grant_entry_t *act;
+ grant_mapping_t *map;
+ int found = 0;
+
+ lgt = ld->grant_table;
+
+#if GRANT_DEBUG_VERBOSE
+ if ( ld->domain_id != 0 )
+ {
+ DPRINTK("Foreign unref rd(%d) ld(%d) frm(%x) flgs(%x).\n",
+ rd->domain_id, ld->domain_id, frame, readonly);
+ }
+#endif
+
+ /* Fast exit if we're not mapping anything using grant tables */
+ if ( lgt->map_count == 0 )
+ return 0;
+
+ if ( get_domain(rd) == 0 )
+ {
+ DPRINTK("gnttab_check_unmap: couldn't get_domain rd(%d)\n",
+ rd->domain_id);
+ return 0;
+ }
+
+ rgt = rd->grant_table;
+
+ for ( handle = 0; handle < lgt->maptrack_limit; handle++ )
+ {
+ map = &lgt->maptrack[handle];
+
+ if ( ( map->ref_and_flags & MAPTRACK_GNTMAP_MASK ) &&
+ ( readonly ? 1 : (!(map->ref_and_flags & GNTMAP_readonly))))
+ {
+ ref = (map->ref_and_flags >> MAPTRACK_REF_SHIFT);
+ act = &rgt->active[ref];
+
+ spin_lock(&rgt->lock);
+
+ if ( act->frame != frame )
+ {
+ spin_unlock(&rgt->lock);
+ continue;
+ }
+
+ refcount = act->pin & ( readonly ? GNTPIN_hstr_mask
+ : GNTPIN_hstw_mask );
+ if ( refcount == 0 )
+ {
+ spin_unlock(&rgt->lock);
+ continue;
+ }
+
+ /* gotcha */
+ DPRINTK("Grant unref rd(%d) ld(%d) frm(%lx) flgs(%x).\n",
+ rd->domain_id, ld->domain_id, frame, readonly);
+
+ if ( readonly )
+ act->pin -= GNTPIN_hstr_inc;
+ else
+ {
+ act->pin -= GNTPIN_hstw_inc;
+
+ /* any more granted writable mappings? */
+ if ( (act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) == 0 )
+ {
+ clear_bit(_GTF_writing, &rgt->shared[ref].flags);
+ put_page_type(&frame_table[frame]);
+ }
+ }
+
+ if ( act->pin == 0 )
+ {
+ clear_bit(_GTF_reading, &rgt->shared[ref].flags);
+ put_page(&frame_table[frame]);
+ }
+ spin_unlock(&rgt->lock);
+
+ clear_bit(GNTMAP_host_map, &map->ref_and_flags);
+
+ if ( !(map->ref_and_flags & GNTMAP_device_map) )
+ put_maptrack_handle(lgt, handle);
+
+ found = 1;
+ break;
+ }
+ }
+ put_domain(rd);
+
+ return found;
+}
+
+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;
+
+ DPRINTK("gnttab_prepare_for_transfer rd(%hu) ld(%hu) ref(%hu).\n",
+ rd->domain_id, ld->domain_id, ref);
+
+ 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;
+
+ DPRINTK("gnttab_notify_transfer rd(%hu) ld(%hu) ref(%hu).\n",
+ rd->domain_id, ld->domain_id, ref);
+
+ 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);
+ if ( t->maptrack != NULL )
+ free_xenheap_page(t->maptrack);
+ xfree(t);
+ }
+ return -ENOMEM;
+}
+
+void
+gnttab_release_dev_mappings(grant_table_t *gt)
+{
+ 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;
+
+ ld = current->domain;
+
+ 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. */
+}
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Nru a/xen/arch/ia64/hypercall.c b/xen/arch/ia64/hypercall.c
--- a/xen/arch/ia64/hypercall.c 2005-06-23 07:03:29 -04:00
+++ b/xen/arch/ia64/hypercall.c 2005-06-23 07:03:29 -04:00
@@ -149,6 +149,12 @@
regs->r8 = do_event_channel_op(regs->r14);
break;
+#ifndef CONFIG_VTI
+ case __HYPERVISOR_grant_table_op:
+ regs->r8 = do_grant_table_op(regs->r14, regs->r15, regs->r16);
+ break;
+#endif
+
case __HYPERVISOR_console_io:
regs->r8 = do_console_io(regs->r14, regs->r15, regs->r16);
break;
diff -Nru a/xen/arch/ia64/xenmisc.c b/xen/arch/ia64/xenmisc.c
--- a/xen/arch/ia64/xenmisc.c 2005-06-23 07:03:29 -04:00
+++ b/xen/arch/ia64/xenmisc.c 2005-06-23 07:03:29 -04:00
@@ -62,8 +62,10 @@
void sync_lazy_execstate_mask(cpumask_t mask) {}
void sync_lazy_execstate_all(void) {}
+#ifdef CONFIG_VTI
int grant_table_create(struct domain *d) { return 0; }
void grant_table_destroy(struct domain *d) { return; }
+#endif
struct pt_regs *guest_cpu_user_regs(void) { return ia64_task_regs(current); }
@@ -71,6 +73,35 @@
{
raise_softirq(AC_TIMER_SOFTIRQ);
}
+
+#ifndef CONFIG_VTI
+unsigned long
+__gpfn_to_mfn_foreign(struct domain *d, unsigned long gpfn)
+{
+ if (d == dom0)
+ return(gpfn);
+ else {
+ unsigned long pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT);
+ if (!pte) {
+printk("__gpfn_to_mfn_foreign: bad gpfn. spinning...\n");
+while(1);
+ return 0;
+ }
+ return ((pte & _PFN_MASK) >> PAGE_SHIFT);
+ }
+}
+
+u32
+__mfn_to_gpfn(struct domain *d, unsigned long frame)
+{
+ // FIXME: is this right?
+if ((frame << PAGE_SHIFT) & _PAGE_PPN_MASK) {
+printk("__mfn_to_gpfn: bad frame. spinning...\n");
+while(1);
+}
+ return frame;
+}
+#endif
unsigned long __hypercall_create_continuation(
unsigned int op, unsigned int nr_args, ...)
diff -Nru a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h
--- a/xen/include/asm-ia64/mm.h 2005-06-23 07:03:29 -04:00
+++ b/xen/include/asm-ia64/mm.h 2005-06-23 07:03:29 -04:00
@@ -132,6 +132,7 @@
static inline void put_page(struct pfn_info *page)
{
+#ifdef CONFIG_VTI // doesn't work with non-VTI in grant tables yet
u32 nx, x, y = page->count_info;
do {
@@ -142,12 +143,14 @@
if (unlikely((nx & PGC_count_mask) == 0))
free_domheap_page(page);
+#endif
}
/* count_info and ownership are checked atomically. */
static inline int get_page(struct pfn_info *page,
struct domain *domain)
{
+#if 0
u64 x, nx, y = *((u64*)&page->count_info);
u32 _domain = pickle_domptr(domain);
@@ -164,7 +167,7 @@
}
}
while(unlikely(y = cmpxchg(&page->count_info, x, nx)) != x);
-
+#endif
return 1;
}
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|