| @@ -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 */ |
59 | int gnt_nr_grant_frames; | | 68 | int 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 */ |
61 | int gnt_max_grant_frames; | | 70 | int gnt_max_grant_frames; |
62 | /* Number of grant status frames */ | | | |
63 | int gnt_status_frames; | | | |
64 | | | 71 | |
65 | /* table of free grant entries */ | | 72 | /* table of free grant entries */ |
66 | grant_ref_t *gnt_entries; | | 73 | grant_ref_t *gnt_entries; |
67 | /* last free entry */ | | 74 | /* last free entry */ |
68 | int last_gnt_entry; | | 75 | int 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 | |
73 | grant_entry_v2_t *grant_table; | | 84 | grant_entry_v2_t *grant_table; |
| | | 85 | /* Number of grant status frames */ |
| | | 86 | int gnt_status_frames; |
| | | 87 | |
74 | grant_status_t *grant_status; | | 88 | grant_status_t *grant_status; |
| | | 89 | #else /* USE_GRANT_V2 */ |
| | | 90 | #define NR_GRANT_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(grant_entry_v1_t)) |
| | | 91 | grant_entry_v1_t *grant_table; |
| | | 92 | #endif /* USE_GRANT_V2 */ |
75 | kmutex_t grant_lock; | | 93 | kmutex_t grant_lock; |
76 | | | 94 | |
77 | static grant_ref_t xengnt_get_entry(void); | | 95 | static grant_ref_t xengnt_get_entry(void); |
78 | static void xengnt_free_entry(grant_ref_t); | | 96 | static void xengnt_free_entry(grant_ref_t); |
79 | static int xengnt_more_entries(void); | | 97 | static int xengnt_more_entries(void); |
80 | static int xengnt_map_status(void); | | 98 | static int xengnt_map_status(void); |
81 | | | 99 | |
82 | void | | 100 | void |
83 | xengnt_init(void) | | 101 | xengnt_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 | */ |
137 | bool | | 160 | bool |
138 | xengnt_resume(void) | | 161 | xengnt_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 | */ |
185 | static int | | 210 | static int |
186 | xengnt_map_status(void) | | 211 | xengnt_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 | */ |
237 | static int | | 265 | static int |
238 | xengnt_more_entries(void) | | 266 | xengnt_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) |
360 | static void | | 388 | static void |
361 | xengnt_free_entry(grant_ref_t entry) | | 389 | xengnt_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 |
373 | int | | 402 | int |
374 | xengnt_grant_access(domid_t dom, paddr_t ma, int ro, grant_ref_t *entryp) | | 403 | xengnt_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 | |
421 | int | | 449 | int |
422 | xengnt_status(grant_ref_t entry) | | 450 | xengnt_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 | |
| | | 456 | int |
| | | 457 | xengnt_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 | |
| | | 481 | static inline uint16_t |
| | | 482 | xen_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 | |
| | | 495 | void |
| | | 496 | xengnt_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 | |
| | | 512 | int |
| | | 513 | xengnt_status(grant_ref_t entry) |
| | | 514 | { |
| | | 515 | return (grant_table[entry].flags & (GTF_reading|GTF_writing)); |
| | | 516 | } |
| | | 517 | #endif /* USE_GRANT_V2 */ |