xref: /openbsd-src/sys/dev/pci/drm/drm_ioc32.c (revision f005ef32267c16bdb134f0e9fa4477dbe07c263a)
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