aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/drm_bufs.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@starflyer.(none)>2005-06-23 07:29:18 -0400
committerDave Airlie <airlied@linux.ie>2005-06-23 07:29:18 -0400
commit9a18664506dbce5e23f3c5de7b1c5a042dd26520 (patch)
tree8f047c14a507b3f925e50f797650b15e23058a77 /drivers/char/drm/drm_bufs.c
parentee98689be1b054897ff17655008c3048fe88be94 (diff)
drm: 32/64-bit DRM ioctl compatibility patch
The patch is against a 2.6.11 kernel tree. I am running this with a 32-bit X server (compiled up from X.org CVS as of a couple of weeks ago) and 32-bit DRI libraries and clients. All the userland stuff is identical to what I am using under a 32-bit kernel on my G4 powerbook (which is a 32-bit machine of course). I haven't tried compiling up a 64-bit X server or clients yet. In the compatibility routines I have assumed that the kernel can safely access user addresses after set_fs(KERNEL_DS). That is, where an ioctl argument structure contains pointers to other structures, and those other structures are already compatible between the 32-bit and 64-bit ABIs (i.e. they only contain things like chars, shorts or ints), I just check the address with access_ok() and then pass it through to the 64-bit ioctl code. I believe this approach may not work on sparc64, but it does work on ppc64 and x86_64 at least. One tricky area which may need to be revisited is the question of how to handle the handles which we pass back to userspace to identify mappings. These handles are generated in the ADDMAP ioctl and then passed in as the offset value to mmap. However, offset values for mmap seem to be generated in other ways as well, particularly for AGP mappings. The approach I have ended up with is to generate a fake 32-bit handle only for _DRM_SHM mappings. The handles for other mappings (AGP, REG, FB) are physical addresses which are already limited to 32 bits, and generating fake handles for them created all sorts of problems in the mmap/nopage code. This patch has been updated to use the new compatibility ioctls. From: Paul Mackerras <paulus@samba.org> Signed-off-by: Dave Airlie <airlied@linux.ie>
Diffstat (limited to 'drivers/char/drm/drm_bufs.c')
-rw-r--r--drivers/char/drm/drm_bufs.c25
1 files changed, 18 insertions, 7 deletions
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 4113bcba67fe..3407380b865a 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -60,6 +60,15 @@ int drm_order( unsigned long size )
60} 60}
61EXPORT_SYMBOL(drm_order); 61EXPORT_SYMBOL(drm_order);
62 62
63#ifdef CONFIG_COMPAT
64/*
65 * Used to allocate 32-bit handles for _DRM_SHM regions
66 * The 0x10000000 value is chosen to be out of the way of
67 * FB/register and GART physical addresses.
68 */
69static unsigned int map32_handle = 0x10000000;
70#endif
71
63/** 72/**
64 * Ioctl to specify a range of memory that is available for mapping by a non-root process. 73 * Ioctl to specify a range of memory that is available for mapping by a non-root process.
65 * 74 *
@@ -187,16 +196,18 @@ int drm_addmap( struct inode *inode, struct file *filp,
187 196
188 down(&dev->struct_sem); 197 down(&dev->struct_sem);
189 list_add(&list->head, &dev->maplist->head); 198 list_add(&list->head, &dev->maplist->head);
199#ifdef CONFIG_COMPAT
200 /* Assign a 32-bit handle for _DRM_SHM mappings */
201 /* We do it here so that dev->struct_sem protects the increment */
202 if (map->type == _DRM_SHM)
203 map->offset = map32_handle += PAGE_SIZE;
204#endif
190 up(&dev->struct_sem); 205 up(&dev->struct_sem);
191 206
192 if ( copy_to_user( argp, map, sizeof(*map) ) ) 207 if ( copy_to_user( argp, map, sizeof(*map) ) )
193 return -EFAULT; 208 return -EFAULT;
194 if ( map->type != _DRM_SHM ) { 209 if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
195 if ( copy_to_user( &argp->handle, 210 return -EFAULT;
196 &map->offset,
197 sizeof(map->offset) ) )
198 return -EFAULT;
199 }
200 return 0; 211 return 0;
201} 212}
202 213
@@ -240,7 +251,7 @@ int drm_rmmap(struct inode *inode, struct file *filp,
240 r_list = list_entry(list, drm_map_list_t, head); 251 r_list = list_entry(list, drm_map_list_t, head);
241 252
242 if(r_list->map && 253 if(r_list->map &&
243 r_list->map->handle == request.handle && 254 r_list->map->offset == (unsigned long) request.handle &&
244 r_list->map->flags & _DRM_REMOVABLE) break; 255 r_list->map->flags & _DRM_REMOVABLE) break;
245 } 256 }
246 257