| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: xengnt.c,v 1.20 2011/09/20 00:12:24 jym Exp $ */ | | 1 | /* $NetBSD: xengnt.c,v 1.21 2011/12/09 03:58:12 cherry 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,35 +16,36 @@ | | | @@ -16,35 +16,36 @@ |
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.20 2011/09/20 00:12:24 jym Exp $"); | | 29 | __KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1.21 2011/12/09 03:58:12 cherry 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/malloc.h> | | 34 | #include <sys/malloc.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 <uvm/uvm.h> | | 39 | #include <uvm/uvm.h> |
39 | | | 40 | |
40 | #include <xen/hypervisor.h> | | 41 | #include <xen/hypervisor.h> |
41 | #include <xen/xen.h> | | 42 | #include <xen/xen.h> |
42 | #include <xen/granttables.h> | | 43 | #include <xen/granttables.h> |
43 | | | 44 | |
44 | /* #define XENDEBUG */ | | 45 | /* #define XENDEBUG */ |
45 | #ifdef XENDEBUG | | 46 | #ifdef XENDEBUG |
46 | #define DPRINTF(x) printf x | | 47 | #define DPRINTF(x) printf x |
47 | #else | | 48 | #else |
48 | #define DPRINTF(x) | | 49 | #define DPRINTF(x) |
49 | #endif | | 50 | #endif |
50 | | | 51 | |
| @@ -54,26 +55,27 @@ __KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1 | | | @@ -54,26 +55,27 @@ __KERNEL_RCSID(0, "$NetBSD: xengnt.c,v 1 |
54 | int gnt_nr_grant_frames; | | 55 | int gnt_nr_grant_frames; |
55 | /* Maximum number of frames that can make up the grant table */ | | 56 | /* Maximum number of frames that can make up the grant table */ |
56 | int gnt_max_grant_frames; | | 57 | int gnt_max_grant_frames; |
57 | | | 58 | |
58 | /* table of free grant entries */ | | 59 | /* table of free grant entries */ |
59 | grant_ref_t *gnt_entries; | | 60 | grant_ref_t *gnt_entries; |
60 | /* last free entry */ | | 61 | /* last free entry */ |
61 | int last_gnt_entry; | | 62 | int last_gnt_entry; |
62 | /* empty entry in the list */ | | 63 | /* empty entry in the list */ |
63 | #define XENGNT_NO_ENTRY 0xffffffff | | 64 | #define XENGNT_NO_ENTRY 0xffffffff |
64 | | | 65 | |
65 | /* VM address of the grant table */ | | 66 | /* VM address of the grant table */ |
66 | grant_entry_t *grant_table; | | 67 | grant_entry_t *grant_table; |
| | | 68 | kmutex_t grant_lock; |
67 | | | 69 | |
68 | static grant_ref_t xengnt_get_entry(void); | | 70 | static grant_ref_t xengnt_get_entry(void); |
69 | static void xengnt_free_entry(grant_ref_t); | | 71 | static void xengnt_free_entry(grant_ref_t); |
70 | static int xengnt_more_entries(void); | | 72 | static int xengnt_more_entries(void); |
71 | | | 73 | |
72 | void | | 74 | void |
73 | xengnt_init(void) | | 75 | xengnt_init(void) |
74 | { | | 76 | { |
75 | struct gnttab_query_size query; | | 77 | struct gnttab_query_size query; |
76 | int rc; | | 78 | int rc; |
77 | int nr_grant_entries; | | 79 | int nr_grant_entries; |
78 | int i; | | 80 | int i; |
79 | | | 81 | |
| @@ -89,26 +91,28 @@ xengnt_init(void) | | | @@ -89,26 +91,28 @@ xengnt_init(void) |
89 | gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE; | | 91 | gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE; |
90 | | | 92 | |
91 | grant_table = (void *)uvm_km_alloc(kernel_map, | | 93 | grant_table = (void *)uvm_km_alloc(kernel_map, |
92 | gnt_max_grant_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); | | 94 | gnt_max_grant_frames * PAGE_SIZE, 0, UVM_KMF_VAONLY); |
93 | if (grant_table == NULL) | | 95 | if (grant_table == NULL) |
94 | panic("xengnt_init() no VM space"); | | 96 | panic("xengnt_init() no VM space"); |
95 | gnt_entries = malloc((nr_grant_entries + 1) * sizeof(grant_ref_t), | | 97 | gnt_entries = malloc((nr_grant_entries + 1) * sizeof(grant_ref_t), |
96 | M_DEVBUF, M_NOWAIT); | | 98 | M_DEVBUF, M_NOWAIT); |
97 | if (gnt_entries == NULL) | | 99 | if (gnt_entries == NULL) |
98 | panic("xengnt_init() no space for bitmask"); | | 100 | panic("xengnt_init() no space for bitmask"); |
99 | for (i = 0; i <= nr_grant_entries; i++) | | 101 | for (i = 0; i <= nr_grant_entries; i++) |
100 | gnt_entries[i] = XENGNT_NO_ENTRY; | | 102 | gnt_entries[i] = XENGNT_NO_ENTRY; |
101 | | | 103 | |
| | | 104 | mutex_init(&grant_lock, MUTEX_DEFAULT, IPL_VM); |
| | | 105 | |
102 | xengnt_resume(); | | 106 | xengnt_resume(); |
103 | | | 107 | |
104 | } | | 108 | } |
105 | | | 109 | |
106 | /* | | 110 | /* |
107 | * Resume grant table state | | 111 | * Resume grant table state |
108 | */ | | 112 | */ |
109 | bool | | 113 | bool |
110 | xengnt_resume(void) | | 114 | xengnt_resume(void) |
111 | { | | 115 | { |
112 | int previous_nr_grant_frames = gnt_nr_grant_frames; | | 116 | int previous_nr_grant_frames = gnt_nr_grant_frames; |
113 | | | 117 | |
114 | last_gnt_entry = 0; | | 118 | last_gnt_entry = 0; |
| @@ -207,115 +211,119 @@ xengnt_more_entries(void) | | | @@ -207,115 +211,119 @@ xengnt_more_entries(void) |
207 | } | | 211 | } |
208 | gnt_nr_grant_frames = nframes_new; | | 212 | gnt_nr_grant_frames = nframes_new; |
209 | free(pages, M_DEVBUF); | | 213 | free(pages, M_DEVBUF); |
210 | return 0; | | 214 | return 0; |
211 | } | | 215 | } |
212 | | | 216 | |
213 | /* | | 217 | /* |
214 | * Returns a reference to the first free entry in grant table | | 218 | * Returns a reference to the first free entry in grant table |
215 | */ | | 219 | */ |
216 | static grant_ref_t | | 220 | static grant_ref_t |
217 | xengnt_get_entry(void) | | 221 | xengnt_get_entry(void) |
218 | { | | 222 | { |
219 | grant_ref_t entry; | | 223 | grant_ref_t entry; |
220 | int s = splvm(); | | 224 | mutex_enter(&grant_lock); |
221 | static struct timeval xengnt_nonmemtime; | | 225 | static struct timeval xengnt_nonmemtime; |
222 | static const struct timeval xengnt_nonmemintvl = {5,0}; | | 226 | static const struct timeval xengnt_nonmemintvl = {5,0}; |
223 | | | 227 | |
224 | if (last_gnt_entry == 0) { | | 228 | if (last_gnt_entry == 0) { |
225 | if (xengnt_more_entries()) { | | 229 | if (xengnt_more_entries()) { |
226 | splx(s); | | 230 | mutex_exit(&grant_lock); |
227 | if (ratecheck(&xengnt_nonmemtime, &xengnt_nonmemintvl)) | | 231 | if (ratecheck(&xengnt_nonmemtime, &xengnt_nonmemintvl)) |
228 | printf("xengnt_get_entry: out of grant " | | 232 | printf("xengnt_get_entry: out of grant " |
229 | "table entries\n"); | | 233 | "table entries\n"); |
230 | return XENGNT_NO_ENTRY; | | 234 | return XENGNT_NO_ENTRY; |
231 | } | | 235 | } |
232 | } | | 236 | } |
233 | KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); | | 237 | KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); |
234 | last_gnt_entry--; | | 238 | last_gnt_entry--; |
235 | entry = gnt_entries[last_gnt_entry]; | | 239 | entry = gnt_entries[last_gnt_entry]; |
236 | gnt_entries[last_gnt_entry] = XENGNT_NO_ENTRY; | | 240 | gnt_entries[last_gnt_entry] = XENGNT_NO_ENTRY; |
237 | splx(s); | | 241 | mutex_exit(&grant_lock); |
238 | KASSERT(entry != XENGNT_NO_ENTRY); | | 242 | KASSERT(entry != XENGNT_NO_ENTRY); |
239 | KASSERT(last_gnt_entry >= 0); | | 243 | KASSERT(last_gnt_entry >= 0); |
240 | KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); | | 244 | KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); |
241 | return entry; | | 245 | return entry; |
242 | } | | 246 | } |
243 | | | 247 | |
244 | /* | | 248 | /* |
245 | * Mark the grant table entry as free | | 249 | * Mark the grant table entry as free |
246 | */ | | 250 | */ |
247 | static void | | 251 | static void |
248 | xengnt_free_entry(grant_ref_t entry) | | 252 | xengnt_free_entry(grant_ref_t entry) |
249 | { | | 253 | { |
250 | int s = splvm(); | | 254 | mutex_enter(&grant_lock); |
251 | KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); | | 255 | KASSERT(gnt_entries[last_gnt_entry] == XENGNT_NO_ENTRY); |
252 | KASSERT(last_gnt_entry >= 0); | | 256 | KASSERT(last_gnt_entry >= 0); |
253 | KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); | | 257 | KASSERT(last_gnt_entry <= gnt_max_grant_frames * NR_GRANT_ENTRIES_PER_PAGE); |
254 | gnt_entries[last_gnt_entry] = entry; | | 258 | gnt_entries[last_gnt_entry] = entry; |
255 | last_gnt_entry++; | | 259 | last_gnt_entry++; |
256 | splx(s); | | 260 | mutex_exit(&grant_lock); |
257 | } | | 261 | } |
258 | | | 262 | |
259 | int | | 263 | int |
260 | xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp) | | 264 | xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp) |
261 | { | | 265 | { |
262 | *entryp = xengnt_get_entry(); | | 266 | *entryp = xengnt_get_entry(); |
263 | if (__predict_false(*entryp == XENGNT_NO_ENTRY)) | | 267 | if (__predict_false(*entryp == XENGNT_NO_ENTRY)) |
264 | return ENOMEM; | | 268 | return ENOMEM; |
265 | | | 269 | |
| | | 270 | mutex_enter(&grant_lock); |
266 | grant_table[*entryp].frame = ma >> PAGE_SHIFT; | | 271 | grant_table[*entryp].frame = ma >> PAGE_SHIFT; |
267 | grant_table[*entryp].domid = dom; | | 272 | grant_table[*entryp].domid = dom; |
268 | /* | | 273 | /* |
269 | * ensure that the above values reach global visibility | | 274 | * ensure that the above values reach global visibility |
270 | * before permitting frame's access (done when we set flags) | | 275 | * before permitting frame's access (done when we set flags) |
271 | */ | | 276 | */ |
272 | xen_rmb(); | | 277 | xen_rmb(); |
273 | grant_table[*entryp].flags = | | 278 | grant_table[*entryp].flags = |
274 | GTF_permit_access | (ro ? GTF_readonly : 0); | | 279 | GTF_permit_access | (ro ? GTF_readonly : 0); |
| | | 280 | mutex_exit(&grant_lock); |
275 | return 0; | | 281 | return 0; |
276 | } | | 282 | } |
277 | | | 283 | |
278 | void | | 284 | void |
279 | xengnt_revoke_access(grant_ref_t entry) | | 285 | xengnt_revoke_access(grant_ref_t entry) |
280 | { | | 286 | { |
281 | uint16_t flags, nflags; | | 287 | uint16_t flags, nflags; |
282 | | | 288 | |
283 | nflags = grant_table[entry].flags; | | 289 | nflags = grant_table[entry].flags; |
284 | | | 290 | |
285 | do { | | 291 | do { |
286 | if ((flags = nflags) & (GTF_reading|GTF_writing)) | | 292 | if ((flags = nflags) & (GTF_reading|GTF_writing)) |
287 | panic("xengnt_revoke_access: still in use"); | | 293 | panic("xengnt_revoke_access: still in use"); |
288 | nflags = xen_atomic_cmpxchg16(&grant_table[entry].flags, | | 294 | nflags = xen_atomic_cmpxchg16(&grant_table[entry].flags, |
289 | flags, 0); | | 295 | flags, 0); |
290 | } while (nflags != flags); | | 296 | } while (nflags != flags); |
291 | xengnt_free_entry(entry); | | 297 | xengnt_free_entry(entry); |
292 | } | | 298 | } |
293 | | | 299 | |
294 | int | | 300 | int |
295 | xengnt_grant_transfer(domid_t dom, grant_ref_t *entryp) | | 301 | xengnt_grant_transfer(domid_t dom, grant_ref_t *entryp) |
296 | { | | 302 | { |
297 | *entryp = xengnt_get_entry(); | | 303 | *entryp = xengnt_get_entry(); |
298 | if (__predict_false(*entryp == XENGNT_NO_ENTRY)) | | 304 | if (__predict_false(*entryp == XENGNT_NO_ENTRY)) |
299 | return ENOMEM; | | 305 | return ENOMEM; |
300 | | | 306 | |
| | | 307 | mutex_enter(&grant_lock); |
301 | grant_table[*entryp].frame = 0; | | 308 | grant_table[*entryp].frame = 0; |
302 | grant_table[*entryp].domid = dom; | | 309 | grant_table[*entryp].domid = dom; |
303 | /* | | 310 | /* |
304 | * ensure that the above values reach global visibility | | 311 | * ensure that the above values reach global visibility |
305 | * before permitting frame's transfer (done when we set flags) | | 312 | * before permitting frame's transfer (done when we set flags) |
306 | */ | | 313 | */ |
307 | xen_rmb(); | | 314 | xen_rmb(); |
308 | grant_table[*entryp].flags = GTF_accept_transfer; | | 315 | grant_table[*entryp].flags = GTF_accept_transfer; |
| | | 316 | mutex_exit(&grant_lock); |
309 | return 0; | | 317 | return 0; |
310 | } | | 318 | } |
311 | | | 319 | |
312 | paddr_t | | 320 | paddr_t |
313 | xengnt_revoke_transfer(grant_ref_t entry) | | 321 | xengnt_revoke_transfer(grant_ref_t entry) |
314 | { | | 322 | { |
315 | paddr_t page; | | 323 | paddr_t page; |
316 | uint16_t flags; | | 324 | uint16_t flags; |
317 | | | 325 | |
318 | /* if the transfer has not started, free the entry and return 0 */ | | 326 | /* if the transfer has not started, free the entry and return 0 */ |
319 | while (!((flags = grant_table[entry].flags) & GTF_transfer_committed)) { | | 327 | while (!((flags = grant_table[entry].flags) & GTF_transfer_committed)) { |
320 | if (xen_atomic_cmpxchg16(&grant_table[entry].flags, | | 328 | if (xen_atomic_cmpxchg16(&grant_table[entry].flags, |
321 | flags, 0) == flags ) { | | 329 | flags, 0) == flags ) { |