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