Branch data Line data Source code
1 : : /*
2 : : * \file drm_ioc32.c
3 : : *
4 : : * 32-bit ioctl compatibility routines for the DRM.
5 : : *
6 : : * \author Paul Mackerras <paulus@samba.org>
7 : : *
8 : : * Copyright (C) Paul Mackerras 2005.
9 : : * All Rights Reserved.
10 : : *
11 : : * Permission is hereby granted, free of charge, to any person obtaining a
12 : : * copy of this software and associated documentation files (the "Software"),
13 : : * to deal in the Software without restriction, including without limitation
14 : : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : : * and/or sell copies of the Software, and to permit persons to whom the
16 : : * Software is furnished to do so, subject to the following conditions:
17 : : *
18 : : * The above copyright notice and this permission notice (including the next
19 : : * paragraph) shall be included in all copies or substantial portions of the
20 : : * Software.
21 : : *
22 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : : * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 : : * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 : : * IN THE SOFTWARE.
29 : : */
30 : : #include <linux/compat.h>
31 : : #include <linux/ratelimit.h>
32 : : #include <linux/export.h>
33 : :
34 : : #include <drm/drm_agpsupport.h>
35 : : #include <drm/drm_file.h>
36 : : #include <drm/drm_print.h>
37 : :
38 : : #include "drm_crtc_internal.h"
39 : : #include "drm_internal.h"
40 : : #include "drm_legacy.h"
41 : :
42 : : #define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t)
43 : : #define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t)
44 : : #define DRM_IOCTL_GET_MAP32 DRM_IOWR(0x04, drm_map32_t)
45 : : #define DRM_IOCTL_GET_CLIENT32 DRM_IOWR(0x05, drm_client32_t)
46 : : #define DRM_IOCTL_GET_STATS32 DRM_IOR( 0x06, drm_stats32_t)
47 : :
48 : : #define DRM_IOCTL_SET_UNIQUE32 DRM_IOW( 0x10, drm_unique32_t)
49 : : #define DRM_IOCTL_ADD_MAP32 DRM_IOWR(0x15, drm_map32_t)
50 : : #define DRM_IOCTL_ADD_BUFS32 DRM_IOWR(0x16, drm_buf_desc32_t)
51 : : #define DRM_IOCTL_MARK_BUFS32 DRM_IOW( 0x17, drm_buf_desc32_t)
52 : : #define DRM_IOCTL_INFO_BUFS32 DRM_IOWR(0x18, drm_buf_info32_t)
53 : : #define DRM_IOCTL_MAP_BUFS32 DRM_IOWR(0x19, drm_buf_map32_t)
54 : : #define DRM_IOCTL_FREE_BUFS32 DRM_IOW( 0x1a, drm_buf_free32_t)
55 : :
56 : : #define DRM_IOCTL_RM_MAP32 DRM_IOW( 0x1b, drm_map32_t)
57 : :
58 : : #define DRM_IOCTL_SET_SAREA_CTX32 DRM_IOW( 0x1c, drm_ctx_priv_map32_t)
59 : : #define DRM_IOCTL_GET_SAREA_CTX32 DRM_IOWR(0x1d, drm_ctx_priv_map32_t)
60 : :
61 : : #define DRM_IOCTL_RES_CTX32 DRM_IOWR(0x26, drm_ctx_res32_t)
62 : : #define DRM_IOCTL_DMA32 DRM_IOWR(0x29, drm_dma32_t)
63 : :
64 : : #define DRM_IOCTL_AGP_ENABLE32 DRM_IOW( 0x32, drm_agp_mode32_t)
65 : : #define DRM_IOCTL_AGP_INFO32 DRM_IOR( 0x33, drm_agp_info32_t)
66 : : #define DRM_IOCTL_AGP_ALLOC32 DRM_IOWR(0x34, drm_agp_buffer32_t)
67 : : #define DRM_IOCTL_AGP_FREE32 DRM_IOW( 0x35, drm_agp_buffer32_t)
68 : : #define DRM_IOCTL_AGP_BIND32 DRM_IOW( 0x36, drm_agp_binding32_t)
69 : : #define DRM_IOCTL_AGP_UNBIND32 DRM_IOW( 0x37, drm_agp_binding32_t)
70 : :
71 : : #define DRM_IOCTL_SG_ALLOC32 DRM_IOW( 0x38, drm_scatter_gather32_t)
72 : : #define DRM_IOCTL_SG_FREE32 DRM_IOW( 0x39, drm_scatter_gather32_t)
73 : :
74 : : #define DRM_IOCTL_UPDATE_DRAW32 DRM_IOW( 0x3f, drm_update_draw32_t)
75 : :
76 : : #define DRM_IOCTL_WAIT_VBLANK32 DRM_IOWR(0x3a, drm_wait_vblank32_t)
77 : :
78 : : #define DRM_IOCTL_MODE_ADDFB232 DRM_IOWR(0xb8, drm_mode_fb_cmd232_t)
79 : :
80 : : typedef struct drm_version_32 {
81 : : int version_major; /* Major version */
82 : : int version_minor; /* Minor version */
83 : : int version_patchlevel; /* Patch level */
84 : : u32 name_len; /* Length of name buffer */
85 : : u32 name; /* Name of driver */
86 : : u32 date_len; /* Length of date buffer */
87 : : u32 date; /* User-space buffer to hold date */
88 : : u32 desc_len; /* Length of desc buffer */
89 : : u32 desc; /* User-space buffer to hold desc */
90 : : } drm_version32_t;
91 : :
92 : 0 : static int compat_drm_version(struct file *file, unsigned int cmd,
93 : : unsigned long arg)
94 : : {
95 : 0 : drm_version32_t v32;
96 : 0 : struct drm_version v;
97 : 0 : int err;
98 : :
99 [ # # ]: 0 : if (copy_from_user(&v32, (void __user *)arg, sizeof(v32)))
100 : : return -EFAULT;
101 : :
102 : 0 : v = (struct drm_version) {
103 : 0 : .name_len = v32.name_len,
104 : 0 : .name = compat_ptr(v32.name),
105 : 0 : .date_len = v32.date_len,
106 : 0 : .date = compat_ptr(v32.date),
107 : 0 : .desc_len = v32.desc_len,
108 : 0 : .desc = compat_ptr(v32.desc),
109 : : };
110 : 0 : err = drm_ioctl_kernel(file, drm_version, &v,
111 : : DRM_RENDER_ALLOW);
112 [ # # ]: 0 : if (err)
113 : : return err;
114 : :
115 : 0 : v32.version_major = v.version_major;
116 : 0 : v32.version_minor = v.version_minor;
117 : 0 : v32.version_patchlevel = v.version_patchlevel;
118 : 0 : v32.name_len = v.name_len;
119 : 0 : v32.date_len = v.date_len;
120 : 0 : v32.desc_len = v.desc_len;
121 [ # # ]: 0 : if (copy_to_user((void __user *)arg, &v32, sizeof(v32)))
122 : 0 : return -EFAULT;
123 : : return 0;
124 : : }
125 : :
126 : : typedef struct drm_unique32 {
127 : : u32 unique_len; /* Length of unique */
128 : : u32 unique; /* Unique name for driver instantiation */
129 : : } drm_unique32_t;
130 : :
131 : 0 : static int compat_drm_getunique(struct file *file, unsigned int cmd,
132 : : unsigned long arg)
133 : : {
134 : 0 : drm_unique32_t uq32;
135 : 0 : struct drm_unique uq;
136 : 0 : int err;
137 : :
138 [ # # ]: 0 : if (copy_from_user(&uq32, (void __user *)arg, sizeof(uq32)))
139 : : return -EFAULT;
140 : 0 : uq = (struct drm_unique){
141 : 0 : .unique_len = uq32.unique_len,
142 : 0 : .unique = compat_ptr(uq32.unique),
143 : : };
144 : :
145 : 0 : err = drm_ioctl_kernel(file, drm_getunique, &uq, 0);
146 [ # # ]: 0 : if (err)
147 : : return err;
148 : :
149 : 0 : uq32.unique_len = uq.unique_len;
150 [ # # ]: 0 : if (copy_to_user((void __user *)arg, &uq32, sizeof(uq32)))
151 : 0 : return -EFAULT;
152 : : return 0;
153 : : }
154 : :
155 : 0 : static int compat_drm_setunique(struct file *file, unsigned int cmd,
156 : : unsigned long arg)
157 : : {
158 : : /* it's dead */
159 : 0 : return -EINVAL;
160 : : }
161 : :
162 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
163 : : typedef struct drm_map32 {
164 : : u32 offset; /* Requested physical address (0 for SAREA) */
165 : : u32 size; /* Requested physical size (bytes) */
166 : : enum drm_map_type type; /* Type of memory to map */
167 : : enum drm_map_flags flags; /* Flags */
168 : : u32 handle; /* User-space: "Handle" to pass to mmap() */
169 : : int mtrr; /* MTRR slot used */
170 : : } drm_map32_t;
171 : :
172 : : static int compat_drm_getmap(struct file *file, unsigned int cmd,
173 : : unsigned long arg)
174 : : {
175 : : drm_map32_t __user *argp = (void __user *)arg;
176 : : drm_map32_t m32;
177 : : struct drm_map map;
178 : : int err;
179 : :
180 : : if (copy_from_user(&m32, argp, sizeof(m32)))
181 : : return -EFAULT;
182 : :
183 : : map.offset = m32.offset;
184 : : err = drm_ioctl_kernel(file, drm_legacy_getmap_ioctl, &map, 0);
185 : : if (err)
186 : : return err;
187 : :
188 : : m32.offset = map.offset;
189 : : m32.size = map.size;
190 : : m32.type = map.type;
191 : : m32.flags = map.flags;
192 : : m32.handle = ptr_to_compat((void __user *)map.handle);
193 : : m32.mtrr = map.mtrr;
194 : : if (copy_to_user(argp, &m32, sizeof(m32)))
195 : : return -EFAULT;
196 : : return 0;
197 : :
198 : : }
199 : :
200 : : static int compat_drm_addmap(struct file *file, unsigned int cmd,
201 : : unsigned long arg)
202 : : {
203 : : drm_map32_t __user *argp = (void __user *)arg;
204 : : drm_map32_t m32;
205 : : struct drm_map map;
206 : : int err;
207 : :
208 : : if (copy_from_user(&m32, argp, sizeof(m32)))
209 : : return -EFAULT;
210 : :
211 : : map.offset = m32.offset;
212 : : map.size = m32.size;
213 : : map.type = m32.type;
214 : : map.flags = m32.flags;
215 : :
216 : : err = drm_ioctl_kernel(file, drm_legacy_addmap_ioctl, &map,
217 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
218 : : if (err)
219 : : return err;
220 : :
221 : : m32.offset = map.offset;
222 : : m32.mtrr = map.mtrr;
223 : : m32.handle = ptr_to_compat((void __user *)map.handle);
224 : : if (map.handle != compat_ptr(m32.handle))
225 : : pr_err_ratelimited("compat_drm_addmap truncated handle %p for type %d offset %x\n",
226 : : map.handle, m32.type, m32.offset);
227 : :
228 : : if (copy_to_user(argp, &m32, sizeof(m32)))
229 : : return -EFAULT;
230 : :
231 : : return 0;
232 : : }
233 : :
234 : : static int compat_drm_rmmap(struct file *file, unsigned int cmd,
235 : : unsigned long arg)
236 : : {
237 : : drm_map32_t __user *argp = (void __user *)arg;
238 : : struct drm_map map;
239 : : u32 handle;
240 : :
241 : : if (get_user(handle, &argp->handle))
242 : : return -EFAULT;
243 : : map.handle = compat_ptr(handle);
244 : : return drm_ioctl_kernel(file, drm_legacy_rmmap_ioctl, &map, DRM_AUTH);
245 : : }
246 : : #endif
247 : :
248 : : typedef struct drm_client32 {
249 : : int idx; /* Which client desired? */
250 : : int auth; /* Is client authenticated? */
251 : : u32 pid; /* Process ID */
252 : : u32 uid; /* User ID */
253 : : u32 magic; /* Magic */
254 : : u32 iocs; /* Ioctl count */
255 : : } drm_client32_t;
256 : :
257 : 0 : static int compat_drm_getclient(struct file *file, unsigned int cmd,
258 : : unsigned long arg)
259 : : {
260 : 0 : drm_client32_t c32;
261 : 0 : drm_client32_t __user *argp = (void __user *)arg;
262 : 0 : struct drm_client client;
263 : 0 : int err;
264 : :
265 [ # # ]: 0 : if (copy_from_user(&c32, argp, sizeof(c32)))
266 : : return -EFAULT;
267 : :
268 : 0 : client.idx = c32.idx;
269 : :
270 : 0 : err = drm_ioctl_kernel(file, drm_getclient, &client, 0);
271 [ # # ]: 0 : if (err)
272 : : return err;
273 : :
274 : 0 : c32.idx = client.idx;
275 : 0 : c32.auth = client.auth;
276 : 0 : c32.pid = client.pid;
277 : 0 : c32.uid = client.uid;
278 : 0 : c32.magic = client.magic;
279 : 0 : c32.iocs = client.iocs;
280 : :
281 [ # # ]: 0 : if (copy_to_user(argp, &c32, sizeof(c32)))
282 : 0 : return -EFAULT;
283 : : return 0;
284 : : }
285 : :
286 : : typedef struct drm_stats32 {
287 : : u32 count;
288 : : struct {
289 : : u32 value;
290 : : enum drm_stat_type type;
291 : : } data[15];
292 : : } drm_stats32_t;
293 : :
294 : 0 : static int compat_drm_getstats(struct file *file, unsigned int cmd,
295 : : unsigned long arg)
296 : : {
297 : 0 : drm_stats32_t __user *argp = (void __user *)arg;
298 : 0 : int err;
299 : :
300 : 0 : err = drm_ioctl_kernel(file, drm_noop, NULL, 0);
301 [ # # ]: 0 : if (err)
302 : : return err;
303 : :
304 [ # # ]: 0 : if (clear_user(argp, sizeof(drm_stats32_t)))
305 : 0 : return -EFAULT;
306 : : return 0;
307 : : }
308 : :
309 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
310 : : typedef struct drm_buf_desc32 {
311 : : int count; /* Number of buffers of this size */
312 : : int size; /* Size in bytes */
313 : : int low_mark; /* Low water mark */
314 : : int high_mark; /* High water mark */
315 : : int flags;
316 : : u32 agp_start; /* Start address in the AGP aperture */
317 : : } drm_buf_desc32_t;
318 : :
319 : : static int compat_drm_addbufs(struct file *file, unsigned int cmd,
320 : : unsigned long arg)
321 : : {
322 : : drm_buf_desc32_t __user *argp = (void __user *)arg;
323 : : drm_buf_desc32_t desc32;
324 : : struct drm_buf_desc desc;
325 : : int err;
326 : :
327 : : if (copy_from_user(&desc32, argp, sizeof(drm_buf_desc32_t)))
328 : : return -EFAULT;
329 : :
330 : : desc = (struct drm_buf_desc){
331 : : desc32.count, desc32.size, desc32.low_mark, desc32.high_mark,
332 : : desc32.flags, desc32.agp_start
333 : : };
334 : :
335 : : err = drm_ioctl_kernel(file, drm_legacy_addbufs, &desc,
336 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
337 : : if (err)
338 : : return err;
339 : :
340 : : desc32 = (drm_buf_desc32_t){
341 : : desc.count, desc.size, desc.low_mark, desc.high_mark,
342 : : desc.flags, desc.agp_start
343 : : };
344 : : if (copy_to_user(argp, &desc32, sizeof(drm_buf_desc32_t)))
345 : : return -EFAULT;
346 : :
347 : : return 0;
348 : : }
349 : :
350 : : static int compat_drm_markbufs(struct file *file, unsigned int cmd,
351 : : unsigned long arg)
352 : : {
353 : : drm_buf_desc32_t b32;
354 : : drm_buf_desc32_t __user *argp = (void __user *)arg;
355 : : struct drm_buf_desc buf;
356 : :
357 : : if (copy_from_user(&b32, argp, sizeof(b32)))
358 : : return -EFAULT;
359 : :
360 : : buf.size = b32.size;
361 : : buf.low_mark = b32.low_mark;
362 : : buf.high_mark = b32.high_mark;
363 : :
364 : : return drm_ioctl_kernel(file, drm_legacy_markbufs, &buf,
365 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
366 : : }
367 : :
368 : : typedef struct drm_buf_info32 {
369 : : int count; /**< Entries in list */
370 : : u32 list;
371 : : } drm_buf_info32_t;
372 : :
373 : : static int copy_one_buf32(void *data, int count, struct drm_buf_entry *from)
374 : : {
375 : : drm_buf_info32_t *request = data;
376 : : drm_buf_desc32_t __user *to = compat_ptr(request->list);
377 : : drm_buf_desc32_t v = {.count = from->buf_count,
378 : : .size = from->buf_size,
379 : : .low_mark = from->low_mark,
380 : : .high_mark = from->high_mark};
381 : :
382 : : if (copy_to_user(to + count, &v, offsetof(drm_buf_desc32_t, flags)))
383 : : return -EFAULT;
384 : : return 0;
385 : : }
386 : :
387 : : static int drm_legacy_infobufs32(struct drm_device *dev, void *data,
388 : : struct drm_file *file_priv)
389 : : {
390 : : drm_buf_info32_t *request = data;
391 : : return __drm_legacy_infobufs(dev, data, &request->count, copy_one_buf32);
392 : : }
393 : :
394 : : static int compat_drm_infobufs(struct file *file, unsigned int cmd,
395 : : unsigned long arg)
396 : : {
397 : : drm_buf_info32_t req32;
398 : : drm_buf_info32_t __user *argp = (void __user *)arg;
399 : : int err;
400 : :
401 : : if (copy_from_user(&req32, argp, sizeof(req32)))
402 : : return -EFAULT;
403 : :
404 : : if (req32.count < 0)
405 : : req32.count = 0;
406 : :
407 : : err = drm_ioctl_kernel(file, drm_legacy_infobufs32, &req32, DRM_AUTH);
408 : : if (err)
409 : : return err;
410 : :
411 : : if (put_user(req32.count, &argp->count))
412 : : return -EFAULT;
413 : :
414 : : return 0;
415 : : }
416 : :
417 : : typedef struct drm_buf_pub32 {
418 : : int idx; /**< Index into the master buffer list */
419 : : int total; /**< Buffer size */
420 : : int used; /**< Amount of buffer in use (for DMA) */
421 : : u32 address; /**< Address of buffer */
422 : : } drm_buf_pub32_t;
423 : :
424 : : typedef struct drm_buf_map32 {
425 : : int count; /**< Length of the buffer list */
426 : : u32 virtual; /**< Mmap'd area in user-virtual */
427 : : u32 list; /**< Buffer information */
428 : : } drm_buf_map32_t;
429 : :
430 : : static int map_one_buf32(void *data, int idx, unsigned long virtual,
431 : : struct drm_buf *buf)
432 : : {
433 : : drm_buf_map32_t *request = data;
434 : : drm_buf_pub32_t __user *to = compat_ptr(request->list) + idx;
435 : : drm_buf_pub32_t v;
436 : :
437 : : v.idx = buf->idx;
438 : : v.total = buf->total;
439 : : v.used = 0;
440 : : v.address = virtual + buf->offset;
441 : : if (copy_to_user(to, &v, sizeof(v)))
442 : : return -EFAULT;
443 : : return 0;
444 : : }
445 : :
446 : : static int drm_legacy_mapbufs32(struct drm_device *dev, void *data,
447 : : struct drm_file *file_priv)
448 : : {
449 : : drm_buf_map32_t *request = data;
450 : : void __user *v;
451 : : int err = __drm_legacy_mapbufs(dev, data, &request->count,
452 : : &v, map_one_buf32,
453 : : file_priv);
454 : : request->virtual = ptr_to_compat(v);
455 : : return err;
456 : : }
457 : :
458 : : static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
459 : : unsigned long arg)
460 : : {
461 : : drm_buf_map32_t __user *argp = (void __user *)arg;
462 : : drm_buf_map32_t req32;
463 : : int err;
464 : :
465 : : if (copy_from_user(&req32, argp, sizeof(req32)))
466 : : return -EFAULT;
467 : : if (req32.count < 0)
468 : : return -EINVAL;
469 : :
470 : : err = drm_ioctl_kernel(file, drm_legacy_mapbufs32, &req32, DRM_AUTH);
471 : : if (err)
472 : : return err;
473 : :
474 : : if (put_user(req32.count, &argp->count)
475 : : || put_user(req32.virtual, &argp->virtual))
476 : : return -EFAULT;
477 : :
478 : : return 0;
479 : : }
480 : :
481 : : typedef struct drm_buf_free32 {
482 : : int count;
483 : : u32 list;
484 : : } drm_buf_free32_t;
485 : :
486 : : static int compat_drm_freebufs(struct file *file, unsigned int cmd,
487 : : unsigned long arg)
488 : : {
489 : : drm_buf_free32_t req32;
490 : : struct drm_buf_free request;
491 : : drm_buf_free32_t __user *argp = (void __user *)arg;
492 : :
493 : : if (copy_from_user(&req32, argp, sizeof(req32)))
494 : : return -EFAULT;
495 : :
496 : : request.count = req32.count;
497 : : request.list = compat_ptr(req32.list);
498 : : return drm_ioctl_kernel(file, drm_legacy_freebufs, &request, DRM_AUTH);
499 : : }
500 : :
501 : : typedef struct drm_ctx_priv_map32 {
502 : : unsigned int ctx_id; /**< Context requesting private mapping */
503 : : u32 handle; /**< Handle of map */
504 : : } drm_ctx_priv_map32_t;
505 : :
506 : : static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
507 : : unsigned long arg)
508 : : {
509 : : drm_ctx_priv_map32_t req32;
510 : : struct drm_ctx_priv_map request;
511 : : drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
512 : :
513 : : if (copy_from_user(&req32, argp, sizeof(req32)))
514 : : return -EFAULT;
515 : :
516 : : request.ctx_id = req32.ctx_id;
517 : : request.handle = compat_ptr(req32.handle);
518 : : return drm_ioctl_kernel(file, drm_legacy_setsareactx, &request,
519 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
520 : : }
521 : :
522 : : static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
523 : : unsigned long arg)
524 : : {
525 : : struct drm_ctx_priv_map req;
526 : : drm_ctx_priv_map32_t req32;
527 : : drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
528 : : int err;
529 : :
530 : : if (copy_from_user(&req32, argp, sizeof(req32)))
531 : : return -EFAULT;
532 : :
533 : : req.ctx_id = req32.ctx_id;
534 : : err = drm_ioctl_kernel(file, drm_legacy_getsareactx, &req, DRM_AUTH);
535 : : if (err)
536 : : return err;
537 : :
538 : : req32.handle = ptr_to_compat((void __user *)req.handle);
539 : : if (copy_to_user(argp, &req32, sizeof(req32)))
540 : : return -EFAULT;
541 : :
542 : : return 0;
543 : : }
544 : :
545 : : typedef struct drm_ctx_res32 {
546 : : int count;
547 : : u32 contexts;
548 : : } drm_ctx_res32_t;
549 : :
550 : : static int compat_drm_resctx(struct file *file, unsigned int cmd,
551 : : unsigned long arg)
552 : : {
553 : : drm_ctx_res32_t __user *argp = (void __user *)arg;
554 : : drm_ctx_res32_t res32;
555 : : struct drm_ctx_res res;
556 : : int err;
557 : :
558 : : if (copy_from_user(&res32, argp, sizeof(res32)))
559 : : return -EFAULT;
560 : :
561 : : res.count = res32.count;
562 : : res.contexts = compat_ptr(res32.contexts);
563 : : err = drm_ioctl_kernel(file, drm_legacy_resctx, &res, DRM_AUTH);
564 : : if (err)
565 : : return err;
566 : :
567 : : res32.count = res.count;
568 : : if (copy_to_user(argp, &res32, sizeof(res32)))
569 : : return -EFAULT;
570 : :
571 : : return 0;
572 : : }
573 : :
574 : : typedef struct drm_dma32 {
575 : : int context; /**< Context handle */
576 : : int send_count; /**< Number of buffers to send */
577 : : u32 send_indices; /**< List of handles to buffers */
578 : : u32 send_sizes; /**< Lengths of data to send */
579 : : enum drm_dma_flags flags; /**< Flags */
580 : : int request_count; /**< Number of buffers requested */
581 : : int request_size; /**< Desired size for buffers */
582 : : u32 request_indices; /**< Buffer information */
583 : : u32 request_sizes;
584 : : int granted_count; /**< Number of buffers granted */
585 : : } drm_dma32_t;
586 : :
587 : : static int compat_drm_dma(struct file *file, unsigned int cmd,
588 : : unsigned long arg)
589 : : {
590 : : drm_dma32_t d32;
591 : : drm_dma32_t __user *argp = (void __user *)arg;
592 : : struct drm_dma d;
593 : : int err;
594 : :
595 : : if (copy_from_user(&d32, argp, sizeof(d32)))
596 : : return -EFAULT;
597 : :
598 : : d.context = d32.context;
599 : : d.send_count = d32.send_count;
600 : : d.send_indices = compat_ptr(d32.send_indices);
601 : : d.send_sizes = compat_ptr(d32.send_sizes);
602 : : d.flags = d32.flags;
603 : : d.request_count = d32.request_count;
604 : : d.request_indices = compat_ptr(d32.request_indices);
605 : : d.request_sizes = compat_ptr(d32.request_sizes);
606 : : err = drm_ioctl_kernel(file, drm_legacy_dma_ioctl, &d, DRM_AUTH);
607 : : if (err)
608 : : return err;
609 : :
610 : : if (put_user(d.request_size, &argp->request_size)
611 : : || put_user(d.granted_count, &argp->granted_count))
612 : : return -EFAULT;
613 : :
614 : : return 0;
615 : : }
616 : : #endif
617 : :
618 : : #if IS_ENABLED(CONFIG_AGP)
619 : : typedef struct drm_agp_mode32 {
620 : : u32 mode; /**< AGP mode */
621 : : } drm_agp_mode32_t;
622 : :
623 : 0 : static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
624 : : unsigned long arg)
625 : : {
626 : 0 : drm_agp_mode32_t __user *argp = (void __user *)arg;
627 : 0 : struct drm_agp_mode mode;
628 : :
629 [ # # ]: 0 : if (get_user(mode.mode, &argp->mode))
630 : : return -EFAULT;
631 : :
632 : 0 : return drm_ioctl_kernel(file, drm_agp_enable_ioctl, &mode,
633 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
634 : : }
635 : :
636 : : typedef struct drm_agp_info32 {
637 : : int agp_version_major;
638 : : int agp_version_minor;
639 : : u32 mode;
640 : : u32 aperture_base; /* physical address */
641 : : u32 aperture_size; /* bytes */
642 : : u32 memory_allowed; /* bytes */
643 : : u32 memory_used;
644 : :
645 : : /* PCI information */
646 : : unsigned short id_vendor;
647 : : unsigned short id_device;
648 : : } drm_agp_info32_t;
649 : :
650 : 0 : static int compat_drm_agp_info(struct file *file, unsigned int cmd,
651 : : unsigned long arg)
652 : : {
653 : 0 : drm_agp_info32_t __user *argp = (void __user *)arg;
654 : 0 : drm_agp_info32_t i32;
655 : 0 : struct drm_agp_info info;
656 : 0 : int err;
657 : :
658 : 0 : err = drm_ioctl_kernel(file, drm_agp_info_ioctl, &info, DRM_AUTH);
659 [ # # ]: 0 : if (err)
660 : : return err;
661 : :
662 : 0 : i32.agp_version_major = info.agp_version_major;
663 : 0 : i32.agp_version_minor = info.agp_version_minor;
664 : 0 : i32.mode = info.mode;
665 : 0 : i32.aperture_base = info.aperture_base;
666 : 0 : i32.aperture_size = info.aperture_size;
667 : 0 : i32.memory_allowed = info.memory_allowed;
668 : 0 : i32.memory_used = info.memory_used;
669 : 0 : i32.id_vendor = info.id_vendor;
670 : 0 : i32.id_device = info.id_device;
671 [ # # ]: 0 : if (copy_to_user(argp, &i32, sizeof(i32)))
672 : 0 : return -EFAULT;
673 : :
674 : : return 0;
675 : : }
676 : :
677 : : typedef struct drm_agp_buffer32 {
678 : : u32 size; /**< In bytes -- will round to page boundary */
679 : : u32 handle; /**< Used for binding / unbinding */
680 : : u32 type; /**< Type of memory to allocate */
681 : : u32 physical; /**< Physical used by i810 */
682 : : } drm_agp_buffer32_t;
683 : :
684 : 0 : static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
685 : : unsigned long arg)
686 : : {
687 : 0 : drm_agp_buffer32_t __user *argp = (void __user *)arg;
688 : 0 : drm_agp_buffer32_t req32;
689 : 0 : struct drm_agp_buffer request;
690 : 0 : int err;
691 : :
692 [ # # ]: 0 : if (copy_from_user(&req32, argp, sizeof(req32)))
693 : : return -EFAULT;
694 : :
695 : 0 : request.size = req32.size;
696 : 0 : request.type = req32.type;
697 : 0 : err = drm_ioctl_kernel(file, drm_agp_alloc_ioctl, &request,
698 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
699 [ # # ]: 0 : if (err)
700 : : return err;
701 : :
702 : 0 : req32.handle = request.handle;
703 : 0 : req32.physical = request.physical;
704 [ # # ]: 0 : if (copy_to_user(argp, &req32, sizeof(req32))) {
705 : 0 : drm_ioctl_kernel(file, drm_agp_free_ioctl, &request,
706 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
707 : 0 : return -EFAULT;
708 : : }
709 : :
710 : : return 0;
711 : : }
712 : :
713 : 0 : static int compat_drm_agp_free(struct file *file, unsigned int cmd,
714 : : unsigned long arg)
715 : : {
716 : 0 : drm_agp_buffer32_t __user *argp = (void __user *)arg;
717 : 0 : struct drm_agp_buffer request;
718 : :
719 [ # # ]: 0 : if (get_user(request.handle, &argp->handle))
720 : : return -EFAULT;
721 : :
722 : 0 : return drm_ioctl_kernel(file, drm_agp_free_ioctl, &request,
723 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
724 : : }
725 : :
726 : : typedef struct drm_agp_binding32 {
727 : : u32 handle; /**< From drm_agp_buffer */
728 : : u32 offset; /**< In bytes -- will round to page boundary */
729 : : } drm_agp_binding32_t;
730 : :
731 : 0 : static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
732 : : unsigned long arg)
733 : : {
734 : 0 : drm_agp_binding32_t __user *argp = (void __user *)arg;
735 : 0 : drm_agp_binding32_t req32;
736 : 0 : struct drm_agp_binding request;
737 : :
738 [ # # ]: 0 : if (copy_from_user(&req32, argp, sizeof(req32)))
739 : : return -EFAULT;
740 : :
741 : 0 : request.handle = req32.handle;
742 : 0 : request.offset = req32.offset;
743 : 0 : return drm_ioctl_kernel(file, drm_agp_bind_ioctl, &request,
744 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
745 : : }
746 : :
747 : 0 : static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
748 : : unsigned long arg)
749 : : {
750 : 0 : drm_agp_binding32_t __user *argp = (void __user *)arg;
751 : 0 : struct drm_agp_binding request;
752 : :
753 [ # # ]: 0 : if (get_user(request.handle, &argp->handle))
754 : : return -EFAULT;
755 : :
756 : 0 : return drm_ioctl_kernel(file, drm_agp_unbind_ioctl, &request,
757 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
758 : : }
759 : : #endif /* CONFIG_AGP */
760 : :
761 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
762 : : typedef struct drm_scatter_gather32 {
763 : : u32 size; /**< In bytes -- will round to page boundary */
764 : : u32 handle; /**< Used for mapping / unmapping */
765 : : } drm_scatter_gather32_t;
766 : :
767 : : static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
768 : : unsigned long arg)
769 : : {
770 : : drm_scatter_gather32_t __user *argp = (void __user *)arg;
771 : : struct drm_scatter_gather request;
772 : : int err;
773 : :
774 : : if (get_user(request.size, &argp->size))
775 : : return -EFAULT;
776 : :
777 : : err = drm_ioctl_kernel(file, drm_legacy_sg_alloc, &request,
778 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
779 : : if (err)
780 : : return err;
781 : :
782 : : /* XXX not sure about the handle conversion here... */
783 : : if (put_user(request.handle >> PAGE_SHIFT, &argp->handle))
784 : : return -EFAULT;
785 : :
786 : : return 0;
787 : : }
788 : :
789 : : static int compat_drm_sg_free(struct file *file, unsigned int cmd,
790 : : unsigned long arg)
791 : : {
792 : : drm_scatter_gather32_t __user *argp = (void __user *)arg;
793 : : struct drm_scatter_gather request;
794 : : unsigned long x;
795 : :
796 : : if (get_user(x, &argp->handle))
797 : : return -EFAULT;
798 : : request.handle = x << PAGE_SHIFT;
799 : : return drm_ioctl_kernel(file, drm_legacy_sg_free, &request,
800 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
801 : : }
802 : : #endif
803 : : #if defined(CONFIG_X86)
804 : : typedef struct drm_update_draw32 {
805 : : drm_drawable_t handle;
806 : : unsigned int type;
807 : : unsigned int num;
808 : : /* 64-bit version has a 32-bit pad here */
809 : : u64 data; /**< Pointer */
810 : : } __attribute__((packed)) drm_update_draw32_t;
811 : :
812 : 0 : static int compat_drm_update_draw(struct file *file, unsigned int cmd,
813 : : unsigned long arg)
814 : : {
815 : 0 : drm_update_draw32_t update32;
816 [ # # ]: 0 : if (copy_from_user(&update32, (void __user *)arg, sizeof(update32)))
817 : : return -EFAULT;
818 : :
819 : 0 : return drm_ioctl_kernel(file, drm_noop, NULL,
820 : : DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY);
821 : : }
822 : : #endif
823 : :
824 : : struct drm_wait_vblank_request32 {
825 : : enum drm_vblank_seq_type type;
826 : : unsigned int sequence;
827 : : u32 signal;
828 : : };
829 : :
830 : : struct drm_wait_vblank_reply32 {
831 : : enum drm_vblank_seq_type type;
832 : : unsigned int sequence;
833 : : s32 tval_sec;
834 : : s32 tval_usec;
835 : : };
836 : :
837 : : typedef union drm_wait_vblank32 {
838 : : struct drm_wait_vblank_request32 request;
839 : : struct drm_wait_vblank_reply32 reply;
840 : : } drm_wait_vblank32_t;
841 : :
842 : 0 : static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
843 : : unsigned long arg)
844 : : {
845 : 0 : drm_wait_vblank32_t __user *argp = (void __user *)arg;
846 : 0 : drm_wait_vblank32_t req32;
847 : 0 : union drm_wait_vblank req;
848 : 0 : int err;
849 : :
850 [ # # ]: 0 : if (copy_from_user(&req32, argp, sizeof(req32)))
851 : : return -EFAULT;
852 : :
853 : 0 : req.request.type = req32.request.type;
854 : 0 : req.request.sequence = req32.request.sequence;
855 : 0 : req.request.signal = req32.request.signal;
856 : 0 : err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED);
857 [ # # ]: 0 : if (err)
858 : : return err;
859 : :
860 : 0 : req32.reply.type = req.reply.type;
861 : 0 : req32.reply.sequence = req.reply.sequence;
862 : 0 : req32.reply.tval_sec = req.reply.tval_sec;
863 : 0 : req32.reply.tval_usec = req.reply.tval_usec;
864 [ # # ]: 0 : if (copy_to_user(argp, &req32, sizeof(req32)))
865 : 0 : return -EFAULT;
866 : :
867 : : return 0;
868 : : }
869 : :
870 : : #if defined(CONFIG_X86)
871 : : typedef struct drm_mode_fb_cmd232 {
872 : : u32 fb_id;
873 : : u32 width;
874 : : u32 height;
875 : : u32 pixel_format;
876 : : u32 flags;
877 : : u32 handles[4];
878 : : u32 pitches[4];
879 : : u32 offsets[4];
880 : : u64 modifier[4];
881 : : } __attribute__((packed)) drm_mode_fb_cmd232_t;
882 : :
883 : 0 : static int compat_drm_mode_addfb2(struct file *file, unsigned int cmd,
884 : : unsigned long arg)
885 : : {
886 : 0 : struct drm_mode_fb_cmd232 __user *argp = (void __user *)arg;
887 : 0 : struct drm_mode_fb_cmd2 req64;
888 : 0 : int err;
889 : :
890 [ # # ]: 0 : if (copy_from_user(&req64, argp,
891 : : offsetof(drm_mode_fb_cmd232_t, modifier)))
892 : : return -EFAULT;
893 : :
894 [ # # ]: 0 : if (copy_from_user(&req64.modifier, &argp->modifier,
895 : : sizeof(req64.modifier)))
896 : : return -EFAULT;
897 : :
898 : 0 : err = drm_ioctl_kernel(file, drm_mode_addfb2, &req64, 0);
899 [ # # ]: 0 : if (err)
900 : : return err;
901 : :
902 [ # # ]: 0 : if (put_user(req64.fb_id, &argp->fb_id))
903 : 0 : return -EFAULT;
904 : :
905 : : return 0;
906 : : }
907 : : #endif
908 : :
909 : : static struct {
910 : : drm_ioctl_compat_t *fn;
911 : : char *name;
912 : : } drm_compat_ioctls[] = {
913 : : #define DRM_IOCTL32_DEF(n, f) [DRM_IOCTL_NR(n##32)] = {.fn = f, .name = #n}
914 : : DRM_IOCTL32_DEF(DRM_IOCTL_VERSION, compat_drm_version),
915 : : DRM_IOCTL32_DEF(DRM_IOCTL_GET_UNIQUE, compat_drm_getunique),
916 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
917 : : DRM_IOCTL32_DEF(DRM_IOCTL_GET_MAP, compat_drm_getmap),
918 : : #endif
919 : : DRM_IOCTL32_DEF(DRM_IOCTL_GET_CLIENT, compat_drm_getclient),
920 : : DRM_IOCTL32_DEF(DRM_IOCTL_GET_STATS, compat_drm_getstats),
921 : : DRM_IOCTL32_DEF(DRM_IOCTL_SET_UNIQUE, compat_drm_setunique),
922 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
923 : : DRM_IOCTL32_DEF(DRM_IOCTL_ADD_MAP, compat_drm_addmap),
924 : : DRM_IOCTL32_DEF(DRM_IOCTL_ADD_BUFS, compat_drm_addbufs),
925 : : DRM_IOCTL32_DEF(DRM_IOCTL_MARK_BUFS, compat_drm_markbufs),
926 : : DRM_IOCTL32_DEF(DRM_IOCTL_INFO_BUFS, compat_drm_infobufs),
927 : : DRM_IOCTL32_DEF(DRM_IOCTL_MAP_BUFS, compat_drm_mapbufs),
928 : : DRM_IOCTL32_DEF(DRM_IOCTL_FREE_BUFS, compat_drm_freebufs),
929 : : DRM_IOCTL32_DEF(DRM_IOCTL_RM_MAP, compat_drm_rmmap),
930 : : DRM_IOCTL32_DEF(DRM_IOCTL_SET_SAREA_CTX, compat_drm_setsareactx),
931 : : DRM_IOCTL32_DEF(DRM_IOCTL_GET_SAREA_CTX, compat_drm_getsareactx),
932 : : DRM_IOCTL32_DEF(DRM_IOCTL_RES_CTX, compat_drm_resctx),
933 : : DRM_IOCTL32_DEF(DRM_IOCTL_DMA, compat_drm_dma),
934 : : #endif
935 : : #if IS_ENABLED(CONFIG_AGP)
936 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ENABLE, compat_drm_agp_enable),
937 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_INFO, compat_drm_agp_info),
938 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_ALLOC, compat_drm_agp_alloc),
939 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_FREE, compat_drm_agp_free),
940 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_BIND, compat_drm_agp_bind),
941 : : DRM_IOCTL32_DEF(DRM_IOCTL_AGP_UNBIND, compat_drm_agp_unbind),
942 : : #endif
943 : : #if IS_ENABLED(CONFIG_DRM_LEGACY)
944 : : DRM_IOCTL32_DEF(DRM_IOCTL_SG_ALLOC, compat_drm_sg_alloc),
945 : : DRM_IOCTL32_DEF(DRM_IOCTL_SG_FREE, compat_drm_sg_free),
946 : : #endif
947 : : #if defined(CONFIG_X86) || defined(CONFIG_IA64)
948 : : DRM_IOCTL32_DEF(DRM_IOCTL_UPDATE_DRAW, compat_drm_update_draw),
949 : : #endif
950 : : DRM_IOCTL32_DEF(DRM_IOCTL_WAIT_VBLANK, compat_drm_wait_vblank),
951 : : #if defined(CONFIG_X86) || defined(CONFIG_IA64)
952 : : DRM_IOCTL32_DEF(DRM_IOCTL_MODE_ADDFB2, compat_drm_mode_addfb2),
953 : : #endif
954 : : };
955 : :
956 : : /**
957 : : * drm_compat_ioctl - 32bit IOCTL compatibility handler for DRM drivers
958 : : * @filp: file this ioctl is called on
959 : : * @cmd: ioctl cmd number
960 : : * @arg: user argument
961 : : *
962 : : * Compatibility handler for 32 bit userspace running on 64 kernels. All actual
963 : : * IOCTL handling is forwarded to drm_ioctl(), while marshalling structures as
964 : : * appropriate. Note that this only handles DRM core IOCTLs, if the driver has
965 : : * botched IOCTL itself, it must handle those by wrapping this function.
966 : : *
967 : : * Returns:
968 : : * Zero on success, negative error code on failure.
969 : : */
970 : 0 : long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
971 : : {
972 : 0 : unsigned int nr = DRM_IOCTL_NR(cmd);
973 : 0 : struct drm_file *file_priv = filp->private_data;
974 : 0 : drm_ioctl_compat_t *fn;
975 : 0 : int ret;
976 : :
977 : : /* Assume that ioctls without an explicit compat routine will just
978 : : * work. This may not always be a good assumption, but it's better
979 : : * than always failing.
980 : : */
981 [ # # ]: 0 : if (nr >= ARRAY_SIZE(drm_compat_ioctls))
982 : 0 : return drm_ioctl(filp, cmd, arg);
983 : :
984 : 0 : fn = drm_compat_ioctls[nr].fn;
985 [ # # ]: 0 : if (!fn)
986 : 0 : return drm_ioctl(filp, cmd, arg);
987 : :
988 : 0 : DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
989 : : task_pid_nr(current),
990 : : (long)old_encode_dev(file_priv->minor->kdev->devt),
991 : : file_priv->authenticated,
992 : : drm_compat_ioctls[nr].name);
993 : 0 : ret = (*fn)(filp, cmd, arg);
994 [ # # ]: 0 : if (ret)
995 : 0 : DRM_DEBUG("ret = %d\n", ret);
996 : 0 : return ret;
997 : : }
998 : : EXPORT_SYMBOL(drm_compat_ioctl);
|