1/** 2 * \file radeon_ioc32.c 3 * 4 * 32-bit ioctl compatibility routines for the Radeon 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 32#include <drm/drmP.h> 33#include <drm/radeon_drm.h> 34#include "radeon_drv.h" 35 36typedef struct drm_radeon_init32 { 37 int func; 38 u32 sarea_priv_offset; 39 int is_pci; 40 int cp_mode; 41 int gart_size; 42 int ring_size; 43 int usec_timeout; 44 45 unsigned int fb_bpp; 46 unsigned int front_offset, front_pitch; 47 unsigned int back_offset, back_pitch; 48 unsigned int depth_bpp; 49 unsigned int depth_offset, depth_pitch; 50 51 u32 fb_offset; 52 u32 mmio_offset; 53 u32 ring_offset; 54 u32 ring_rptr_offset; 55 u32 buffers_offset; 56 u32 gart_textures_offset; 57} drm_radeon_init32_t; 58 59static int compat_radeon_cp_init(struct file *file, unsigned int cmd, 60 unsigned long arg) 61{ 62 drm_radeon_init32_t init32; 63 drm_radeon_init_t __user *init; 64 65 if (copy_from_user(&init32, (void __user *)arg, sizeof(init32))) 66 return -EFAULT; 67 68 init = compat_alloc_user_space(sizeof(*init)); 69 if (!access_ok(VERIFY_WRITE, init, sizeof(*init)) 70 || __put_user(init32.func, &init->func) 71 || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset) 72 || __put_user(init32.is_pci, &init->is_pci) 73 || __put_user(init32.cp_mode, &init->cp_mode) 74 || __put_user(init32.gart_size, &init->gart_size) 75 || __put_user(init32.ring_size, &init->ring_size) 76 || __put_user(init32.usec_timeout, &init->usec_timeout) 77 || __put_user(init32.fb_bpp, &init->fb_bpp) 78 || __put_user(init32.front_offset, &init->front_offset) 79 || __put_user(init32.front_pitch, &init->front_pitch) 80 || __put_user(init32.back_offset, &init->back_offset) 81 || __put_user(init32.back_pitch, &init->back_pitch) 82 || __put_user(init32.depth_bpp, &init->depth_bpp) 83 || __put_user(init32.depth_offset, &init->depth_offset) 84 || __put_user(init32.depth_pitch, &init->depth_pitch) 85 || __put_user(init32.fb_offset, &init->fb_offset) 86 || __put_user(init32.mmio_offset, &init->mmio_offset) 87 || __put_user(init32.ring_offset, &init->ring_offset) 88 || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset) 89 || __put_user(init32.buffers_offset, &init->buffers_offset) 90 || __put_user(init32.gart_textures_offset, 91 &init->gart_textures_offset)) 92 return -EFAULT; 93 94 return drm_ioctl(file, DRM_IOCTL_RADEON_CP_INIT, (unsigned long)init); 95} 96 97typedef struct drm_radeon_clear32 { 98 unsigned int flags; 99 unsigned int clear_color; 100 unsigned int clear_depth; 101 unsigned int color_mask; 102 unsigned int depth_mask; /* misnamed field: should be stencil */ 103 u32 depth_boxes; 104} drm_radeon_clear32_t; 105 106static int compat_radeon_cp_clear(struct file *file, unsigned int cmd, 107 unsigned long arg) 108{ 109 drm_radeon_clear32_t clr32; 110 drm_radeon_clear_t __user *clr; 111 112 if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32))) 113 return -EFAULT; 114 115 clr = compat_alloc_user_space(sizeof(*clr)); 116 if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr)) 117 || __put_user(clr32.flags, &clr->flags) 118 || __put_user(clr32.clear_color, &clr->clear_color) 119 || __put_user(clr32.clear_depth, &clr->clear_depth) 120 || __put_user(clr32.color_mask, &clr->color_mask) 121 || __put_user(clr32.depth_mask, &clr->depth_mask) 122 || __put_user((void __user *)(unsigned long)clr32.depth_boxes, 123 &clr->depth_boxes)) 124 return -EFAULT; 125 126 return drm_ioctl(file, DRM_IOCTL_RADEON_CLEAR, (unsigned long)clr); 127} 128 129typedef struct drm_radeon_stipple32 { 130 u32 mask; 131} drm_radeon_stipple32_t; 132 133static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd, 134 unsigned long arg) 135{ 136 drm_radeon_stipple32_t __user *argp = (void __user *)arg; 137 drm_radeon_stipple_t __user *request; 138 u32 mask; 139 140 if (get_user(mask, &argp->mask)) 141 return -EFAULT; 142 143 request = compat_alloc_user_space(sizeof(*request)); 144 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 145 || __put_user((unsigned int __user *)(unsigned long)mask, 146 &request->mask)) 147 return -EFAULT; 148 149 return drm_ioctl(file, DRM_IOCTL_RADEON_STIPPLE, (unsigned long)request); 150} 151 152typedef struct drm_radeon_tex_image32 { 153 unsigned int x, y; /* Blit coordinates */ 154 unsigned int width, height; 155 u32 data; 156} drm_radeon_tex_image32_t; 157 158typedef struct drm_radeon_texture32 { 159 unsigned int offset; 160 int pitch; 161 int format; 162 int width; /* Texture image coordinates */ 163 int height; 164 u32 image; 165} drm_radeon_texture32_t; 166 167static int compat_radeon_cp_texture(struct file *file, unsigned int cmd, 168 unsigned long arg) 169{ 170 drm_radeon_texture32_t req32; 171 drm_radeon_texture_t __user *request; 172 drm_radeon_tex_image32_t img32; 173 drm_radeon_tex_image_t __user *image; 174 175 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 176 return -EFAULT; 177 if (req32.image == 0) 178 return -EINVAL; 179 if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image, 180 sizeof(img32))) 181 return -EFAULT; 182 183 request = compat_alloc_user_space(sizeof(*request) + sizeof(*image)); 184 if (!access_ok(VERIFY_WRITE, request, 185 sizeof(*request) + sizeof(*image))) 186 return -EFAULT; 187 image = (drm_radeon_tex_image_t __user *) (request + 1); 188 189 if (__put_user(req32.offset, &request->offset) 190 || __put_user(req32.pitch, &request->pitch) 191 || __put_user(req32.format, &request->format) 192 || __put_user(req32.width, &request->width) 193 || __put_user(req32.height, &request->height) 194 || __put_user(image, &request->image) 195 || __put_user(img32.x, &image->x) 196 || __put_user(img32.y, &image->y) 197 || __put_user(img32.width, &image->width) 198 || __put_user(img32.height, &image->height) 199 || __put_user((const void __user *)(unsigned long)img32.data, 200 &image->data)) 201 return -EFAULT; 202 203 return drm_ioctl(file, DRM_IOCTL_RADEON_TEXTURE, (unsigned long)request); 204} 205 206typedef struct drm_radeon_vertex2_32 { 207 int idx; /* Index of vertex buffer */ 208 int discard; /* Client finished with buffer? */ 209 int nr_states; 210 u32 state; 211 int nr_prims; 212 u32 prim; 213} drm_radeon_vertex2_32_t; 214 215static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd, 216 unsigned long arg) 217{ 218 drm_radeon_vertex2_32_t req32; 219 drm_radeon_vertex2_t __user *request; 220 221 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 222 return -EFAULT; 223 224 request = compat_alloc_user_space(sizeof(*request)); 225 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 226 || __put_user(req32.idx, &request->idx) 227 || __put_user(req32.discard, &request->discard) 228 || __put_user(req32.nr_states, &request->nr_states) 229 || __put_user((void __user *)(unsigned long)req32.state, 230 &request->state) 231 || __put_user(req32.nr_prims, &request->nr_prims) 232 || __put_user((void __user *)(unsigned long)req32.prim, 233 &request->prim)) 234 return -EFAULT; 235 236 return drm_ioctl(file, DRM_IOCTL_RADEON_VERTEX2, (unsigned long)request); 237} 238 239typedef struct drm_radeon_cmd_buffer32 { 240 int bufsz; 241 u32 buf; 242 int nbox; 243 u32 boxes; 244} drm_radeon_cmd_buffer32_t; 245 246static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd, 247 unsigned long arg) 248{ 249 drm_radeon_cmd_buffer32_t req32; 250 drm_radeon_cmd_buffer_t __user *request; 251 252 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 253 return -EFAULT; 254 255 request = compat_alloc_user_space(sizeof(*request)); 256 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 257 || __put_user(req32.bufsz, &request->bufsz) 258 || __put_user((void __user *)(unsigned long)req32.buf, 259 &request->buf) 260 || __put_user(req32.nbox, &request->nbox) 261 || __put_user((void __user *)(unsigned long)req32.boxes, 262 &request->boxes)) 263 return -EFAULT; 264 265 return drm_ioctl(file, DRM_IOCTL_RADEON_CMDBUF, (unsigned long)request); 266} 267 268typedef struct drm_radeon_getparam32 { 269 int param; 270 u32 value; 271} drm_radeon_getparam32_t; 272 273static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd, 274 unsigned long arg) 275{ 276 drm_radeon_getparam32_t req32; 277 drm_radeon_getparam_t __user *request; 278 279 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 280 return -EFAULT; 281 282 request = compat_alloc_user_space(sizeof(*request)); 283 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 284 || __put_user(req32.param, &request->param) 285 || __put_user((void __user *)(unsigned long)req32.value, 286 &request->value)) 287 return -EFAULT; 288 289 return drm_ioctl(file, DRM_IOCTL_RADEON_GETPARAM, (unsigned long)request); 290} 291 292typedef struct drm_radeon_mem_alloc32 { 293 int region; 294 int alignment; 295 int size; 296 u32 region_offset; /* offset from start of fb or GART */ 297} drm_radeon_mem_alloc32_t; 298 299static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd, 300 unsigned long arg) 301{ 302 drm_radeon_mem_alloc32_t req32; 303 drm_radeon_mem_alloc_t __user *request; 304 305 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 306 return -EFAULT; 307 308 request = compat_alloc_user_space(sizeof(*request)); 309 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 310 || __put_user(req32.region, &request->region) 311 || __put_user(req32.alignment, &request->alignment) 312 || __put_user(req32.size, &request->size) 313 || __put_user((int __user *)(unsigned long)req32.region_offset, 314 &request->region_offset)) 315 return -EFAULT; 316 317 return drm_ioctl(file, DRM_IOCTL_RADEON_ALLOC, (unsigned long)request); 318} 319 320typedef struct drm_radeon_irq_emit32 { 321 u32 irq_seq; 322} drm_radeon_irq_emit32_t; 323 324static int compat_radeon_irq_emit(struct file *file, unsigned int cmd, 325 unsigned long arg) 326{ 327 drm_radeon_irq_emit32_t req32; 328 drm_radeon_irq_emit_t __user *request; 329 330 if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) 331 return -EFAULT; 332 333 request = compat_alloc_user_space(sizeof(*request)); 334 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 335 || __put_user((int __user *)(unsigned long)req32.irq_seq, 336 &request->irq_seq)) 337 return -EFAULT; 338 339 return drm_ioctl(file, DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long)request); 340} 341 342/* The two 64-bit arches where alignof(u64)==4 in 32-bit code */ 343#if defined (CONFIG_X86_64) || defined(CONFIG_IA64) 344typedef struct drm_radeon_setparam32 { 345 int param; 346 u64 value; 347} __attribute__((packed)) drm_radeon_setparam32_t; 348 349static int compat_radeon_cp_setparam(struct file *file, unsigned int cmd, 350 unsigned long arg) 351{ 352 drm_radeon_setparam32_t req32; 353 drm_radeon_setparam_t __user *request; 354 355 if (copy_from_user(&req32, (void __user *) arg, sizeof(req32))) 356 return -EFAULT; 357 358 request = compat_alloc_user_space(sizeof(*request)); 359 if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) 360 || __put_user(req32.param, &request->param) 361 || __put_user((void __user *)(unsigned long)req32.value, 362 &request->value)) 363 return -EFAULT; 364 365 return drm_ioctl(file, DRM_IOCTL_RADEON_SETPARAM, (unsigned long) request); 366} 367#else 368#define compat_radeon_cp_setparam NULL 369#endif /* X86_64 || IA64 */ 370 371static drm_ioctl_compat_t *radeon_compat_ioctls[] = { 372 [DRM_RADEON_CP_INIT] = compat_radeon_cp_init, 373 [DRM_RADEON_CLEAR] = compat_radeon_cp_clear, 374 [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple, 375 [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture, 376 [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2, 377 [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf, 378 [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam, 379 [DRM_RADEON_SETPARAM] = compat_radeon_cp_setparam, 380 [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc, 381 [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit, 382}; 383 384/** 385 * Called whenever a 32-bit process running under a 64-bit kernel 386 * performs an ioctl on /dev/dri/card<n>. 387 * 388 * \param filp file pointer. 389 * \param cmd command. 390 * \param arg user argument. 391 * \return zero on success or negative number on failure. 392 */ 393long radeon_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 394{ 395 unsigned int nr = DRM_IOCTL_NR(cmd); 396 drm_ioctl_compat_t *fn = NULL; 397 int ret; 398 399 if (nr < DRM_COMMAND_BASE) 400 return drm_compat_ioctl(filp, cmd, arg); 401 402 if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(radeon_compat_ioctls)) 403 fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE]; 404 405 if (fn != NULL) 406 ret = (*fn) (filp, cmd, arg); 407 else 408 ret = drm_ioctl(filp, cmd, arg); 409 410 return ret; 411} 412 413long radeon_kms_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 414{ 415 unsigned int nr = DRM_IOCTL_NR(cmd); 416 int ret; 417 418 if (nr < DRM_COMMAND_BASE) 419 return drm_compat_ioctl(filp, cmd, arg); 420 421 ret = radeon_drm_ioctl(filp, cmd, arg); 422 423 return ret; 424} 425