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 (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,425 +1,517 @@ @@ -1,425 +1,517 @@
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 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
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{
140 int previous_nr_grant_frames = gnt_nr_grant_frames; 163 int previous_nr_grant_frames = gnt_nr_grant_frames;
141 164
142 last_gnt_entry = 0; 165 last_gnt_entry = 0;
143 gnt_nr_grant_frames = 0; 166 gnt_nr_grant_frames = 0;
144 167
145 mutex_enter(&grant_lock); 168 mutex_enter(&grant_lock);
146 while (gnt_nr_grant_frames < previous_nr_grant_frames) { 169 while (gnt_nr_grant_frames < previous_nr_grant_frames) {
147 if (xengnt_more_entries() != 0) 170 if (xengnt_more_entries() != 0)
148 panic("xengnt_resume: can't restore grant frames"); 171 panic("xengnt_resume: can't restore grant frames");
149 } 172 }
150 xengnt_map_status(); 173 xengnt_map_status();
151 mutex_exit(&grant_lock); 174 mutex_exit(&grant_lock);
152 return true; 175 return true;
153} 176}
154 177
155/* 178/*
156 * Suspend grant table state 179 * Suspend grant table state
157 */ 180 */
158bool 181bool
159xengnt_suspend(void) { 182xengnt_suspend(void) {
160 183
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;
243 int i, start_gnt; 271 int i, start_gnt;
244 size_t sz; 272 size_t sz;
245 KASSERT(mutex_owned(&grant_lock)); 273 KASSERT(mutex_owned(&grant_lock));
246 274
247 if (gnt_nr_grant_frames == gnt_max_grant_frames) 275 if (gnt_nr_grant_frames == gnt_max_grant_frames)
248 return ENOMEM; 276 return ENOMEM;
249 277
250 sz = nframes_new * sizeof(*pages); 278 sz = nframes_new * sizeof(*pages);
251 pages = kmem_alloc(sz, KM_NOSLEEP); 279 pages = kmem_alloc(sz, KM_NOSLEEP);
252 if (pages == NULL) 280 if (pages == NULL)
253 return ENOMEM; 281 return ENOMEM;
254 282
255 if (xen_feature(XENFEAT_auto_translated_physmap)) { 283 if (xen_feature(XENFEAT_auto_translated_physmap)) {
256 /* 284 /*
257 * Note: Although we allocate space for the entire 285 * Note: Although we allocate space for the entire
258 * table, in this mode we only update one entry at a 286 * table, in this mode we only update one entry at a
259 * time. 287 * time.
260 */ 288 */
261 struct vm_page *pg; 289 struct vm_page *pg;
262 struct xen_add_to_physmap xmap; 290 struct xen_add_to_physmap xmap;
263 291
264 pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE|UVM_PGA_ZERO); 292 pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE|UVM_PGA_ZERO);
265 pages[gnt_nr_grant_frames] = atop(uvm_vm_page_to_phys(pg)); 293 pages[gnt_nr_grant_frames] = atop(uvm_vm_page_to_phys(pg));
266 294
267 xmap.domid = DOMID_SELF; 295 xmap.domid = DOMID_SELF;
268 xmap.space = XENMAPSPACE_grant_table; 296 xmap.space = XENMAPSPACE_grant_table;
269 xmap.idx = gnt_nr_grant_frames; 297 xmap.idx = gnt_nr_grant_frames;
270 xmap.gpfn = pages[gnt_nr_grant_frames]; 298 xmap.gpfn = pages[gnt_nr_grant_frames];
271 299
272 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xmap) < 0) 300 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xmap) < 0)
273 panic("%s: Unable to register HYPERVISOR_shared_info\n", __func__); 301 panic("%s: Unable to register HYPERVISOR_shared_info\n", __func__);
274 302
275 } else { 303 } else {
276 setup.dom = DOMID_SELF; 304 setup.dom = DOMID_SELF;
277 setup.nr_frames = nframes_new; 305 setup.nr_frames = nframes_new;
278 set_xen_guest_handle(setup.frame_list, pages); 306 set_xen_guest_handle(setup.frame_list, pages);
279 307
280 /* 308 /*
281 * setup the grant table, made of nframes_new frames 309 * setup the grant table, made of nframes_new frames
282 * and return the list of their virtual addresses 310 * and return the list of their virtual addresses
283 * in 'pages' 311 * in 'pages'
284 */ 312 */
285 if (HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0) 313 if (HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0)
286 panic("%s: setup table failed", __func__); 314 panic("%s: setup table failed", __func__);
287 if (setup.status != GNTST_okay) { 315 if (setup.status != GNTST_okay) {
288 aprint_error("%s: setup table returned %d\n", 316 aprint_error("%s: setup table returned %d\n",
289 __func__, setup.status); 317 __func__, setup.status);
290 kmem_free(pages, sz); 318 kmem_free(pages, sz);
291 return ENOMEM; 319 return ENOMEM;
292 } 320 }
293 } 321 }
294 322
295 DPRINTF(("xengnt_more_entries: map 0x%lx -> %p\n", 323 DPRINTF(("xengnt_more_entries: map 0x%lx -> %p\n",
296 pages[gnt_nr_grant_frames], 324 pages[gnt_nr_grant_frames],
297 (char *)grant_table + gnt_nr_grant_frames * PAGE_SIZE)); 325 (char *)grant_table + gnt_nr_grant_frames * PAGE_SIZE));
298 326
299 /* 327 /*
300 * map between grant_table addresses and the machine addresses of 328 * map between grant_table addresses and the machine addresses of
301 * the grant table frames 329 * the grant table frames
302 */ 330 */
303 pmap_kenter_ma(((vaddr_t)grant_table) + gnt_nr_grant_frames * PAGE_SIZE, 331 pmap_kenter_ma(((vaddr_t)grant_table) + gnt_nr_grant_frames * PAGE_SIZE,
304 ((paddr_t)pages[gnt_nr_grant_frames]) << PAGE_SHIFT, 332 ((paddr_t)pages[gnt_nr_grant_frames]) << PAGE_SHIFT,
305 VM_PROT_WRITE, 0); 333 VM_PROT_WRITE, 0);
306 pmap_update(pmap_kernel()); 334 pmap_update(pmap_kernel());
307 335
308 /* 336 /*
309 * add the grant entries associated to the last grant table frame 337 * add the grant entries associated to the last grant table frame
310 * and mark them as free. Prevent using the first grants (from 0 to 8) 338 * and mark them as free. Prevent using the first grants (from 0 to 8)
311 * since they are used by the tools. 339 * since they are used by the tools.
312 */ 340 */
313 start_gnt = (gnt_nr_grant_frames * NR_GRANT_ENTRIES_PER_PAGE) < 341 start_gnt = (gnt_nr_grant_frames * NR_GRANT_ENTRIES_PER_PAGE) <
314 (NR_RESERVED_ENTRIES + 1) ? 342 (NR_RESERVED_ENTRIES + 1) ?
315 (NR_RESERVED_ENTRIES + 1) : 343 (NR_RESERVED_ENTRIES + 1) :
316 (gnt_nr_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); 344 (gnt_nr_grant_frames * NR_GRANT_ENTRIES_PER_PAGE);
317 for (i = start_gnt; 345 for (i = start_gnt;
318 i < nframes_new * NR_GRANT_ENTRIES_PER_PAGE; 346 i < nframes_new * NR_GRANT_ENTRIES_PER_PAGE;
319 i++) { 347 i++) {
320 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); 348 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY);
321 gnt_entries[last_gnt_entry] = i; 349 gnt_entries[last_gnt_entry] = i;
322 last_gnt_entry++; 350 last_gnt_entry++;
323 } 351 }
324 gnt_nr_grant_frames = nframes_new; 352 gnt_nr_grant_frames = nframes_new;
325 kmem_free(pages, sz); 353 kmem_free(pages, sz);
326 return 0; 354 return 0;
327} 355}
328 356
329/* 357/*
330 * Returns a reference to the first free entry in grant table 358 * Returns a reference to the first free entry in grant table
331 */ 359 */
332static grant_ref_t 360static grant_ref_t
333xengnt_get_entry(void) 361xengnt_get_entry(void)
334{ 362{
335 grant_ref_t entry; 363 grant_ref_t entry;
336 static struct timeval xengnt_nonmemtime; 364 static struct timeval xengnt_nonmemtime;
337 static const struct timeval xengnt_nonmemintvl = {5,0}; 365 static const struct timeval xengnt_nonmemintvl = {5,0};
338 366
339 KASSERT(mutex_owned(&grant_lock)); 367 KASSERT(mutex_owned(&grant_lock));
340 368
341 if (__predict_false(last_gnt_entry == 0)) { 369 if (__predict_false(last_gnt_entry == 0)) {
342 if (ratecheck(&xengnt_nonmemtime, &xengnt_nonmemintvl)) 370 if (ratecheck(&xengnt_nonmemtime, &xengnt_nonmemintvl))
343 printf("xengnt_get_entry: out of grant " 371 printf("xengnt_get_entry: out of grant "
344 "table entries\n"); 372 "table entries\n");
345 return XENGNT_NO_ENTRY; 373 return XENGNT_NO_ENTRY;
346 } 374 }
347 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); 375 KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY);
348 last_gnt_entry--; 376 last_gnt_entry--;
349 entry = gnt_entries[last_gnt_entry]; 377 entry = gnt_entries[last_gnt_entry];
350 gnt_entries[last_gnt_entry] = XENGNT_NO_ENTRY; 378 gnt_entries[last_gnt_entry] = XENGNT_NO_ENTRY;
351 KASSERT(entry != XENGNT_NO_ENTRY && entry > NR_RESERVED_ENTRIES); 379 KASSERT(entry != XENGNT_NO_ENTRY && entry > NR_RESERVED_ENTRIES);
352 KASSERT(last_gnt_entry >= 0); 380 KASSERT(last_gnt_entry >= 0);
353 KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); 381 KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE);
354 return entry; 382 return entry;
355} 383}
356 384
357/* 385/*
358 * Mark the grant table entry as free 386 * Mark the grant table entry as free
359 */ 387 */
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;
386 /* 415 /*
387 * ensure that the above values reach global visibility  416 * ensure that the above values reach global visibility
388 * before permitting frame's access (done when we set flags) 417 * before permitting frame's access (done when we set flags)
389 */ 418 */
390 xen_rmb(); 419 xen_rmb();
391 grant_table[*entryp].hdr.flags = 420 grant_table[*entryp].hdr.flags =
392 GTF_permit_access | (ro ? GTF_readonly : 0); 421 GTF_permit_access | (ro ? GTF_readonly : 0);
393 mutex_exit(&grant_lock); 422 mutex_exit(&grant_lock);
394 return 0; 423 return 0;
395} 424}
396 425
397void 426void
398xengnt_revoke_access(grant_ref_t entry) 427xengnt_revoke_access(grant_ref_t entry)
399{ 428{
400 grant_table[entry].hdr.flags = 0; 429 grant_table[entry].hdr.flags = 0;
401 xen_mb(); /* Concurrent access by hypervisor */ 430 xen_mb(); /* Concurrent access by hypervisor */
402 431
403 if (__predict_false((grant_status[entry] & (GTF_reading|GTF_writing)) 432 if (__predict_false((grant_status[entry] & (GTF_reading|GTF_writing))
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 */