User: | Jiri Slaby |
Error type: | Invalid Pointer Dereference |
Error type description: | A pointer which is invalid is being dereferenced |
File location: | drivers/media/video/videobuf-vmalloc.c |
Line in file: | 142 |
Project: | Linux Kernel |
Project version: | 2.6.28 |
Tools: |
Stanse
(1.2)
Smatch (1.59) |
Entered: | 2011-11-07 22:22:22 UTC |
1/* 2 * helper functions for vmalloc video4linux capture buffers 3 * 4 * The functions expect the hardware being able to scatter gather 5 * (i.e. the buffers are not linear in physical memory, but fragmented 6 * into PAGE_SIZE chunks). They also assume the driver does not need 7 * to touch the video data. 8 * 9 * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 14 */ 15 16#include <linux/init.h> 17#include <linux/module.h> 18#include <linux/moduleparam.h> 19#include <linux/slab.h> 20#include <linux/interrupt.h> 21 22#include <linux/pci.h> 23#include <linux/vmalloc.h> 24#include <linux/pagemap.h> 25#include <asm/page.h> 26#include <asm/pgtable.h> 27 28#include <media/videobuf-vmalloc.h> 29 30#define MAGIC_DMABUF 0x17760309 31#define MAGIC_VMAL_MEM 0x18221223 32 33#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \ 34 { printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); } 35 36static int debug; 37module_param(debug, int, 0644); 38 39MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers"); 40MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); 41MODULE_LICENSE("GPL"); 42 43#define dprintk(level, fmt, arg...) if (debug >= level) \ 44 printk(KERN_DEBUG "vbuf-vmalloc: " fmt , ## arg) 45 46 47/***************************************************************************/ 48 49static void 50videobuf_vm_open(struct vm_area_struct *vma) 51{ 52 struct videobuf_mapping *map = vma->vm_private_data; 53 54 dprintk(2,"vm_open %p [count=%u,vma=%08lx-%08lx]\n",map, 55 map->count,vma->vm_start,vma->vm_end); 56 57 map->count++; 58} 59 60static void videobuf_vm_close(struct vm_area_struct *vma) 61{ 62 struct videobuf_mapping *map = vma->vm_private_data; 63 struct videobuf_queue *q = map->q; 64 int i; 65 66 dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map, 67 map->count, vma->vm_start, vma->vm_end); 68 69 map->count--; 70 if (0 == map->count) { 71 struct videobuf_vmalloc_memory *mem; 72 73 dprintk(1, "munmap %p q=%p\n", map, q); 74 mutex_lock(&q->vb_lock); 75 76 /* We need first to cancel streams, before unmapping */ 77 if (q->streaming) 78 videobuf_queue_cancel(q); 79 80 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 81 if (NULL == q->bufs[i]) 82 continue; 83 84 if (q->bufs[i]->map != map) 85 continue; 86 87 mem = q->bufs[i]->priv; 88 if (mem) { 89 /* This callback is called only if kernel has 90 allocated memory and this memory is mmapped. 91 In this case, memory should be freed, 92 in order to do memory unmap. 93 */ 94 95 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); 96 97 /* vfree is not atomic - can't be 98 called with IRQ's disabled 99 */ 100 dprintk(1, "%s: buf[%d] freeing (%p)\n", 101 __func__, i, mem->vmalloc); 102 103 vfree(mem->vmalloc); 104 mem->vmalloc = NULL; 105 } 106 107 q->bufs[i]->map = NULL; 108 q->bufs[i]->baddr = 0; 109 } 110 111 kfree(map); 112 113 mutex_unlock(&q->vb_lock); 114 } 115 116 return; 117} 118 119static struct vm_operations_struct videobuf_vm_ops = 120{ 121 .open = videobuf_vm_open, 122 .close = videobuf_vm_close, 123}; 124 125/* --------------------------------------------------------------------- 126 * vmalloc handlers for the generic methods 127 */ 128 129/* Allocated area consists on 3 parts: 130 struct video_buffer 131 struct <driver>_buffer (cx88_buffer, saa7134_buf, ...) 132 struct videobuf_dma_sg_memory 133 */ 134 135static void *__videobuf_alloc(size_t size) 136{ 137 struct videobuf_vmalloc_memory *mem; 138 struct videobuf_buffer *vb; 139 140 vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); 141 142 mem = vb->priv = ((char *)vb)+size; 143 mem->magic=MAGIC_VMAL_MEM; 144 145 dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n", 146 __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb), 147 mem,(long)sizeof(*mem)); 148 149 return vb; 150} 151 152static int __videobuf_iolock (struct videobuf_queue* q, 153 struct videobuf_buffer *vb, 154 struct v4l2_framebuffer *fbuf) 155{ 156 struct videobuf_vmalloc_memory *mem = vb->priv; 157 int pages; 158 159 BUG_ON(!mem); 160 161 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); 162 163 switch (vb->memory) { 164 case V4L2_MEMORY_MMAP: 165 dprintk(1, "%s memory method MMAP\n", __func__); 166 167 /* All handling should be done by __videobuf_mmap_mapper() */ 168 if (!mem->vmalloc) { 169 printk(KERN_ERR "memory is not alloced/mmapped.\n"); 170 return -EINVAL; 171 } 172 break; 173 case V4L2_MEMORY_USERPTR: 174 pages = PAGE_ALIGN(vb->size); 175 176 dprintk(1, "%s memory method USERPTR\n", __func__); 177 178#if 1 179 if (vb->baddr) { 180 printk(KERN_ERR "USERPTR is currently not supported\n"); 181 return -EINVAL; 182 } 183#endif 184 185 /* The only USERPTR currently supported is the one needed for 186 read() method. 187 */ 188 189 mem->vmalloc = vmalloc_user(pages); 190 if (!mem->vmalloc) { 191 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); 192 return -ENOMEM; 193 } 194 dprintk(1, "vmalloc is at addr %p (%d pages)\n", 195 mem->vmalloc, pages); 196 197#if 0 198 int rc; 199 /* Kernel userptr is used also by read() method. In this case, 200 there's no need to remap, since data will be copied to user 201 */ 202 if (!vb->baddr) 203 return 0; 204 205 /* FIXME: to properly support USERPTR, remap should occur. 206 The code below won't work, since mem->vma = NULL 207 */ 208 /* Try to remap memory */ 209 rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); 210 if (rc < 0) { 211 printk(KERN_ERR "mmap: remap failed with error %d. ", rc); 212 return -ENOMEM; 213 } 214#endif 215 216 break; 217 case V4L2_MEMORY_OVERLAY: 218 default: 219 dprintk(1, "%s memory method OVERLAY/unknown\n", __func__); 220 221 /* Currently, doesn't support V4L2_MEMORY_OVERLAY */ 222 printk(KERN_ERR "Memory method currently unsupported.\n"); 223 return -EINVAL; 224 } 225 226 return 0; 227} 228 229static int __videobuf_sync(struct videobuf_queue *q, 230 struct videobuf_buffer *buf) 231{ 232 return 0; 233} 234 235static int __videobuf_mmap_free(struct videobuf_queue *q) 236{ 237 unsigned int i; 238 239 dprintk(1, "%s\n", __func__); 240 for (i = 0; i < VIDEO_MAX_FRAME; i++) { 241 if (q->bufs[i]) { 242 if (q->bufs[i]->map) 243 return -EBUSY; 244 } 245 } 246 247 return 0; 248} 249 250static int __videobuf_mmap_mapper(struct videobuf_queue *q, 251 struct vm_area_struct *vma) 252{ 253 struct videobuf_vmalloc_memory *mem; 254 struct videobuf_mapping *map; 255 unsigned int first; 256 int retval, pages; 257 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; 258 259 dprintk(1, "%s\n", __func__); 260 if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) 261 return -EINVAL; 262 263 /* look for first buffer to map */ 264 for (first = 0; first < VIDEO_MAX_FRAME; first++) { 265 if (NULL == q->bufs[first]) 266 continue; 267 268 if (V4L2_MEMORY_MMAP != q->bufs[first]->memory) 269 continue; 270 if (q->bufs[first]->boff == offset) 271 break; 272 } 273 if (VIDEO_MAX_FRAME == first) { 274 dprintk(1,"mmap app bug: offset invalid [offset=0x%lx]\n", 275 (vma->vm_pgoff << PAGE_SHIFT)); 276 return -EINVAL; 277 } 278 279 /* create mapping + update buffer list */ 280 map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL); 281 if (NULL == map) 282 return -ENOMEM; 283 284 q->bufs[first]->map = map; 285 map->start = vma->vm_start; 286 map->end = vma->vm_end; 287 map->q = q; 288 289 q->bufs[first]->baddr = vma->vm_start; 290 291 mem = q->bufs[first]->priv; 292 BUG_ON(!mem); 293 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); 294 295 pages = PAGE_ALIGN(vma->vm_end - vma->vm_start); 296 mem->vmalloc = vmalloc_user(pages); 297 if (!mem->vmalloc) { 298 printk(KERN_ERR "vmalloc (%d pages) failed\n", pages); 299 goto error; 300 } 301 dprintk(1, "vmalloc is at addr %p (%d pages)\n", 302 mem->vmalloc, pages); 303 304 /* Try to remap memory */ 305 retval = remap_vmalloc_range(vma, mem->vmalloc, 0); 306 if (retval < 0) { 307 printk(KERN_ERR "mmap: remap failed with error %d. ", retval); 308 vfree(mem->vmalloc); 309 goto error; 310 } 311 312 vma->vm_ops = &videobuf_vm_ops; 313 vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED; 314 vma->vm_private_data = map; 315 316 dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n", 317 map, q, vma->vm_start, vma->vm_end, 318 (long int) q->bufs[first]->bsize, 319 vma->vm_pgoff, first); 320 321 videobuf_vm_open(vma); 322 323 return 0; 324 325error: 326 mem = NULL; 327 kfree(map); 328 return -ENOMEM; 329} 330 331static int __videobuf_copy_to_user ( struct videobuf_queue *q, 332 char __user *data, size_t count, 333 int nonblocking ) 334{ 335 struct videobuf_vmalloc_memory *mem=q->read_buf->priv; 336 BUG_ON (!mem); 337 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 338 339 BUG_ON (!mem->vmalloc); 340 341 /* copy to userspace */ 342 if (count > q->read_buf->size - q->read_off) 343 count = q->read_buf->size - q->read_off; 344 345 if (copy_to_user(data, mem->vmalloc+q->read_off, count)) 346 return -EFAULT; 347 348 return count; 349} 350 351static int __videobuf_copy_stream ( struct videobuf_queue *q, 352 char __user *data, size_t count, size_t pos, 353 int vbihack, int nonblocking ) 354{ 355 unsigned int *fc; 356 struct videobuf_vmalloc_memory *mem=q->read_buf->priv; 357 BUG_ON (!mem); 358 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 359 360 if (vbihack) { 361 /* dirty, undocumented hack -- pass the frame counter 362 * within the last four bytes of each vbi data block. 363 * We need that one to maintain backward compatibility 364 * to all vbi decoding software out there ... */ 365 fc = (unsigned int*)mem->vmalloc; 366 fc += (q->read_buf->size>>2) -1; 367 *fc = q->read_buf->field_count >> 1; 368 dprintk(1,"vbihack: %d\n",*fc); 369 } 370 371 /* copy stuff using the common method */ 372 count = __videobuf_copy_to_user (q,data,count,nonblocking); 373 374 if ( (count==-EFAULT) && (0 == pos) ) 375 return -EFAULT; 376 377 return count; 378} 379 380static struct videobuf_qtype_ops qops = { 381 .magic = MAGIC_QTYPE_OPS, 382 383 .alloc = __videobuf_alloc, 384 .iolock = __videobuf_iolock, 385 .sync = __videobuf_sync, 386 .mmap_free = __videobuf_mmap_free, 387 .mmap_mapper = __videobuf_mmap_mapper, 388 .video_copy_to_user = __videobuf_copy_to_user, 389 .copy_stream = __videobuf_copy_stream, 390 .vmalloc = videobuf_to_vmalloc, 391}; 392 393void videobuf_queue_vmalloc_init(struct videobuf_queue* q, 394 struct videobuf_queue_ops *ops, 395 void *dev, 396 spinlock_t *irqlock, 397 enum v4l2_buf_type type, 398 enum v4l2_field field, 399 unsigned int msize, 400 void *priv) 401{ 402 videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize, 403 priv, &qops); 404} 405 406EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); 407 408void *videobuf_to_vmalloc (struct videobuf_buffer *buf) 409{ 410 struct videobuf_vmalloc_memory *mem=buf->priv; 411 BUG_ON (!mem); 412 MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); 413 414 return mem->vmalloc; 415} 416EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); 417 418void videobuf_vmalloc_free (struct videobuf_buffer *buf) 419{ 420 struct videobuf_vmalloc_memory *mem = buf->priv; 421 422 /* mmapped memory can't be freed here, otherwise mmapped region 423 would be released, while still needed. In this case, the memory 424 release should happen inside videobuf_vm_close(). 425 So, it should free memory only if the memory were allocated for 426 read() operation. 427 */ 428 if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0)) 429 return; 430 431 if (!mem) 432 return; 433 434 MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM); 435 436 vfree(mem->vmalloc); 437 mem->vmalloc = NULL; 438 439 return; 440} 441EXPORT_SYMBOL_GPL(videobuf_vmalloc_free); 442 443/* 444 * Local variables: 445 * c-basic-offset: 8 446 * End: 447 */