diff options
Diffstat (limited to 'drivers/char/drm/drm_vm.c')
-rw-r--r-- | drivers/char/drm/drm_vm.c | 69 |
1 files changed, 35 insertions, 34 deletions
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index ffd0800ed601..b9cfc077f6bc 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c | |||
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
59 | drm_device_t *dev = priv->head->dev; | 59 | drm_device_t *dev = priv->head->dev; |
60 | drm_map_t *map = NULL; | 60 | drm_map_t *map = NULL; |
61 | drm_map_list_t *r_list; | 61 | drm_map_list_t *r_list; |
62 | struct list_head *list; | 62 | drm_hash_item_t *hash; |
63 | 63 | ||
64 | /* | 64 | /* |
65 | * Find the right map | 65 | * Find the right map |
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma, | |||
70 | if (!dev->agp || !dev->agp->cant_use_aperture) | 70 | if (!dev->agp || !dev->agp->cant_use_aperture) |
71 | goto vm_nopage_error; | 71 | goto vm_nopage_error; |
72 | 72 | ||
73 | list_for_each(list, &dev->maplist->head) { | 73 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) |
74 | r_list = list_entry(list, drm_map_list_t, head); | 74 | goto vm_nopage_error; |
75 | map = r_list->map; | 75 | |
76 | if (!map) | 76 | r_list = drm_hash_entry(hash, drm_map_list_t, hash); |
77 | continue; | 77 | map = r_list->map; |
78 | if (r_list->user_token == VM_OFFSET(vma)) | ||
79 | break; | ||
80 | } | ||
81 | 78 | ||
82 | if (map && map->type == _DRM_AGP) { | 79 | if (map && map->type == _DRM_AGP) { |
83 | unsigned long offset = address - vma->vm_start; | 80 | unsigned long offset = address - vma->vm_start; |
@@ -150,14 +147,14 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma, | |||
150 | if (address > vma->vm_end) | 147 | if (address > vma->vm_end) |
151 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 148 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
152 | if (!map) | 149 | if (!map) |
153 | return NOPAGE_OOM; /* Nothing allocated */ | 150 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
154 | 151 | ||
155 | offset = address - vma->vm_start; | 152 | offset = address - vma->vm_start; |
156 | i = (unsigned long)map->handle + offset; | 153 | i = (unsigned long)map->handle + offset; |
157 | page = (map->type == _DRM_CONSISTENT) ? | 154 | page = (map->type == _DRM_CONSISTENT) ? |
158 | virt_to_page((void *)i) : vmalloc_to_page((void *)i); | 155 | virt_to_page((void *)i) : vmalloc_to_page((void *)i); |
159 | if (!page) | 156 | if (!page) |
160 | return NOPAGE_OOM; | 157 | return NOPAGE_SIGBUS; |
161 | get_page(page); | 158 | get_page(page); |
162 | 159 | ||
163 | DRM_DEBUG("shm_nopage 0x%lx\n", address); | 160 | DRM_DEBUG("shm_nopage 0x%lx\n", address); |
@@ -275,7 +272,7 @@ static __inline__ struct page *drm_do_vm_dma_nopage(struct vm_area_struct *vma, | |||
275 | if (address > vma->vm_end) | 272 | if (address > vma->vm_end) |
276 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 273 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
277 | if (!dma->pagelist) | 274 | if (!dma->pagelist) |
278 | return NOPAGE_OOM; /* Nothing allocated */ | 275 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
279 | 276 | ||
280 | offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ | 277 | offset = address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ |
281 | page_nr = offset >> PAGE_SHIFT; | 278 | page_nr = offset >> PAGE_SHIFT; |
@@ -313,7 +310,7 @@ static __inline__ struct page *drm_do_vm_sg_nopage(struct vm_area_struct *vma, | |||
313 | if (address > vma->vm_end) | 310 | if (address > vma->vm_end) |
314 | return NOPAGE_SIGBUS; /* Disallow mremap */ | 311 | return NOPAGE_SIGBUS; /* Disallow mremap */ |
315 | if (!entry->pagelist) | 312 | if (!entry->pagelist) |
316 | return NOPAGE_OOM; /* Nothing allocated */ | 313 | return NOPAGE_SIGBUS; /* Nothing allocated */ |
317 | 314 | ||
318 | offset = address - vma->vm_start; | 315 | offset = address - vma->vm_start; |
319 | map_offset = map->offset - (unsigned long)dev->sg->virtual; | 316 | map_offset = map->offset - (unsigned long)dev->sg->virtual; |
@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) | |||
467 | dev = priv->head->dev; | 464 | dev = priv->head->dev; |
468 | dma = dev->dma; | 465 | dma = dev->dma; |
469 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", | 466 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
470 | vma->vm_start, vma->vm_end, VM_OFFSET(vma)); | 467 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); |
471 | 468 | ||
472 | /* Length must match exact page count */ | 469 | /* Length must match exact page count */ |
473 | if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { | 470 | if (!dma || (length >> PAGE_SHIFT) != dma->page_count) { |
@@ -476,6 +473,22 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) | |||
476 | } | 473 | } |
477 | unlock_kernel(); | 474 | unlock_kernel(); |
478 | 475 | ||
476 | if (!capable(CAP_SYS_ADMIN) && | ||
477 | (dma->flags & _DRM_DMA_USE_PCI_RO)) { | ||
478 | vma->vm_flags &= ~(VM_WRITE | VM_MAYWRITE); | ||
479 | #if defined(__i386__) || defined(__x86_64__) | ||
480 | pgprot_val(vma->vm_page_prot) &= ~_PAGE_RW; | ||
481 | #else | ||
482 | /* Ye gads this is ugly. With more thought | ||
483 | we could move this up higher and use | ||
484 | `protection_map' instead. */ | ||
485 | vma->vm_page_prot = | ||
486 | __pgprot(pte_val | ||
487 | (pte_wrprotect | ||
488 | (__pte(pgprot_val(vma->vm_page_prot))))); | ||
489 | #endif | ||
490 | } | ||
491 | |||
479 | vma->vm_ops = &drm_vm_dma_ops; | 492 | vma->vm_ops = &drm_vm_dma_ops; |
480 | 493 | ||
481 | vma->vm_flags |= VM_RESERVED; /* Don't swap */ | 494 | vma->vm_flags |= VM_RESERVED; /* Don't swap */ |
@@ -521,12 +534,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
521 | drm_file_t *priv = filp->private_data; | 534 | drm_file_t *priv = filp->private_data; |
522 | drm_device_t *dev = priv->head->dev; | 535 | drm_device_t *dev = priv->head->dev; |
523 | drm_map_t *map = NULL; | 536 | drm_map_t *map = NULL; |
524 | drm_map_list_t *r_list; | ||
525 | unsigned long offset = 0; | 537 | unsigned long offset = 0; |
526 | struct list_head *list; | 538 | drm_hash_item_t *hash; |
527 | 539 | ||
528 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", | 540 | DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", |
529 | vma->vm_start, vma->vm_end, VM_OFFSET(vma)); | 541 | vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT); |
530 | 542 | ||
531 | if (!priv->authenticated) | 543 | if (!priv->authenticated) |
532 | return -EACCES; | 544 | return -EACCES; |
@@ -535,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
535 | * the AGP mapped at physical address 0 | 547 | * the AGP mapped at physical address 0 |
536 | * --BenH. | 548 | * --BenH. |
537 | */ | 549 | */ |
538 | if (!VM_OFFSET(vma) | 550 | if (!(vma->vm_pgoff << PAGE_SHIFT) |
539 | #if __OS_HAS_AGP | 551 | #if __OS_HAS_AGP |
540 | && (!dev->agp | 552 | && (!dev->agp |
541 | || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) | 553 | || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE) |
@@ -543,23 +555,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
543 | ) | 555 | ) |
544 | return drm_mmap_dma(filp, vma); | 556 | return drm_mmap_dma(filp, vma); |
545 | 557 | ||
546 | /* A sequential search of a linked list is | 558 | if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) { |
547 | fine here because: 1) there will only be | 559 | DRM_ERROR("Could not find map\n"); |
548 | about 5-10 entries in the list and, 2) a | 560 | return -EINVAL; |
549 | DRI client only has to do this mapping | ||
550 | once, so it doesn't have to be optimized | ||
551 | for performance, even if the list was a | ||
552 | bit longer. */ | ||
553 | list_for_each(list, &dev->maplist->head) { | ||
554 | |||
555 | r_list = list_entry(list, drm_map_list_t, head); | ||
556 | map = r_list->map; | ||
557 | if (!map) | ||
558 | continue; | ||
559 | if (r_list->user_token == VM_OFFSET(vma)) | ||
560 | break; | ||
561 | } | 561 | } |
562 | 562 | ||
563 | map = drm_hash_entry(hash, drm_map_list_t, hash)->map; | ||
563 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) | 564 | if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) |
564 | return -EPERM; | 565 | return -EPERM; |
565 | 566 | ||
@@ -620,7 +621,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma) | |||
620 | offset = dev->driver->get_reg_ofs(dev); | 621 | offset = dev->driver->get_reg_ofs(dev); |
621 | #ifdef __sparc__ | 622 | #ifdef __sparc__ |
622 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | 623 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); |
623 | if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start, | 624 | if (io_remap_pfn_range(vma, vma->vm_start, |
624 | (map->offset + offset) >> PAGE_SHIFT, | 625 | (map->offset + offset) >> PAGE_SHIFT, |
625 | vma->vm_end - vma->vm_start, | 626 | vma->vm_end - vma->vm_start, |
626 | vma->vm_page_prot)) | 627 | vma->vm_page_prot)) |