[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 5 of 8] Introduce a grant_entry_v2 structure
# HG changeset patch # User Steven Smith <steven.smith@xxxxxxxxxxxxx> # Date 1222082608 -3600 # Node ID 842baf721920b032f358ad326145817b42d053a1 # Parent 1df819bcf08654a2f23e88ce22295caf7806d65c Introduce a grant_entry_v2 structure. Signed-off-by: Steven Smith <steven.smith@xxxxxxxxxx> diff -r 1df819bcf086 -r 842baf721920 tools/libxc/xc_linux.c --- a/tools/libxc/xc_linux.c Mon Sep 22 12:23:28 2008 +0100 +++ b/tools/libxc/xc_linux.c Mon Sep 22 12:23:28 2008 +0100 @@ -558,7 +558,21 @@ return ret; } -struct grant_entry_v1 *xc_gnttab_map_table(int xc_handle, int domid, int *gnt_num) +int xc_gnttab_get_version(int xc_handle, int domid) +{ + struct gnttab_get_version query; + int rc; + + query.dom = domid; + rc = xc_gnttab_op(xc_handle, GNTTABOP_get_version, + &query, sizeof(query), 1); + if (rc < 0) + return rc; + else + return query.version; +} + +static void *_gnttab_map_table(int xc_handle, int domid, int *gnt_num) { int rc, i; struct gnttab_query_size query; @@ -638,6 +652,22 @@ return gnt; } +struct grant_entry_v1 *xc_gnttab_map_table_v1(int xc_handle, int domid, + int *gnt_num) +{ + if (xc_gnttab_get_version(xc_handle, domid) == 2) + return NULL; + return _gnttab_map_table(xc_handle, domid, gnt_num); +} + +struct grant_entry_v2 *xc_gnttab_map_table_v2(int xc_handle, int domid, + int *gnt_num) +{ + if (xc_gnttab_get_version(xc_handle, domid) != 2) + return NULL; + return _gnttab_map_table(xc_handle, domid, gnt_num); +} + /* * Local variables: * mode: C diff -r 1df819bcf086 -r 842baf721920 tools/libxc/xc_offline_page.c --- a/tools/libxc/xc_offline_page.c Mon Sep 22 12:23:28 2008 +0100 +++ b/tools/libxc/xc_offline_page.c Mon Sep 22 12:23:28 2008 +0100 @@ -132,8 +132,8 @@ /* * There should no update to the grant when domain paused */ -static int xc_is_page_granted(int xc_handle, xen_pfn_t gpfn, - struct grant_entry_v1 *gnttab, int gnt_num) +static int xc_is_page_granted_v1(int xc_handle, xen_pfn_t gpfn, + struct grant_entry_v1 *gnttab, int gnt_num) { int i = 0; @@ -142,6 +142,22 @@ for (i = 0; i < gnt_num; i++) if ( ((gnttab[i].flags & GTF_type_mask) != GTF_invalid) && + (gnttab[i].frame == gpfn) ) + break; + + return (i != gnt_num); +} + +static int xc_is_page_granted_v2(int xc_handle, xen_pfn_t gpfn, + struct grant_entry_v2 *gnttab, int gnt_num) +{ + int i = 0; + + if (!gnttab) + return 0; + + for (i = 0; i < gnt_num; i++) + if ( ((gnttab[i].hdr.flags & GTF_type_mask) != GTF_invalid) && (gnttab[i].frame == gpfn) ) break; @@ -549,7 +565,8 @@ struct domain_mem_info minfo; struct xc_mmu *mmu = NULL; struct pte_backup old_ptes = {NULL, 0, 0}; - struct grant_entry_v1 *gnttab = NULL; + struct grant_entry_v1 *gnttab_v1 = NULL; + struct grant_entry_v2 *gnttab_v2 = NULL; struct mmuext_op mops; int gnt_num, unpined = 0; void *old_p, *backup = NULL; @@ -588,14 +605,20 @@ goto failed; } - gnttab = xc_gnttab_map_table(xc_handle, domid, &gnt_num); - if (!gnttab) + gnttab_v2 = xc_gnttab_map_table_v2(xc_handle, domid, &gnt_num); + if (!gnttab_v2) { - ERROR("Failed to map grant table\n"); - goto failed; + gnttab_v1 = xc_gnttab_map_table_v1(xc_handle, domid, &gnt_num); + if (!gnttab_v1) + { + ERROR("Failed to map grant table\n"); + goto failed; + } } - if (xc_is_page_granted(xc_handle, mfn, gnttab, gnt_num)) + if (gnttab_v1 + ? xc_is_page_granted_v1(xc_handle, mfn, gnttab_v1, gnt_num) + : xc_is_page_granted_v2(xc_handle, mfn, gnttab_v2, gnt_num)) { ERROR("Page %lx is granted now\n", mfn); goto failed; @@ -755,8 +778,10 @@ if (backup) free(backup); - if (gnttab) - munmap(gnttab, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v1))); + if (gnttab_v1) + munmap(gnttab_v1, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v1))); + if (gnttab_v2) + munmap(gnttab_v2, gnt_num / (PAGE_SIZE/sizeof(struct grant_entry_v2))); close_mem_info(xc_handle, &minfo); diff -r 1df819bcf086 -r 842baf721920 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Mon Sep 22 12:23:28 2008 +0100 +++ b/tools/libxc/xenctrl.h Mon Sep 22 12:23:28 2008 +0100 @@ -943,7 +943,9 @@ int xc_gnttab_op(int xc_handle, int cmd, void * op, int op_size, int count); -struct grant_entry_v1 *xc_gnttab_map_table(int xc_handle, int domid, int *gnt_num); +int xc_gnttab_get_version(int xc_handle, int domid); +struct grant_entry_v1 *xc_gnttab_map_table_v1(int xc_handle, int domid, int *gnt_num); +struct grant_entry_v2 *xc_gnttab_map_table_v2(int xc_handle, int domid, int *gnt_num); int xc_physdev_map_pirq(int xc_handle, int domid, diff -r 1df819bcf086 -r 842baf721920 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/arch/x86/hvm/hvm.c Mon Sep 22 12:23:28 2008 +0100 @@ -2084,12 +2084,26 @@ return hvm_intblk_none; } +static int grant_table_op_is_allowed(unsigned int cmd) +{ + switch (cmd) { + case GNTTABOP_query_size: + case GNTTABOP_setup_table: + case GNTTABOP_set_version: + case GNTTABOP_copy: + case GNTTABOP_map_grant_ref: + case GNTTABOP_unmap_grant_ref: + return 1; + default: + /* all other commands need auditing */ + return 0; + } +} + static long hvm_grant_table_op( unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count) { - if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) && - (cmd != GNTTABOP_map_grant_ref) && (cmd != GNTTABOP_unmap_grant_ref) && - (cmd != GNTTABOP_copy)) + if ( !grant_table_op_is_allowed(cmd) ) return -ENOSYS; /* all other commands need auditing */ return do_grant_table_op(cmd, uop, count); } @@ -2141,13 +2155,12 @@ #else /* defined(__x86_64__) */ -static long hvm_grant_table_op_compat32( - unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count) +static long hvm_grant_table_op_compat32(unsigned int cmd, + XEN_GUEST_HANDLE(void) uop, + unsigned int count) { - if ( (cmd != GNTTABOP_query_size) && (cmd != GNTTABOP_setup_table) && - (cmd != GNTTABOP_map_grant_ref) && (cmd != GNTTABOP_unmap_grant_ref) && - (cmd != GNTTABOP_copy)) - return -ENOSYS; /* all other commands need auditing */ + if ( !grant_table_op_is_allowed(cmd) ) + return -ENOSYS; return compat_grant_table_op(cmd, uop, count); } diff -r 1df819bcf086 -r 842baf721920 xen/arch/x86/mm.c --- a/xen/arch/x86/mm.c Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/arch/x86/mm.c Mon Sep 22 12:23:28 2008 +0100 @@ -4000,12 +4000,25 @@ case XENMAPSPACE_grant_table: spin_lock(&d->grant_table->lock); - if ( (xatp.idx >= nr_grant_frames(d->grant_table)) && - (xatp.idx < max_nr_grant_frames) ) - gnttab_grow_table(d, xatp.idx + 1); - - if ( xatp.idx < nr_grant_frames(d->grant_table) ) - mfn = virt_to_mfn(d->grant_table->shared[xatp.idx]); + if ( d->grant_table->gt_version == 0 ) + d->grant_table->gt_version = 1; + + if ( d->grant_table->gt_version == 2 && + (xatp.idx & XENMAPIDX_grant_table_status) ) + { + xatp.idx &= ~XENMAPIDX_grant_table_status; + if ( xatp.idx < nr_status_frames(d->grant_table) ) + mfn = virt_to_mfn(d->grant_table->status[xatp.idx]); + } + else + { + if ( (xatp.idx >= nr_grant_frames(d->grant_table)) && + (xatp.idx < max_nr_grant_frames) ) + gnttab_grow_table(d, xatp.idx + 1); + + if ( xatp.idx < nr_grant_frames(d->grant_table) ) + mfn = virt_to_mfn(d->grant_table->shared_raw[xatp.idx]); + } spin_unlock(&d->grant_table->lock); break; diff -r 1df819bcf086 -r 842baf721920 xen/common/compat/grant_table.c --- a/xen/common/compat/grant_table.c Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/common/compat/grant_table.c Mon Sep 22 12:23:28 2008 +0100 @@ -8,6 +8,14 @@ #define xen_grant_entry_v1 grant_entry_v1 CHECK_grant_entry_v1; #undef xen_grant_entry_v1 + +#define xen_grant_entry_header grant_entry_header +CHECK_grant_entry_header; +#undef xen_grant_entry_header + +#define xen_grant_entry_v2 grant_entry_v2 +CHECK_grant_entry_v2; +#undef xen_grant_entry_v2 #define xen_gnttab_map_grant_ref gnttab_map_grant_ref CHECK_gnttab_map_grant_ref; @@ -28,6 +36,16 @@ #define xen_gnttab_dump_table gnttab_dump_table CHECK_gnttab_dump_table; #undef xen_gnttab_dump_table + +#define xen_gnttab_set_version gnttab_set_version +CHECK_gnttab_set_version; +#undef xen_gnttab_set_version + +DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_compat_t); + +#define xen_gnttab_get_version gnttab_get_version +CHECK_gnttab_get_version; +#undef xen_gnttab_get_version int compat_grant_table_op(unsigned int cmd, XEN_GUEST_HANDLE(void) cmp_uop, @@ -76,6 +94,10 @@ CASE(dump_table); #endif +#ifndef CHECK_gnttab_get_status_frames + CASE(get_status_frames); +#endif + #undef CASE default: return do_grant_table_op(cmd, cmp_uop, count); @@ -92,11 +114,13 @@ struct gnttab_setup_table *setup; struct gnttab_transfer *xfer; struct gnttab_copy *copy; + struct gnttab_get_status_frames *get_status; } nat; union { struct compat_gnttab_setup_table setup; struct compat_gnttab_transfer xfer; struct compat_gnttab_copy copy; + struct compat_gnttab_get_status_frames get_status; } cmp; set_xen_guest_handle(nat.uop, COMPAT_ARG_XLAT_VIRT_BASE); @@ -233,6 +257,63 @@ } break; + case GNTTABOP_get_status_frames: { + unsigned int max_frame_list_size_in_pages = + (COMPAT_ARG_XLAT_SIZE - sizeof(*nat.get_status)) / + sizeof(*nat.get_status->frame_list.p); + if ( count != 1) + { + rc = -EINVAL; + break; + } + if ( unlikely(__copy_from_guest(&cmp.get_status, cmp_uop, 1) || + !compat_handle_okay(cmp.get_status.frame_list, + cmp.get_status.nr_frames)) ) + { + rc = -EFAULT; + break; + } + if ( max_frame_list_size_in_pages < + grant_to_status_frames(max_nr_grant_frames) ) + { + gdprintk(XENLOG_WARNING, + "grant_to_status_frames(max_nr_grant_frames) is too large (%u,%u)\n", + grant_to_status_frames(max_nr_grant_frames), + max_frame_list_size_in_pages); + rc = -EINVAL; + break; + } + +#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \ + set_xen_guest_handle((_d_)->frame_list, (uint64_t *)(nat.get_status + 1)) + XLAT_gnttab_get_status_frames(nat.get_status, &cmp.get_status); +#undef XLAT_gnttab_get_status_frames_HNDL_frame_list + + rc = gnttab_get_status_frames( + guest_handle_cast(nat.uop, gnttab_get_status_frames_t), + count); + if ( rc >= 0 ) + { +#define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \ + do \ + { \ + if ( (_s_)->status == GNTST_okay ) \ + { \ + for ( i = 0; i < (_s_)->nr_frames; ++i ) \ + { \ + uint64_t frame = (_s_)->frame_list.p[i]; \ + (void)__copy_to_compat_offset((_d_)->frame_list, i, &frame, 1); \ + } \ + } \ + } while (0) + XLAT_gnttab_get_status_frames(&cmp.get_status, nat.get_status); +#undef XLAT_gnttab_get_status_frames_HNDL_frame_list + if ( unlikely(__copy_to_guest(cmp_uop, &cmp.get_status, 1)) ) + rc = -EFAULT; + } + break; + } + default: domain_crash(current->domain); break; diff -r 1df819bcf086 -r 842baf721920 xen/common/grant_table.c --- a/xen/common/grant_table.c Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/common/grant_table.c Mon Sep 22 12:23:28 2008 +0100 @@ -105,9 +105,24 @@ } -#define SHGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v1_t)) -#define shared_entry(t, e) \ - ((t)->shared[(e)/SHGNT_PER_PAGE][(e)%SHGNT_PER_PAGE]) +#define SHGNT_PER_PAGE_V1 (PAGE_SIZE / sizeof(grant_entry_v1_t)) +#define shared_entry_v1(t, e) \ + ((t)->shared_v1[(e)/SHGNT_PER_PAGE_V1][(e)%SHGNT_PER_PAGE_V1]) +#define SHGNT_PER_PAGE_V2 (PAGE_SIZE / sizeof(grant_entry_v2_t)) +#define shared_entry_v2(t, e) \ + ((t)->shared_v2[(e)/SHGNT_PER_PAGE_V2][(e)%SHGNT_PER_PAGE_V2]) +#define STGNT_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) +#define status_entry(t, e) \ + ((t)->status[(e)/STGNT_PER_PAGE][(e)%STGNT_PER_PAGE]) +static grant_entry_header_t * +shared_entry_header(struct grant_table *t, grant_ref_t ref) +{ + ASSERT(t->gt_version != 0); + if (t->gt_version == 1) + return (grant_entry_header_t*)&shared_entry_v1(t, ref); + else + return &shared_entry_v2(t, ref).hdr; +} #define ACGNT_PER_PAGE (PAGE_SIZE / sizeof(struct active_grant_entry)) #define active_entry(t, e) \ ((t)->active[(e)/ACGNT_PER_PAGE][(e)%ACGNT_PER_PAGE]) @@ -183,6 +198,174 @@ return handle; } +/* Number of grant table entries. Caller must hold d's grant table lock. */ +static unsigned int nr_grant_entries(struct grant_table *gt) +{ + ASSERT(gt->gt_version != 0); + if (gt->gt_version == 1) + return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v1_t); + else + return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v2_t); +} + +static int _set_status_v1(domid_t domid, + int readonly, + grant_entry_header_t *shah, + struct active_grant_entry *act) +{ + int rc = GNTST_okay; + union grant_combo scombo, prev_scombo, new_scombo; + uint16_t mask = GTF_type_mask; + + /* + * 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. + */ + int retries = 0; + + scombo.word = *(u32 *)shah; + + /* + * This loop attempts to set the access (reading/writing) flags + * in the grant table entry. It tries a cmpxchg on the field + * up to five times, and then fails under the assumption that + * the guest is misbehaving. + */ + for ( ; ; ) + { + /* If not already pinned, check the grant domid and type. */ + if ( !act->pin && + (((scombo.shorts.flags & mask) != + GTF_permit_access) || + (scombo.shorts.domid != domid)) ) + PIN_FAIL(done, GNTST_general_error, + "Bad flags (%x) or dom (%d). (expected dom %d)\n", + scombo.shorts.flags, scombo.shorts.domid, + domid); + + new_scombo = scombo; + new_scombo.shorts.flags |= GTF_reading; + + if ( !readonly ) + { + new_scombo.shorts.flags |= GTF_writing; + if ( unlikely(scombo.shorts.flags & GTF_readonly) ) + PIN_FAIL(done, GNTST_general_error, + "Attempt to write-pin a r/o grant entry.\n"); + } + + prev_scombo.word = cmpxchg((u32 *)shah, + scombo.word, new_scombo.word); + if ( likely(prev_scombo.word == scombo.word) ) + break; + + if ( retries++ == 4 ) + PIN_FAIL(done, GNTST_general_error, + "Shared grant entry is unstable.\n"); + + scombo = prev_scombo; + } + +done: + return rc; +} + +static int _set_status_v2(domid_t domid, + int readonly, + grant_entry_header_t *shah, + struct active_grant_entry *act, + grant_status_t *status) +{ + int rc = GNTST_okay; + union grant_combo scombo; + uint16_t flags = shah->flags; + domid_t id = shah->domid; + uint16_t mask = GTF_type_mask; + + /* we read flags and domid in a single memory access. + this avoids the need for another memory barrier to + ensure access to these fields are not reordered */ + scombo.word = *(u32 *)shah; + barrier(); /* but we still need to stop the compiler from turning + it back into two reads */ + flags = scombo.shorts.flags; + id = scombo.shorts.domid; + + /* If not already pinned, check the grant domid and type. */ + if ( !act->pin && + (((flags & mask) != GTF_permit_access) || + (id != domid)) ) + PIN_FAIL(done, GNTST_general_error, + "Bad flags (%x) or dom (%d). (expected dom %d)\n", + flags, id, domid); + + if ( readonly ) + { + *status |= GTF_reading; + } + else + { + if ( unlikely(flags & GTF_readonly) ) + PIN_FAIL(done, GNTST_general_error, + "Attempt to write-pin a r/o grant entry.\n"); + *status |= GTF_reading | GTF_writing; + } + + /* Make sure guest sees status update before checking if flags are + still valid */ + mb(); + + scombo.word = *(u32 *)shah; + barrier(); + flags = scombo.shorts.flags; + id = scombo.shorts.domid; + + if ( !act->pin ) + { + if ( ((flags & mask) != GTF_permit_access) || + (id != domid) || + (!readonly && (flags & GTF_readonly)) ) + { + gnttab_clear_flag(_GTF_reading | _GTF_writing, status); + PIN_FAIL(done, GNTST_general_error, + "Unstable flags (%x) or dom (%d). (expected dom %d) " + "(r/w: %d)\n", + flags, id, domid, !readonly); + } + } + else + { + if ( unlikely(flags & GTF_readonly) ) + { + gnttab_clear_flag(_GTF_writing, status); + PIN_FAIL(done, GNTST_general_error, + "Unstable grant readonly flag\n"); + } + } + +done: + return rc; +} + + +static int _set_status(unsigned gt_version, + domid_t domid, + int readonly, + grant_entry_header_t *shah, + struct active_grant_entry *act, + grant_status_t *status) +{ + + if (gt_version == 1) + return _set_status_v1(domid, readonly, shah, act); + else + return _set_status_v2(domid, readonly, shah, act, status); +} + /* * Returns 0 if TLB flush / invalidate required by caller. * va will indicate the address to be invalidated. @@ -205,18 +388,10 @@ unsigned int cache_flags; struct active_grant_entry *act; struct grant_mapping *mt; - grant_entry_v1_t *sha; - union grant_combo scombo, prev_scombo, new_scombo; - - /* - * 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. - */ - int retries = 0; + grant_entry_v1_t *sha1; + grant_entry_v2_t *sha2; + grant_entry_header_t *shah; + uint16_t *status; led = current; ld = led->domain; @@ -262,12 +437,25 @@ spin_lock(&rd->grant_table->lock); + if ( rd->grant_table->gt_version == 0 ) + PIN_FAIL(unlock_out, GNTST_general_error, + "remote grant table not yet set up"); + /* Bounds check on the grant ref */ if ( unlikely(op->ref >= nr_grant_entries(rd->grant_table))) PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad ref (%d).\n", op->ref); act = &active_entry(rd->grant_table, op->ref); - sha = &shared_entry(rd->grant_table, op->ref); + shah = shared_entry_header(rd->grant_table, op->ref); + if (rd->grant_table->gt_version == 1) { + sha1 = &shared_entry_v1(rd->grant_table, op->ref); + sha2 = NULL; + status = &shah->flags; + } else { + sha2 = &shared_entry_v2(rd->grant_table, op->ref); + sha1 = NULL; + status = &status_entry(rd->grant_table, op->ref); + } /* If already pinned, check the active domid and avoid refcnt overflow. */ if ( act->pin && @@ -281,54 +469,19 @@ (!(op->flags & GNTMAP_readonly) && !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask))) ) { - scombo.word = *(u32 *)&sha->flags; - - /* - * This loop attempts to set the access (reading/writing) flags - * in the grant table entry. It tries a cmpxchg on the field - * up to five times, and then fails under the assumption that - * the guest is misbehaving. - */ - for ( ; ; ) - { - /* If not already pinned, check the grant domid and type. */ - if ( !act->pin && - (((scombo.shorts.flags & GTF_type_mask) != - GTF_permit_access) || - (scombo.shorts.domid != ld->domain_id)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Bad flags (%x) or dom (%d). (expected dom %d)\n", - scombo.shorts.flags, scombo.shorts.domid, - ld->domain_id); - - new_scombo = scombo; - new_scombo.shorts.flags |= GTF_reading; - - if ( !(op->flags & GNTMAP_readonly) ) - { - new_scombo.shorts.flags |= GTF_writing; - if ( unlikely(scombo.shorts.flags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - } - - prev_scombo.word = cmpxchg((u32 *)&sha->flags, - scombo.word, new_scombo.word); - if ( likely(prev_scombo.word == scombo.word) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - scombo = prev_scombo; - } + if ( (rc = _set_status(rd->grant_table->gt_version, + ld->domain_id, op->flags & GNTMAP_readonly, + shah, act, status) ) != GNTST_okay ) + goto unlock_out; if ( !act->pin ) { - act->domid = scombo.shorts.domid; - act->gfn = sha->frame; - act->frame = gmfn_to_mfn(rd, sha->frame); + act->domid = ld->domain_id; + if ( sha1 ) + act->gfn = sha1->frame; + else + act->gfn = sha2->full_page.frame; + act->frame = gmfn_to_mfn(rd, act->gfn); } } @@ -343,7 +496,7 @@ frame = act->frame; act_pin = act->pin; - cache_flags = (sha->flags & (GTF_PAT | GTF_PWT | GTF_PCD) ); + cache_flags = (shah->flags & (GTF_PAT | GTF_PWT | GTF_PCD) ); spin_unlock(&rd->grant_table->lock); @@ -457,7 +610,7 @@ spin_lock(&rd->grant_table->lock); act = &active_entry(rd->grant_table, op->ref); - sha = &shared_entry(rd->grant_table, op->ref); + shah = shared_entry_header(rd->grant_table, op->ref); if ( op->flags & GNTMAP_device_map ) act->pin -= (op->flags & GNTMAP_readonly) ? @@ -468,10 +621,10 @@ if ( !(op->flags & GNTMAP_readonly) && !(act->pin & (GNTPIN_hstw_mask|GNTPIN_devw_mask)) ) - gnttab_clear_flag(_GTF_writing, &sha->flags); + gnttab_clear_flag(_GTF_writing, status); if ( !act->pin ) - gnttab_clear_flag(_GTF_reading, &sha->flags); + gnttab_clear_flag(_GTF_reading, status); unlock_out: spin_unlock(&rd->grant_table->lock); @@ -508,7 +661,6 @@ domid_t dom; struct domain *ld, *rd; struct active_grant_entry *act; - grant_entry_v1_t *sha; s16 rc = 0; u32 old_pin; @@ -556,7 +708,6 @@ spin_lock(&rd->grant_table->lock); act = &active_entry(rd->grant_table, op->map->ref); - sha = &shared_entry(rd->grant_table, op->map->ref); old_pin = act->pin; if ( op->frame == 0 ) @@ -622,8 +773,9 @@ { struct domain *ld, *rd; struct active_grant_entry *act; - grant_entry_v1_t *sha; + grant_entry_header_t *sha; struct page_info *pg; + uint16_t *status; rd = op->rd; @@ -642,8 +794,16 @@ rcu_lock_domain(rd); spin_lock(&rd->grant_table->lock); + if ( rd->grant_table->gt_version == 0 ) + goto unmap_out; + act = &active_entry(rd->grant_table, op->map->ref); - sha = &shared_entry(rd->grant_table, op->map->ref); + sha = shared_entry_header(rd->grant_table, op->map->ref); + + if ( rd->grant_table->gt_version == 1 ) + status = &sha->flags; + else + status = &status_entry(rd->grant_table, op->map->ref); if ( unlikely(op->frame != act->frame) ) { @@ -694,10 +854,10 @@ if ( ((act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0) && !(op->flags & GNTMAP_readonly) ) - gnttab_clear_flag(_GTF_writing, &sha->flags); + gnttab_clear_flag(_GTF_writing, status); if ( act->pin == 0 ) - gnttab_clear_flag(_GTF_reading, &sha->flags); + gnttab_clear_flag(_GTF_reading, status); unmap_out: spin_unlock(&rd->grant_table->lock); @@ -829,6 +989,50 @@ return -EFAULT; } +static int +gnttab_populate_status_frames(struct domain *d, struct grant_table *gt) +{ + unsigned i; + unsigned req_status_frames; + + req_status_frames = grant_to_status_frames(gt->nr_grant_frames); + for ( i = nr_status_frames(gt); i < req_status_frames; i++ ) + { + if ( (gt->status[i] = alloc_xenheap_page()) == NULL ) + goto status_alloc_failed; + clear_page(gt->status[i]); + } + /* Share the new status frames with the recipient domain */ + for ( i = nr_status_frames(gt); i < req_status_frames; i++ ) + gnttab_create_status_page(d, gt, i); + + gt->nr_status_frames = req_status_frames; + + return 0; + +status_alloc_failed: + for ( i = nr_status_frames(gt); i < req_status_frames; i++ ) + { + free_xenheap_page(gt->status[i]); + gt->status[i] = NULL; + } + return -ENOMEM; +} + +static void +gnttab_unpopulate_status_frames(struct domain *d, struct grant_table *gt) +{ + int i; + + for ( i = 0; i < nr_status_frames(gt); i++ ) + { + page_set_owner(virt_to_page(gt->status[i]), dom_xen); + free_xenheap_page(gt->status[i]); + gt->status[i] = NULL; + } + gt->nr_status_frames = 0; +} + int gnttab_grow_table(struct domain *d, unsigned int req_nr_frames) { @@ -855,9 +1059,9 @@ /* Shared */ for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ ) { - if ( (gt->shared[i] = alloc_xenheap_page()) == NULL ) + if ( (gt->shared_raw[i] = alloc_xenheap_page()) == NULL ) goto shared_alloc_failed; - clear_page(gt->shared[i]); + clear_page(gt->shared_raw[i]); } /* Share the new shared frames with the recipient domain */ @@ -866,13 +1070,20 @@ gt->nr_grant_frames = req_nr_frames; + /* Status pages - version 2 */ + if (gt->gt_version > 1) + { + if ( gnttab_populate_status_frames(d, gt) ) + goto shared_alloc_failed; + } + return 1; shared_alloc_failed: for ( i = nr_grant_frames(gt); i < req_nr_frames; i++ ) { - free_xenheap_page(gt->shared[i]); - gt->shared[i] = NULL; + free_xenheap_page(gt->shared_raw[i]); + gt->shared_raw[i] = NULL; } active_alloc_failed: for ( i = nr_active_grant_frames(gt); @@ -942,7 +1153,13 @@ spin_lock(&d->grant_table->lock); - if ( (op.nr_frames > nr_grant_frames(d->grant_table)) && + if ( d->grant_table->gt_version == 0 ) + d->grant_table->gt_version = 1; + + if ( (op.nr_frames > nr_grant_frames(d->grant_table) || + ( (d->grant_table->gt_version > 1 ) && + (grant_to_status_frames(op.nr_frames) > + nr_status_frames(d->grant_table)) ) ) && !gnttab_grow_table(d, op.nr_frames) ) { gdprintk(XENLOG_INFO, @@ -1046,7 +1263,7 @@ struct domain *rd, struct domain *ld, grant_ref_t ref) { struct grant_table *rgt; - struct grant_entry_v1 *sha; + grant_entry_header_t *sha; union grant_combo scombo, prev_scombo, new_scombo; int retries = 0; @@ -1058,6 +1275,14 @@ spin_lock(&rgt->lock); + if ( rgt->gt_version == 0 ) + { + gdprintk(XENLOG_INFO, + "Grant table not ready for transfer to domain(%d).\n", + rd->domain_id); + goto fail; + } + if ( unlikely(ref >= nr_grant_entries(rd->grant_table)) ) { gdprintk(XENLOG_INFO, @@ -1066,7 +1291,7 @@ goto fail; } - sha = &shared_entry(rgt, ref); + sha = shared_entry_header(rgt, ref); scombo.word = *(u32 *)&sha->flags; @@ -1115,7 +1340,6 @@ struct domain *e; struct page_info *page; int i; - grant_entry_v1_t *sha; struct gnttab_transfer gop; unsigned long mfn; unsigned int max_bitsize; @@ -1248,11 +1472,21 @@ /* Tell the guest about its new page frame. */ spin_lock(&e->grant_table->lock); - sha = &shared_entry(e->grant_table, gop.ref); - guest_physmap_add_page(e, sha->frame, mfn, 0); - sha->frame = mfn; + if ( e->grant_table->gt_version == 1 ) + { + grant_entry_v1_t *sha = &shared_entry_v1(e->grant_table, gop.ref); + guest_physmap_add_page(e, sha->frame, mfn, 0); + sha->frame = mfn; + } + else + { + grant_entry_v2_t *sha = &shared_entry_v2(e->grant_table, gop.ref); + guest_physmap_add_page(e, sha->full_page.frame, mfn, 0); + sha->full_page.frame = mfn; + } wmb(); - sha->flags |= GTF_transfer_completed; + shared_entry_header(e->grant_table, gop.ref)->flags |= + GTF_transfer_completed; spin_unlock(&e->grant_table->lock); @@ -1278,15 +1512,21 @@ __release_grant_for_copy( struct domain *rd, unsigned long gref, int readonly) { - grant_entry_v1_t *sha; + grant_entry_header_t *sha; struct active_grant_entry *act; unsigned long r_frame; + uint16_t *status; spin_lock(&rd->grant_table->lock); act = &active_entry(rd->grant_table, gref); - sha = &shared_entry(rd->grant_table, gref); + sha = shared_entry_header(rd->grant_table, gref); r_frame = act->frame; + + if (rd->grant_table->gt_version == 1) + status = &sha->flags; + else + status = &status_entry(rd->grant_table, gref); if ( readonly ) { @@ -1298,11 +1538,11 @@ act->pin -= GNTPIN_hstw_inc; if ( !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) ) - gnttab_clear_flag(_GTF_writing, &sha->flags); + gnttab_clear_flag(_GTF_writing, status); } if ( !act->pin ) - gnttab_clear_flag(_GTF_reading, &sha->flags); + gnttab_clear_flag(_GTF_reading, status); spin_unlock(&rd->grant_table->lock); } @@ -1316,21 +1556,38 @@ struct domain *rd, unsigned long gref, int readonly, unsigned long *frame) { - grant_entry_v1_t *sha; + grant_entry_v1_t *sha1; + grant_entry_v2_t *sha2; + grant_entry_header_t *shah; struct active_grant_entry *act; + grant_status_t *status; s16 rc = GNTST_okay; - int retries = 0; - union grant_combo scombo, prev_scombo, new_scombo; spin_lock(&rd->grant_table->lock); + + if ( rd->grant_table->gt_version == 0 ) + PIN_FAIL(unlock_out, GNTST_general_error, + "remote grant table not ready\n"); if ( unlikely(gref >= nr_grant_entries(rd->grant_table)) ) PIN_FAIL(unlock_out, GNTST_bad_gntref, "Bad grant reference %ld\n", gref); act = &active_entry(rd->grant_table, gref); - sha = &shared_entry(rd->grant_table, gref); - + shah = shared_entry_header(rd->grant_table, gref); + if ( rd->grant_table->gt_version == 1 ) + { + sha1 = &shared_entry_v1(rd->grant_table, gref); + sha2 = NULL; + status = &shah->flags; + } + else + { + sha1 = NULL; + sha2 = &shared_entry_v2(rd->grant_table, gref); + status = &status_entry(rd->grant_table, gref); + } + /* If already pinned, check the active domid and avoid refcnt overflow. */ if ( act->pin && ((act->domid != current->domain->domain_id) || @@ -1342,48 +1599,18 @@ if ( !act->pin || (!readonly && !(act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask))) ) { - scombo.word = *(u32 *)&sha->flags; - - for ( ; ; ) - { - /* If not already pinned, check the grant domid and type. */ - if ( !act->pin && - (((scombo.shorts.flags & GTF_type_mask) != - GTF_permit_access) || - (scombo.shorts.domid != current->domain->domain_id)) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Bad flags (%x) or dom (%d). (expected dom %d)\n", - scombo.shorts.flags, scombo.shorts.domid, - current->domain->domain_id); - - new_scombo = scombo; - new_scombo.shorts.flags |= GTF_reading; - - if ( !readonly ) - { - new_scombo.shorts.flags |= GTF_writing; - if ( unlikely(scombo.shorts.flags & GTF_readonly) ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Attempt to write-pin a r/o grant entry.\n"); - } - - prev_scombo.word = cmpxchg((u32 *)&sha->flags, - scombo.word, new_scombo.word); - if ( likely(prev_scombo.word == scombo.word) ) - break; - - if ( retries++ == 4 ) - PIN_FAIL(unlock_out, GNTST_general_error, - "Shared grant entry is unstable.\n"); - - scombo = prev_scombo; - } - + if ( (rc = _set_status(rd->grant_table->gt_version, + current->domain->domain_id, + readonly, shah, act, status) ) != GNTST_okay ) + goto unlock_out; if ( !act->pin ) { - act->domid = scombo.shorts.domid; - act->gfn = sha->frame; - act->frame = gmfn_to_mfn(rd, sha->frame); + act->domid = current->domain->domain_id; + if ( sha1 ) + act->gfn = sha1->frame; + else + act->gfn = sha2->full_page.frame; + act->frame = gmfn_to_mfn(rd, act->gfn); } } @@ -1528,6 +1755,165 @@ return 0; } +static long +gnttab_set_version(XEN_GUEST_HANDLE(gnttab_set_version_t uop)) +{ + gnttab_set_version_t op; + struct domain *d = current->domain; + struct grant_table *gt = d->grant_table; + struct active_grant_entry *act; + long res = 0; + int i; + + if (copy_from_guest(&op, uop, 1)) + return -EFAULT; + + if (op.version != 1 && op.version != 2) + return -EINVAL; + + spin_lock(>->lock); + /* Make sure that the grant table isn't currently in use when we + change the version number. */ + /* (You need to change the version number for e.g. kexec.) */ + if ( gt->gt_version != 0 ) + { + for ( i = 0; i < nr_grant_entries(gt); i++ ) + { + act = &active_entry(gt, i); + if ( act->pin != 0 ) + { + gdprintk(XENLOG_WARNING, + "tried to change grant table version from %d to %d, but some grant entries still in use\n", + gt->gt_version, + op.version); + res = -EBUSY; + goto out; + } + } + } + + /* XXX: If we're going to version 2, we could maybe shrink the + active grant table here. */ + + if ( op.version == 2 && gt->gt_version < 2 ) + { + res = gnttab_populate_status_frames(d, gt); + if ( res < 0) + goto out; + } + + if ( op.version < 2 && gt->gt_version == 2 ) + gnttab_unpopulate_status_frames(d, gt); + + if ( op.version != gt->gt_version ) + { + /* Make sure there's no crud left over in the table from the + old version. */ + for ( i = 0; i < nr_grant_frames(gt); i++ ) + memset(gt->shared_raw[i], 0, PAGE_SIZE); + } + + gt->gt_version = op.version; + +out: + spin_unlock(>->lock); + + return res; +} + +static long +gnttab_get_status_frames(XEN_GUEST_HANDLE(gnttab_get_status_frames_t) uop, + int count) +{ + gnttab_get_status_frames_t op; + struct domain *d; + struct grant_table *gt; + uint64_t gmfn; + int i; + int rc; + + if ( count != 1 ) + return -EINVAL; + + if ( unlikely(copy_from_guest(&op, uop, 1) != 0) ) + { + gdprintk(XENLOG_INFO, + "Fault while reading gnttab_get_status_frames_t.\n"); + return -EFAULT; + } + + rc = rcu_lock_target_domain_by_id(op.dom, &d); + if ( rc < 0 ) + { + if ( rc == -ESRCH ) + op.status = GNTST_bad_domain; + else if ( rc == -EPERM ) + op.status = GNTST_permission_denied; + else + op.status = GNTST_general_error; + goto out1; + } + + gt = d->grant_table; + + if ( unlikely(op.nr_frames > nr_status_frames(gt)) ) { + gdprintk(XENLOG_INFO, "Guest requested addresses for %d grant status " + "frames, but only %d are available.\n", + op.nr_frames, nr_status_frames(gt)); + op.status = GNTST_general_error; + goto out2; + } + + op.status = GNTST_okay; + + spin_lock(>->lock); + + for ( i = 0; i < op.nr_frames; i++ ) + { + gmfn = gnttab_status_gmfn(d, d->grant_table, i); + if (copy_to_guest_offset(op.frame_list, + i, + &gmfn, + 1)) + op.status = GNTST_bad_virt_addr; + } + + spin_unlock(>->lock); +out2: + rcu_unlock_domain(d); +out1: + if ( unlikely(copy_to_guest(uop, &op, 1)) ) + return -EFAULT; + + return 0; +} + +static long +gnttab_get_version(XEN_GUEST_HANDLE(gnttab_get_version_t uop)) +{ + gnttab_get_version_t op; + struct domain *d; + + if ( copy_from_guest(&op, uop, 1) ) + return -EFAULT; + d = rcu_lock_domain_by_id(op.dom); + if ( d == NULL ) + return -ESRCH; + if ( !IS_PRIV_FOR(current->domain, d) ) + { + rcu_unlock_domain(d); + return -EPERM; + } + spin_lock(&d->grant_table->lock); + op.version = d->grant_table->gt_version; + spin_unlock(&d->grant_table->lock); + + if ( copy_to_guest(uop, &op, 1) ) + return -EFAULT; + else + return 0; +} + long do_grant_table_op( unsigned int cmd, XEN_GUEST_HANDLE(void) uop, unsigned int count) @@ -1630,6 +2016,22 @@ ASSERT(rc <= 0); break; } + case GNTTABOP_set_version: + { + rc = gnttab_set_version(guest_handle_cast(uop, gnttab_set_version_t)); + break; + } + case GNTTABOP_get_status_frames: + { + rc = gnttab_get_status_frames( + guest_handle_cast(uop, gnttab_get_status_frames_t), count); + break; + } + case GNTTABOP_get_version: + { + rc = gnttab_get_version(guest_handle_cast(uop, gnttab_get_version_t)); + break; + } default: rc = -ENOSYS; break; @@ -1666,9 +2068,6 @@ struct grant_table *t; int i; - /* If this sizeof assertion fails, fix the function: shared_index */ - ASSERT(sizeof(grant_entry_v1_t) == 8); - if ( (t = xmalloc(struct grant_table)) == NULL ) goto no_mem_0; @@ -1703,19 +2102,27 @@ t->maptrack[0][i].ref = i+1; /* Shared grant table. */ - if ( (t->shared = xmalloc_array(struct grant_entry_v1 *, - max_nr_grant_frames)) == NULL ) + if ( (t->shared_raw = xmalloc_array(void *, max_nr_grant_frames)) == NULL ) goto no_mem_3; - memset(t->shared, 0, max_nr_grant_frames * sizeof(t->shared[0])); + memset(t->shared_raw, 0, max_nr_grant_frames * sizeof(t->shared_raw[0])); for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ ) { - if ( (t->shared[i] = alloc_xenheap_page()) == NULL ) + if ( (t->shared_raw[i] = alloc_xenheap_page()) == NULL ) goto no_mem_4; - clear_page(t->shared[i]); + clear_page(t->shared_raw[i]); } for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ ) gnttab_create_shared_page(d, t, i); + + /* Status pages for grant table - for version 2 */ + t->status = xmalloc_array(grant_status_t *, + grant_to_status_frames(max_nr_grant_frames)); + if ( t->status == NULL ) + goto no_mem_4; + memset(t->status, 0, + grant_to_status_frames(max_nr_grant_frames) * sizeof(t->status[0])); + t->nr_status_frames = 0; /* Okay, install the structure. */ d->grant_table = t; @@ -1723,8 +2130,8 @@ no_mem_4: for ( i = 0; i < INITIAL_NR_GRANT_FRAMES; i++ ) - free_xenheap_page(t->shared[i]); - xfree(t->shared); + free_xenheap_page(t->shared_raw[i]); + xfree(t->shared_raw); no_mem_3: free_xenheap_page(t->maptrack[0]); xfree(t->maptrack); @@ -1749,7 +2156,8 @@ grant_handle_t handle; struct domain *rd; struct active_grant_entry *act; - struct grant_entry_v1*sha; + grant_entry_header_t *sha; + uint16_t *status; struct page_info *pg; BUG_ON(!d->is_dying); @@ -1777,7 +2185,12 @@ spin_lock(&rd->grant_table->lock); act = &active_entry(rd->grant_table, ref); - sha = &shared_entry(rd->grant_table, ref); + sha = shared_entry_header(rd->grant_table, ref); + if (rd->grant_table->gt_version == 1) + status = &sha->flags; + else + status = &status_entry(rd->grant_table, ref); + pg = mfn_to_page(act->frame); if ( map->flags & GNTMAP_readonly ) @@ -1823,11 +2236,11 @@ } if ( (act->pin & (GNTPIN_devw_mask|GNTPIN_hstw_mask)) == 0 ) - gnttab_clear_flag(_GTF_writing, &sha->flags); + gnttab_clear_flag(_GTF_writing, status); } if ( act->pin == 0 ) - gnttab_clear_flag(_GTF_reading, &sha->flags); + gnttab_clear_flag(_GTF_reading, status); spin_unlock(&rd->grant_table->lock); @@ -1849,8 +2262,8 @@ return; for ( i = 0; i < nr_grant_frames(t); i++ ) - free_xenheap_page(t->shared[i]); - xfree(t->shared); + free_xenheap_page(t->shared_raw[i]); + xfree(t->shared_raw); for ( i = 0; i < nr_maptrack_frames(t); i++ ) free_xenheap_page(t->maptrack[i]); @@ -1859,6 +2272,10 @@ for ( i = 0; i < nr_active_grant_frames(t); i++ ) free_xenheap_page(t->active[i]); xfree(t->active); + + for ( i = 0; i < nr_status_frames(t); i++ ) + free_xenheap_page(t->status[i]); + xfree(t->status); xfree(t); d->grant_table = NULL; diff -r 1df819bcf086 -r 842baf721920 xen/include/Makefile --- a/xen/include/Makefile Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/Makefile Mon Sep 22 12:23:28 2008 +0100 @@ -58,7 +58,7 @@ mv -f $@.new $@ compat/%.i: compat/%.c Makefile - $(CPP) $(filter-out -M% .%.d,$(CFLAGS)) $(cppflags-y) -o $@ $< + $(CPP) -include public/xen-compat.h $(filter-out -M% .%.d,$(CFLAGS)) $(cppflags-y) -o $@ $< compat/%.c: public/%.h xlat.lst Makefile $(BASEDIR)/tools/compat-build-source.py mkdir -p $(@D) diff -r 1df819bcf086 -r 842baf721920 xen/include/asm-x86/grant_table.h --- a/xen/include/asm-x86/grant_table.h Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/asm-x86/grant_table.h Mon Sep 22 12:23:28 2008 +0100 @@ -21,15 +21,30 @@ #define gnttab_create_shared_page(d, t, i) \ do { \ share_xen_page_with_guest( \ - virt_to_page((char *)(t)->shared[i]), \ + virt_to_page((char *)(t)->shared_raw[i]), \ (d), XENSHARE_writable); \ } while ( 0 ) +#define gnttab_create_status_page(d, t, i) \ + do { \ + share_xen_page_with_guest( \ + virt_to_page((char *)(t)->status[i]), \ + (d), XENSHARE_writable); \ + } while ( 0 ) + + #define gnttab_shared_mfn(d, t, i) \ - ((virt_to_maddr((t)->shared[i]) >> PAGE_SHIFT)) + ((virt_to_maddr((t)->shared_raw[i]) >> PAGE_SHIFT)) #define gnttab_shared_gmfn(d, t, i) \ (mfn_to_gmfn(d, gnttab_shared_mfn(d, t, i))) + + +#define gnttab_status_mfn(d, t, i) \ + ((virt_to_maddr((t)->status[i]) >> PAGE_SHIFT)) + +#define gnttab_status_gmfn(d, t, i) \ + (mfn_to_gmfn(d, gnttab_status_mfn(d, t, i))) #define gnttab_mark_dirty(d, f) paging_mark_dirty((d), (f)) diff -r 1df819bcf086 -r 842baf721920 xen/include/public/grant_table.h --- a/xen/include/public/grant_table.h Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/public/grant_table.h Mon Sep 22 12:23:28 2008 +0100 @@ -90,6 +90,11 @@ * [XEN]: This field is written by Xen and read by the sharing guest. * [GST]: This field is written by the guest and read by Xen. */ + +/* + * Version 1 of the grant table entry structure is maintained purely + * for backwards compatibility. New guests should use version 2. + */ #if __XEN_INTERFACE_VERSION__ < 0x0003020a #define grant_entry_v1 grant_entry #define grant_entry_v1_t grant_entry_t @@ -154,6 +159,55 @@ #define _GTF_transfer_completed (3) #define GTF_transfer_completed (1U<<_GTF_transfer_completed) +/* + * Version 2 grant table entries. These fulfil the same role as + * version 1 entries, but can represent more complicated operations. + * Any given domain will have either a version 1 or a version 2 table, + * and every entry in the table will be the same version. + * + * The interface by which domains use grant references does not depend + * on the grant table version in use by the other domain. + */ +#if __XEN_INTERFACE_VERSION__ >= 0x0003020a +/* + * Version 1 and version 2 grant entries share a common prefix. The + * fields of the prefix are documented as part of struct + * grant_entry_v1. + */ +struct grant_entry_header { + uint16_t flags; + domid_t domid; +}; +typedef struct grant_entry_header grant_entry_header_t; + +/* + * Version 2 of the grant entry structure. + */ +union grant_entry_v2 { + grant_entry_header_t hdr; + + /* + * This member is used for V1-style full page grants, where either: + * + * -- hdr.type is GTF_accept_transfer, or + * -- hdr.type is GTF_permit_access and GTF_sub_page is not set. + * + * In that case, the frame field has the same semantics as the + * field of the same name in the V1 entry structure. + */ + struct { + grant_entry_header_t hdr; + uint32_t pad0; + uint64_t frame; + } full_page; + + uint32_t __spacer[4]; /* Pad to a power of two */ +}; +typedef union grant_entry_v2 grant_entry_v2_t; + +typedef uint16_t grant_status_t; + +#endif /* __XEN_INTERFACE_VERSION__ */ /*********************************** * GRANT TABLE QUERIES AND USES @@ -363,6 +417,63 @@ typedef struct gnttab_unmap_and_replace gnttab_unmap_and_replace_t; DEFINE_XEN_GUEST_HANDLE(gnttab_unmap_and_replace_t); +#if __XEN_INTERFACE_VERSION__ >= 0x0003020a +/* + * GNTTABOP_set_version: Request a particular version of the grant + * table shared table structure. This operation can only be performed + * once in any given domain. It must be performed before any grants + * are activated; otherwise, the domain will be stuck with version 1. + * The only defined versions are 1 and 2. + */ +#define GNTTABOP_set_version 8 +struct gnttab_set_version { + /* IN parameters */ + uint32_t version; +}; +typedef struct gnttab_set_version gnttab_set_version_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_set_version_t); + + +/* + * GNTTABOP_get_status_frames: Get the list of frames used to store grant + * status for <dom>. In grant format version 2, the status is separated + * from the other shared grant fields to allow more efficient synchronization + * using barriers instead of atomic cmpexch operations. + * <nr_frames> specify the size of vector <frame_list>. + * The frame addresses are returned in the <frame_list>. + * Only <nr_frames> addresses are returned, even if the table is larger. + * NOTES: + * 1. <dom> may be specified as DOMID_SELF. + * 2. Only a sufficiently-privileged domain may specify <dom> != DOMID_SELF. + */ +#define GNTTABOP_get_status_frames 9 +struct gnttab_get_status_frames { + /* IN parameters. */ + uint32_t nr_frames; + domid_t dom; + /* OUT parameters. */ + int16_t status; /* GNTST_* */ + XEN_GUEST_HANDLE(uint64_t) frame_list; +}; +typedef struct gnttab_get_status_frames gnttab_get_status_frames_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_t); + +/* + * GNTTABOP_get_version: Get the grant table version which is in + * effect for domain <dom>. + */ +#define GNTTABOP_get_version 10 +struct gnttab_get_version { + /* IN parameters */ + domid_t dom; + uint16_t pad; + /* OUT parameters */ + uint32_t version; +}; +typedef struct gnttab_get_version gnttab_get_version_t; +DEFINE_XEN_GUEST_HANDLE(gnttab_get_version_t); + +#endif /* __XEN_INTERFACE_VERSION__ */ /* * Bitfield values for gnttab_map_grant_ref.flags. diff -r 1df819bcf086 -r 842baf721920 xen/include/public/memory.h --- a/xen/include/public/memory.h Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/public/memory.h Mon Sep 22 12:23:28 2008 +0100 @@ -211,6 +211,8 @@ #define XENMAPSPACE_gmfn 2 /* GMFN */ unsigned int space; +#define XENMAPIDX_grant_table_status 0x80000000 + /* Index into source mapping space. */ xen_ulong_t idx; diff -r 1df819bcf086 -r 842baf721920 xen/include/public/xen.h --- a/xen/include/public/xen.h Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/public/xen.h Mon Sep 22 12:23:28 2008 +0100 @@ -47,6 +47,7 @@ __DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long); DEFINE_XEN_GUEST_HANDLE(void); +DEFINE_XEN_GUEST_HANDLE(uint64_t); DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); #endif diff -r 1df819bcf086 -r 842baf721920 xen/include/xen/grant_table.h --- a/xen/include/xen/grant_table.h Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/xen/grant_table.h Mon Sep 22 12:23:28 2008 +0100 @@ -80,7 +80,15 @@ /* Table size. Number of frames shared with guest */ unsigned int nr_grant_frames; /* Shared grant table (see include/public/grant_table.h). */ - struct grant_entry_v1 **shared; + union { + void **shared_raw; + struct grant_entry_v1 **shared_v1; + union grant_entry_v2 **shared_v2; + }; + /* Number of grant status frames shared with guest (for version 2) */ + unsigned int nr_status_frames; + /* State grant table (see include/public/grant_table.h). */ + grant_status_t **status; /* Active grant table. */ struct active_grant_entry **active; /* Mapping tracking table. */ @@ -89,6 +97,9 @@ unsigned int maptrack_limit; /* Lock protecting updates to active and shared grant tables. */ spinlock_t lock; + /* The defined versions are 1 and 2. Set to 0 if we don't know + what version to use yet. */ + unsigned gt_version; }; /* Create/destroy per-domain grant table context. */ @@ -114,10 +125,19 @@ return gt->nr_grant_frames; } -/* Number of grant table entries. Caller must hold d's grant table lock. */ -static inline unsigned int nr_grant_entries(struct grant_table *gt) +/* Number of status grant table frames. Caller must hold d's gr. table lock.*/ +static inline unsigned int nr_status_frames(struct grant_table *gt) { - return (nr_grant_frames(gt) << PAGE_SHIFT) / sizeof(grant_entry_v1_t); + return gt->nr_status_frames; +} + +#define GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) +#define GRANT_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t)) +/* Number of grant table status entries. Caller must hold d's gr. table lock.*/ +static inline unsigned int grant_to_status_frames(int grant_frames) +{ + return (grant_frames * GRANT_PER_PAGE + GRANT_STATUS_PER_PAGE - 1) / + GRANT_STATUS_PER_PAGE; } static inline unsigned int diff -r 1df819bcf086 -r 842baf721920 xen/include/xlat.lst --- a/xen/include/xlat.lst Mon Sep 22 12:23:28 2008 +0100 +++ b/xen/include/xlat.lst Mon Sep 22 12:23:28 2008 +0100 @@ -44,7 +44,12 @@ ! gnttab_transfer grant_table.h ? gnttab_unmap_grant_ref grant_table.h ? gnttab_unmap_and_replace grant_table.h +? gnttab_set_version grant_table.h +? gnttab_get_version grant_table.h +! gnttab_get_status_frames grant_table.h ? grant_entry_v1 grant_table.h +? grant_entry_header grant_table.h +? grant_entry_v2 grant_table.h ? kexec_exec kexec.h ! kexec_image kexec.h ! kexec_range kexec.h _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |