Mon Apr 20 19:42:10 2020 UTC ()
Bad news:
 * grant table v2 is not supported for HVM guests on 4.11 at last.
 * see xen/arch/x86/hvm/hypercall.c in Xen sources (missing
 * GNTTABOP_get_status_frames)

So restore grant table v1 for !XENPV


(bouyer)
diff -r1.29.2.1 -r1.29.2.2 src/sys/arch/xen/xen/xengnt.c

cvs diff -r1.29.2.1 -r1.29.2.2 src/sys/arch/xen/xen/xengnt.c (expand / switch to unified diff)

--- src/sys/arch/xen/xen/xengnt.c 2020/04/20 11:29:01 1.29.2.1
+++ src/sys/arch/xen/xen/xengnt.c 2020/04/20 19:42:10 1.29.2.2
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: xengnt.c,v 1.29.2.1 2020/04/20 11:29:01 bouyer Exp $ */ 1/* $NetBSD: xengnt.c,v 1.29.2.2 2020/04/20 19:42:10 bouyer Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2006 Manuel Bouyer. 4 * Copyright (c) 2006 Manuel Bouyer.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright 11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the 12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution. 13 * documentation and/or other materials provided with the distribution.
14 * 14 *
@@ -16,124 +16,147 @@ @@ -16,124 +16,147 @@
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 * 25 *
26 */ 26 */
27 27
28#include <sys/cdefs.h> 28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1.29.2.1 2020/04/20 11:29:01 bouyer Exp $"); 29__KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1.29.2.2 2020/04/20 19:42:10 bouyer Exp $");
30 30
31#include <sys/types.h> 31#include <sys/types.h>
32#include <sys/param.h> 32#include <sys/param.h>
33#include <sys/systm.h> 33#include <sys/systm.h>
34#include <sys/kmem.h> 34#include <sys/kmem.h>
35#include <sys/queue.h> 35#include <sys/queue.h>
36#include <sys/extent.h> 36#include <sys/extent.h>
37#include <sys/kernel.h> 37#include <sys/kernel.h>
38#include <sys/mutex.h> 38#include <sys/mutex.h>
39#include <uvm/uvm.h> 39#include <uvm/uvm.h>
40 40
41#include <xen/hypervisor.h> 41#include <xen/hypervisor.h>
42#include <xen/xen.h> 42#include <xen/xen.h>
43#include <xen/granttables.h> 43#include <xen/granttables.h>
44 44
 45#include "opt_xen.h"
 46
 47/*
 48 * grant table v2 is not supported for HVM guests on 4.11 at last.
 49 * see xen/arch/x86/hvm/hypercall.c in Xen sources (missing
 50 * GNTTABOP_get_status_frames)
 51 */
 52
 53#ifdef XENPV
 54#define USE_GRANT_V2
 55#endif
 56
45/* #define XENDEBUG */ 57/* #define XENDEBUG */
46#ifdef XENDEBUG 58#ifdef XENDEBUG
47#define DPRINTF(x) printf x 59#define DPRINTF(x) printf x
48#else 60#else
49#define DPRINTF(x) 61#define DPRINTF(x)
50#endif 62#endif
51 63
52#define NR_GRANT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t)) 
53#define NR_GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t)) 
54 
55/* External tools reserve first few grant table entries. */ 64/* External tools reserve first few grant table entries. */
56#define NR_RESERVED_ENTRIES 8 65#define NR_RESERVED_ENTRIES 8
57 66
58/* Current number of frames making up the grant table */ 67/* Current number of frames making up the grant table */
59int gnt_nr_grant_frames; 68int gnt_nr_grant_frames;
60/* Maximum number of frames that can make up the grant table */ 69/* Maximum number of frames that can make up the grant table */
61int gnt_max_grant_frames; 70int gnt_max_grant_frames;
62/* Number of grant status frames */ 
63int gnt_status_frames; 
64 71
65/* table of free grant entries */ 72/* table of free grant entries */
66grant_ref_t *gnt_entries; 73grant_ref_t *gnt_entries;
67/* last free entry */ 74/* last free entry */
68int last_gnt_entry; 75int last_gnt_entry;
69/* empty entry in the list */ 76/* empty entry in the list */
70#define XENGNT_NO_ENTRY 0xffffffff 77#define XENGNT_NO_ENTRY 0xffffffff
71 78
72/* VM address of the grant table */ 79/* VM address of the grant table */
 80#ifdef USE_GRANT_V2
 81#define NR_GRANT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v2_t))
 82#define NR_GRANT_STATUS_PER_PAGE (PAGE_SIZE / sizeof(grant_status_t))
 83
73grant_entry_v2_t *grant_table; 84grant_entry_v2_t *grant_table;
 85/* Number of grant status frames */
 86int gnt_status_frames;
 87
74grant_status_t *grant_status; 88grant_status_t *grant_status;
 89#else /* USE_GRANT_V2 */
 90#define NR_GRANT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v1_t))
 91grant_entry_v1_t *grant_table;
 92#endif /* USE_GRANT_V2 */
75kmutex_t grant_lock; 93kmutex_t grant_lock;
76 94
77static grant_ref_t xengnt_get_entry(void); 95static grant_ref_t xengnt_get_entry(void);
78static void xengnt_free_entry(grant_ref_t); 96static void xengnt_free_entry(grant_ref_t);
79static int xengnt_more_entries(void); 97static int xengnt_more_entries(void);
80static int xengnt_map_status(void); 98static int xengnt_map_status(void);
81 99
82void 100void
83xengnt_init(void) 101xengnt_init(void)
84{ 102{
85 struct gnttab_query_size query; 103 struct gnttab_query_size query;
86 struct gnttab_set_version gntversion; 
87 int rc; 104 int rc;
88 int nr_grant_entries; 105 int nr_grant_entries;
89 int i; 106 int i;
90 107
91 query.dom = DOMID_SELF; 108 query.dom = DOMID_SELF;
92 rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1); 109 rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
93 if ((rc < 0) || (query.status != GNTST_okay)) 110 if ((rc < 0) || (query.status != GNTST_okay))
94 gnt_max_grant_frames = 4; /* Legacy max number of frames */ 111 gnt_max_grant_frames = 4; /* Legacy max number of frames */
95 else 112 else
96 gnt_max_grant_frames = query.max_nr_frames; 113 gnt_max_grant_frames = query.max_nr_frames;
97 114
98 /* 115 /*
99 * Always allocate max number of grant frames, never expand in runtime 116 * Always allocate max number of grant frames, never expand in runtime
100 */ 117 */
101 gnt_nr_grant_frames = gnt_max_grant_frames; 118 gnt_nr_grant_frames = gnt_max_grant_frames;
102 119
 120
 121#ifdef USE_GRANT_V2
 122 struct gnttab_set_version gntversion;
103 gntversion.version = 2; 123 gntversion.version = 2;
104 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gntversion, 1); 124 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gntversion, 1);
105 if (rc < 0 || gntversion.version != 2) 125 if (rc < 0 || gntversion.version != 2)
106 panic("GNTTABOP_set_version 2 failed %d", rc); 126 panic("GNTTABOP_set_version 2 failed %d", rc);
 127#endif /* USE_GRANT_V2 */
107 128
108 nr_grant_entries = 129 nr_grant_entries =
109 gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE; 130 gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE;
110 131
111 grant_table = (void *)uvm_km_alloc(kernel_map, 132 grant_table = (void *)uvm_km_alloc(kernel_map,
112 gnt_max_grant_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); 133 gnt_max_grant_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY);
113 if (grant_table == NULL) 134 if (grant_table == NULL)
114 panic("xengnt_init() table no VM space"); 135 panic("xengnt_init() table no VM space");
115 136
116 gnt_entries = kmem_alloc((nr_grant_entries + 1) * sizeof(grant_ref_t), 137 gnt_entries = kmem_alloc((nr_grant_entries + 1) * sizeof(grant_ref_t),
117 KM_SLEEP); 138 KM_SLEEP);
118 for (i = 0; i <= nr_grant_entries; i++) 139 for (i = 0; i <= nr_grant_entries; i++)
119 gnt_entries[i] = XENGNT_NO_ENTRY; 140 gnt_entries[i] = XENGNT_NO_ENTRY;
120 141
 142#ifdef USE_GRANT_V2
121 gnt_status_frames = 143 gnt_status_frames =
122 round_page(nr_grant_entries * sizeof(grant_status_t)) / PAGE_SIZE; 144 round_page(nr_grant_entries * sizeof(grant_status_t)) / PAGE_SIZE;
123 grant_status = (void *)uvm_km_alloc(kernel_map, 145 grant_status = (void *)uvm_km_alloc(kernel_map,
124 gnt_status_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); 146 gnt_status_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY);
125 if (grant_status == NULL) 147 if (grant_status == NULL)
126 panic("xengnt_init() status no VM space"); 148 panic("xengnt_init() status no VM space");
 149#endif /* USE_GRANT_V2 */
127 150
128 mutex_init(&grant_lock, MUTEX_DEFAULT, IPL_VM); 151 mutex_init(&grant_lock, MUTEX_DEFAULT, IPL_VM);
129 152
130 xengnt_resume(); 153 xengnt_resume();
131 154
132} 155}
133 156
134/* 157/*
135 * Resume grant table state 158 * Resume grant table state
136 */ 159 */
137bool 160bool
138xengnt_resume(void) 161xengnt_resume(void)
139{ 162{
@@ -161,82 +184,87 @@ xengnt_suspend(void) { @@ -161,82 +184,87 @@ xengnt_suspend(void) {
161 int i; 184 int i;
162 185
163 mutex_enter(&grant_lock); 186 mutex_enter(&grant_lock);
164 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); 187 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY);
165 188
166 for (i = 0; i < last_gnt_entry; i++) { 189 for (i = 0; i < last_gnt_entry; i++) {
167 /* invalidate all grant entries (necessary for resume) */ 190 /* invalidate all grant entries (necessary for resume) */
168 gnt_entries[i] = XENGNT_NO_ENTRY; 191 gnt_entries[i] = XENGNT_NO_ENTRY;
169 } 192 }
170  193
171 /* Remove virtual => machine mapping for grant table */ 194 /* Remove virtual => machine mapping for grant table */
172 pmap_kremove((vaddr_t)grant_table, gnt_nr_grant_frames * PAGE_SIZE); 195 pmap_kremove((vaddr_t)grant_table, gnt_nr_grant_frames * PAGE_SIZE);
173 196
 197#ifdef USE_GRANT_V2
174 /* Remove virtual => machine mapping for status table */ 198 /* Remove virtual => machine mapping for status table */
175 pmap_kremove((vaddr_t)grant_status, gnt_status_frames * PAGE_SIZE); 199 pmap_kremove((vaddr_t)grant_status, gnt_status_frames * PAGE_SIZE);
 200#endif
176 201
177 pmap_update(pmap_kernel()); 202 pmap_update(pmap_kernel());
178 mutex_exit(&grant_lock); 203 mutex_exit(&grant_lock);
179 return true; 204 return true;
180} 205}
181 206
182/* 207/*
183 * Get status frames and enter them into the VA space. 208 * Get status frames and enter them into the VA space.
184 */ 209 */
185static int 210static int
186xengnt_map_status(void) 211xengnt_map_status(void)
187{ 212{
 213#ifdef USE_GRANT_V2
188 gnttab_get_status_frames_t getstatus; 214 gnttab_get_status_frames_t getstatus;
189 uint64_t *pages; 215 uint64_t *pages;
190 size_t sz; 216 size_t sz;
 217 int err;
191 218
192 KASSERT(mutex_owned(&grant_lock)); 219 KASSERT(mutex_owned(&grant_lock));
193 220
194 sz = gnt_status_frames * sizeof(*pages); 221 sz = gnt_status_frames * sizeof(*pages);
195 pages = kmem_alloc(sz, KM_NOSLEEP); 222 pages = kmem_alloc(sz, KM_NOSLEEP);
196 if (pages == NULL) 223 if (pages == NULL)
197 return ENOMEM; 224 return ENOMEM;
198 225
199 getstatus.dom = DOMID_SELF; 226 getstatus.dom = DOMID_SELF;
200 getstatus.nr_frames = gnt_status_frames; 227 getstatus.nr_frames = gnt_status_frames;
201 set_xen_guest_handle(getstatus.frame_list, pages); 228 set_xen_guest_handle(getstatus.frame_list, pages);
202 229
203 /* 230 /*
204 * get the status frames, and return the list of their virtual 231 * get the status frames, and return the list of their virtual
205 * addresses in 'pages' 232 * addresses in 'pages'
206 */ 233 */
207 if (HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames, 234 if ((err = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
208 &getstatus, 1) != 0) 235 &getstatus, 1)) != 0)
209 panic("%s: get_status_frames failed", __func__); 236 panic("%s: get_status_frames failed: %d", __func__, err);
210 if (getstatus.status != GNTST_okay) { 237 if (getstatus.status != GNTST_okay) {
211 aprint_error("%s: get_status_frames returned %d\n", 238 aprint_error("%s: get_status_frames returned %d\n",
212 __func__, getstatus.status); 239 __func__, getstatus.status);
213 kmem_free(pages, sz); 240 kmem_free(pages, sz);
214 return ENOMEM; 241 return ENOMEM;
215 } 242 }
216 243
217 /* 244 /*
218 * map between status_table addresses and the machine addresses of 245 * map between status_table addresses and the machine addresses of
219 * the status table frames 246 * the status table frames
220 */ 247 */
221 for (int i = 0; i < gnt_status_frames; i++) { 248 for (int i = 0; i < gnt_status_frames; i++) {
222 pmap_kenter_ma(((vaddr_t)grant_status) + i * PAGE_SIZE, 249 pmap_kenter_ma(((vaddr_t)grant_status) + i * PAGE_SIZE,
223 ((paddr_t)pages[i]) << PAGE_SHIFT, 250 ((paddr_t)pages[i]) << PAGE_SHIFT,
224 VM_PROT_WRITE, 0); 251 VM_PROT_WRITE, 0);
225 } 252 }
226 pmap_update(pmap_kernel()); 253 pmap_update(pmap_kernel());
227 254
228 kmem_free(pages, sz); 255 kmem_free(pages, sz);
229 256
 257#endif /* USE_GRANT_V2 */
230 return 0; 258 return 0;
231} 259}
232 260
233/* 261/*
234 * Add another page to the grant table 262 * Add another page to the grant table
235 * Returns 0 on success, ENOMEM on failure 263 * Returns 0 on success, ENOMEM on failure
236 */ 264 */
237static int 265static int
238xengnt_more_entries(void) 266xengnt_more_entries(void)
239{ 267{
240 gnttab_setup_table_t setup; 268 gnttab_setup_table_t setup;
241 u_long *pages; 269 u_long *pages;
242 int nframes_new = gnt_nr_grant_frames + 1; 270 int nframes_new = gnt_nr_grant_frames + 1;
@@ -360,26 +388,27 @@ xengnt_get_entry(void) @@ -360,26 +388,27 @@ xengnt_get_entry(void)
360static void 388static void
361xengnt_free_entry(grant_ref_t entry) 389xengnt_free_entry(grant_ref_t entry)
362{ 390{
363 mutex_enter(&grant_lock); 391 mutex_enter(&grant_lock);
364 KASSERT(entry > NR_RESERVED_ENTRIES); 392 KASSERT(entry > NR_RESERVED_ENTRIES);
365 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); 393 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY);
366 KASSERT(last_gnt_entry >= 0); 394 KASSERT(last_gnt_entry >= 0);
367 KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); 395 KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE);
368 gnt_entries[last_gnt_entry] = entry; 396 gnt_entries[last_gnt_entry] = entry;
369 last_gnt_entry++; 397 last_gnt_entry++;
370 mutex_exit(&grant_lock); 398 mutex_exit(&grant_lock);
371} 399}
372 400
 401#ifdef USE_GRANT_V2
373int 402int
374xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp) 403xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp)
375{ 404{
376 mutex_enter(&grant_lock); 405 mutex_enter(&grant_lock);
377 406
378 *entryp = xengnt_get_entry(); 407 *entryp = xengnt_get_entry();
379 if (__predict_false(*entryp == XENGNT_NO_ENTRY)) { 408 if (__predict_false(*entryp == XENGNT_NO_ENTRY)) {
380 mutex_exit(&grant_lock); 409 mutex_exit(&grant_lock);
381 return ENOMEM; 410 return ENOMEM;
382 } 411 }
383 412
384 grant_table[*entryp].full_page.frame = ma >> PAGE_SHIFT; 413 grant_table[*entryp].full_page.frame = ma >> PAGE_SHIFT;
385 grant_table[*entryp].hdr.domid = dom; 414 grant_table[*entryp].hdr.domid = dom;
@@ -404,22 +433,85 @@ xengnt_revoke_access(grant_ref_t entry) @@ -404,22 +433,85 @@ xengnt_revoke_access(grant_ref_t entry)
404 != 0)) 433 != 0))
405 printf("xengnt_revoke_access(%u): still in use\n", 434 printf("xengnt_revoke_access(%u): still in use\n",
406 entry); 435 entry);
407 else { 436 else {
408 437
409 /* 438 /*
410 * The read of grant_status needs to have acquire semantics. 439 * The read of grant_status needs to have acquire semantics.
411 * Reads already have that on x86, so need only protect 440 * Reads already have that on x86, so need only protect
412 * against compiler reordering. May need full barrier 441 * against compiler reordering. May need full barrier
413 * on other architectures. 442 * on other architectures.
414 */ 443 */
415 __insn_barrier(); 444 __insn_barrier();
416 } 445 }
417 
418 xengnt_free_entry(entry); 446 xengnt_free_entry(entry);
419} 447}
420 448
421int 449int
422xengnt_status(grant_ref_t entry) 450xengnt_status(grant_ref_t entry)
423{ 451{
424 return grant_status[entry] & (GTF_reading|GTF_writing); 452 return grant_status[entry] & (GTF_reading|GTF_writing);
425} 453}
 454#else /* USE_GRANT_V2 */
 455
 456int
 457xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp)
 458{
 459 mutex_enter(&grant_lock);
 460
 461 *entryp = xengnt_get_entry();
 462 if (__predict_false(*entryp == XENGNT_NO_ENTRY)) {
 463 mutex_exit(&grant_lock);
 464 return ENOMEM;
 465 }
 466
 467 grant_table[*entryp].frame = ma >> PAGE_SHIFT;
 468 grant_table[*entryp].domid = dom;
 469 /*
 470 * ensure that the above values reach global visibility
 471 * before permitting frame's access (done when we set flags)
 472 */
 473 xen_rmb();
 474 grant_table[*entryp].flags =
 475 GTF_permit_access | (ro ? GTF_readonly : 0);
 476 mutex_exit(&grant_lock);
 477 return 0;
 478}
 479
 480
 481static inline uint16_t
 482xen_atomic_cmpxchg16(volatile uint16_t *ptr, uint16_t val, uint16_t newval)
 483{
 484 unsigned long result;
 485
 486 __asm volatile(__LOCK_PREFIX
 487 "cmpxchgw %w1,%2"
 488 :"=a" (result)
 489 :"q"(newval), "m" (*ptr), "0" (val)
 490 :"memory");
 491
 492 return result;
 493}
 494
 495void
 496xengnt_revoke_access(grant_ref_t entry)
 497{
 498
 499 uint16_t flags, nflags;
 500
 501 nflags = grant_table[entry].flags;
 502
 503 do {
 504 if ((flags = nflags) & (GTF_reading|GTF_writing))
 505 panic("xengnt_revoke_access: still in use");
 506 nflags = xen_atomic_cmpxchg16(&grant_table[entry].flags,
 507 flags, 0);
 508 } while (nflags != flags);
 509 xengnt_free_entry(entry);
 510}
 511
 512int
 513xengnt_status(grant_ref_t entry)
 514{
 515 return (grant_table[entry].flags & (GTF_reading|GTF_writing));
 516}
 517#endif /* USE_GRANT_V2 */