1 /******************************************************************************
2 * common/compat/grant_table.c
3 *
4 */
5
6 #include <xen/hypercall.h>
7 #include <compat/grant_table.h>
8
9 #define xen_grant_entry_v1 grant_entry_v1
10 CHECK_grant_entry_v1;
11 #undef xen_grant_entry_v1
12
13 #define xen_grant_entry_header grant_entry_header
14 CHECK_grant_entry_header;
15 #undef xen_grant_entry_header
16
17 #define xen_grant_entry_v2 grant_entry_v2
18 CHECK_grant_entry_v2;
19 #undef xen_grant_entry_v2
20
21 #define xen_gnttab_map_grant_ref gnttab_map_grant_ref
22 CHECK_gnttab_map_grant_ref;
23 #undef xen_gnttab_map_grant_ref
24
25 #define xen_gnttab_unmap_grant_ref gnttab_unmap_grant_ref
26 CHECK_gnttab_unmap_grant_ref;
27 #undef xen_gnttab_unmap_grant_ref
28
29 #define xen_gnttab_unmap_and_replace gnttab_unmap_and_replace
30 CHECK_gnttab_unmap_and_replace;
31 #undef xen_gnttab_unmap_and_replace
32
33 #define xen_gnttab_query_size gnttab_query_size
34 CHECK_gnttab_query_size;
35 #undef xen_gnttab_query_size
36
37 DEFINE_XEN_GUEST_HANDLE(gnttab_setup_table_compat_t);
38 DEFINE_XEN_GUEST_HANDLE(gnttab_transfer_compat_t);
39 DEFINE_XEN_GUEST_HANDLE(gnttab_copy_compat_t);
40
41 #define xen_gnttab_dump_table gnttab_dump_table
42 CHECK_gnttab_dump_table;
43 #undef xen_gnttab_dump_table
44
45 #define xen_gnttab_set_version gnttab_set_version
46 CHECK_gnttab_set_version;
47 #undef xen_gnttab_set_version
48
49 DEFINE_XEN_GUEST_HANDLE(gnttab_get_status_frames_compat_t);
50
51 #define xen_gnttab_get_version gnttab_get_version
52 CHECK_gnttab_get_version;
53 #undef xen_gnttab_get_version
54
55 #define xen_gnttab_swap_grant_ref gnttab_swap_grant_ref
56 CHECK_gnttab_swap_grant_ref;
57 #undef xen_gnttab_swap_grant_ref
58
59 #define xen_gnttab_cache_flush gnttab_cache_flush
60 CHECK_gnttab_cache_flush;
61 #undef xen_gnttab_cache_flush
62
compat_grant_table_op(unsigned int cmd,XEN_GUEST_HANDLE_PARAM (void)uop,unsigned int count)63 int compat_grant_table_op(
64 unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) uop, unsigned int count)
65 {
66 int rc = 0;
67 unsigned int i, cmd_op;
68 XEN_GUEST_HANDLE_PARAM(void) cnt_uop;
69
70 #ifdef CONFIG_PV_SHIM
71 if ( unlikely(pv_shim) )
72 return pv_shim_grant_table_op(cmd, uop, count);
73 #endif
74
75 set_xen_guest_handle(cnt_uop, NULL);
76 cmd_op = cmd & GNTTABOP_CMD_MASK;
77 if ( cmd_op != GNTTABOP_cache_flush )
78 cmd_op = cmd;
79 switch ( cmd_op )
80 {
81 #define CASE(name) \
82 case GNTTABOP_ ## name: \
83 { \
84 XEN_GUEST_HANDLE_PARAM(gnttab_ ## name ## _compat_t) h = \
85 guest_handle_cast(uop, gnttab_ ## name ## _compat_t); \
86 \
87 if ( unlikely(!guest_handle_okay(h, count)) ) \
88 rc = -EFAULT; \
89 } \
90 break
91
92 #ifndef CHECK_gnttab_map_grant_ref
93 CASE(map_grant_ref);
94 #endif
95
96 #ifndef CHECK_gnttab_unmap_grant_ref
97 CASE(unmap_grant_ref);
98 #endif
99
100 #ifndef CHECK_gnttab_unmap_and_replace
101 CASE(unmap_and_replace);
102 #endif
103
104 #ifndef CHECK_gnttab_setup_table
105 CASE(setup_table);
106 #endif
107
108 #ifndef CHECK_gnttab_transfer
109 CASE(transfer);
110 #endif
111
112 #ifndef CHECK_gnttab_copy
113 CASE(copy);
114 #endif
115
116 #ifndef CHECK_gnttab_query_size
117 CASE(query_size);
118 #endif
119
120 #ifndef CHECK_gnttab_dump_table
121 CASE(dump_table);
122 #endif
123
124 #ifndef CHECK_gnttab_get_status_frames
125 CASE(get_status_frames);
126 #endif
127
128 #ifndef CHECK_gnttab_swap_grant_ref
129 CASE(swap_grant_ref);
130 #endif
131
132 #ifndef CHECK_gnttab_cache_flush
133 CASE(cache_flush);
134 #endif
135
136 #undef CASE
137 default:
138 return do_grant_table_op(cmd, uop, count);
139 }
140
141 if ( (int)count < 0 )
142 rc = -EINVAL;
143
144 for ( i = 0; i < count && rc == 0; )
145 {
146 unsigned int n;
147 union {
148 XEN_GUEST_HANDLE(void) uop;
149 struct gnttab_setup_table *setup;
150 struct gnttab_transfer *xfer;
151 struct gnttab_copy *copy;
152 struct gnttab_get_status_frames *get_status;
153 } nat;
154 union {
155 struct compat_gnttab_setup_table setup;
156 struct compat_gnttab_transfer xfer;
157 struct compat_gnttab_copy copy;
158 struct compat_gnttab_get_status_frames get_status;
159 } cmp;
160
161 set_xen_guest_handle(nat.uop, COMPAT_ARG_XLAT_VIRT_BASE);
162 switch ( cmd_op )
163 {
164 case GNTTABOP_setup_table:
165 if ( unlikely(count > 1) )
166 rc = -EINVAL;
167 else if ( unlikely(__copy_from_guest(&cmp.setup, uop, 1)) )
168 rc = -EFAULT;
169 else if ( unlikely(!compat_handle_okay(cmp.setup.frame_list, cmp.setup.nr_frames)) )
170 rc = -EFAULT;
171 else
172 {
173 unsigned int max_frame_list_size_in_page =
174 (COMPAT_ARG_XLAT_SIZE - sizeof(*nat.setup)) /
175 sizeof(*nat.setup->frame_list.p);
176
177 #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
178 set_xen_guest_handle((_d_)->frame_list, (unsigned long *)(nat.setup + 1))
179 XLAT_gnttab_setup_table(nat.setup, &cmp.setup);
180 #undef XLAT_gnttab_setup_table_HNDL_frame_list
181 rc = gnttab_setup_table(guest_handle_cast(nat.uop,
182 gnttab_setup_table_t),
183 1, max_frame_list_size_in_page);
184 }
185 ASSERT(rc <= 0);
186 if ( rc == 0 )
187 {
188 #define XLAT_gnttab_setup_table_HNDL_frame_list(_d_, _s_) \
189 do \
190 { \
191 if ( (_s_)->status == GNTST_okay ) \
192 { \
193 for ( i = 0; i < (_s_)->nr_frames; ++i ) \
194 { \
195 compat_pfn_t frame = (_s_)->frame_list.p[i]; \
196 if ( frame != (_s_)->frame_list.p[i] ) \
197 { \
198 (_s_)->status = GNTST_address_too_big; \
199 break; \
200 } \
201 if ( __copy_to_compat_offset((_d_)->frame_list, \
202 i, &frame, 1) ) \
203 { \
204 (_s_)->status = GNTST_bad_virt_addr; \
205 break; \
206 } \
207 } \
208 } \
209 } while (0)
210 XLAT_gnttab_setup_table(&cmp.setup, nat.setup);
211 #undef XLAT_gnttab_setup_table_HNDL_frame_list
212 if ( unlikely(__copy_to_guest(uop, &cmp.setup, 1)) )
213 rc = -EFAULT;
214 else
215 i = 1;
216 }
217 break;
218
219 case GNTTABOP_transfer:
220 for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.xfer) && i < count && rc == 0; ++i, ++n )
221 {
222 if ( unlikely(__copy_from_guest_offset(&cmp.xfer, uop, i, 1)) )
223 rc = -EFAULT;
224 else
225 {
226 XLAT_gnttab_transfer(nat.xfer + n, &cmp.xfer);
227 }
228 }
229 if ( rc == 0 )
230 rc = gnttab_transfer(guest_handle_cast(nat.uop, gnttab_transfer_t), n);
231 if ( rc > 0 )
232 {
233 ASSERT(rc < n);
234 i -= n - rc;
235 n = rc;
236 }
237 if ( rc >= 0 )
238 {
239 XEN_GUEST_HANDLE_PARAM(gnttab_transfer_compat_t) xfer;
240
241 xfer = guest_handle_cast(uop, gnttab_transfer_compat_t);
242 guest_handle_add_offset(xfer, i);
243 cnt_uop = guest_handle_cast(xfer, void);
244 while ( n-- )
245 {
246 guest_handle_subtract_offset(xfer, 1);
247 if ( __copy_field_to_guest(xfer, nat.xfer + n, status) )
248 rc = -EFAULT;
249 }
250 }
251 break;
252
253 case GNTTABOP_copy:
254 for ( n = 0; n < COMPAT_ARG_XLAT_SIZE / sizeof(*nat.copy) && i < count && rc == 0; ++i, ++n )
255 {
256 if ( unlikely(__copy_from_guest_offset(&cmp.copy, uop, i, 1)) )
257 rc = -EFAULT;
258 else
259 {
260 enum XLAT_gnttab_copy_source_u source_u;
261 enum XLAT_gnttab_copy_dest_u dest_u;
262
263 if ( cmp.copy.flags & GNTCOPY_source_gref )
264 source_u = XLAT_gnttab_copy_source_u_ref;
265 else
266 source_u = XLAT_gnttab_copy_source_u_gmfn;
267 if ( cmp.copy.flags & GNTCOPY_dest_gref )
268 dest_u = XLAT_gnttab_copy_dest_u_ref;
269 else
270 dest_u = XLAT_gnttab_copy_dest_u_gmfn;
271 XLAT_gnttab_copy(nat.copy + n, &cmp.copy);
272 }
273 }
274 if ( rc == 0 )
275 rc = gnttab_copy(guest_handle_cast(nat.uop, gnttab_copy_t), n);
276 if ( rc > 0 )
277 {
278 ASSERT(rc <= n);
279 i -= rc;
280 n -= rc;
281 }
282 if ( rc >= 0 )
283 {
284 XEN_GUEST_HANDLE_PARAM(gnttab_copy_compat_t) copy;
285
286 copy = guest_handle_cast(uop, gnttab_copy_compat_t);
287 guest_handle_add_offset(copy, i);
288 cnt_uop = guest_handle_cast(copy, void);
289 while ( n-- )
290 {
291 guest_handle_subtract_offset(copy, 1);
292 if ( __copy_field_to_guest(copy, nat.copy + n, status) )
293 rc = -EFAULT;
294 }
295 }
296 break;
297
298 case GNTTABOP_get_status_frames:
299 if ( count != 1)
300 {
301 rc = -EINVAL;
302 break;
303 }
304 if ( unlikely(__copy_from_guest(&cmp.get_status, uop, 1) ||
305 !compat_handle_okay(cmp.get_status.frame_list,
306 cmp.get_status.nr_frames)) )
307 {
308 rc = -EFAULT;
309 break;
310 }
311
312 #define XLAT_gnttab_get_status_frames_HNDL_frame_list(_d_, _s_) \
313 guest_from_compat_handle((_d_)->frame_list, (_s_)->frame_list)
314 XLAT_gnttab_get_status_frames(nat.get_status, &cmp.get_status);
315 #undef XLAT_gnttab_get_status_frames_HNDL_frame_list
316
317 rc = gnttab_get_status_frames(
318 guest_handle_cast(nat.uop, gnttab_get_status_frames_t), count);
319 if ( rc >= 0 )
320 {
321 XEN_GUEST_HANDLE_PARAM(gnttab_get_status_frames_compat_t) get =
322 guest_handle_cast(uop,
323 gnttab_get_status_frames_compat_t);
324
325 if ( unlikely(__copy_field_to_guest(get, nat.get_status,
326 status)) )
327 rc = -EFAULT;
328 else
329 i = 1;
330 }
331 break;
332
333 default:
334 domain_crash(current->domain);
335 break;
336 }
337 }
338
339 if ( rc > 0 )
340 {
341 ASSERT(i < count);
342 ASSERT(!guest_handle_is_null(cnt_uop));
343 rc = hypercall_create_continuation(__HYPERVISOR_grant_table_op,
344 "ihi", cmd, cnt_uop, count - i);
345 }
346
347 return rc;
348 }
349
350 /*
351 * Local variables:
352 * mode: C
353 * c-file-style: "BSD"
354 * c-basic-offset: 4
355 * tab-width: 4
356 * indent-tabs-mode: nil
357 * End:
358 */
359