/* do remap by hand */ virtad = &pgindex->buffer[ofs-intofs]; vmf->page = virt_to_page(virtad); /* return page index */ return 0; /* everything went fine */ } #else /* This is the old nopage method for compatibility reasons */ static struct page *dmar_vm_nopage(struct vm_area_struct * area, unsigned long address, int *nopage_type) { struct page *page = NOPAGE_SIGBUS; /* for debug, gives mempage */ /* address relative to dma memory */ unsigned long ofs = (address - area->vm_start) + VMA_OFFSET(area); unsigned long intofs; unsigned char * virtad = NULL; /* start ad of page in kernel space */ struct dma_page_pointer *pgindex; /* find right page */ pgindex = dma_main_pointer; /* start with first mem piece */ intofs=0; /* linear offset of current mempiece start */ while (intofs+pgindex->fullsize<=ofs) { intofs +=pgindex->fullsize; pgindex=pgindex->next; if (pgindex == dma_main_pointer) { *nopage_type = VM_FAULT_SIGBUS; /* new in kernel 2.6 */ return NOPAGE_SIGBUS; /* ofs not mapped */ } }; /* pgindex contains now the relevant page index */ /* do remap by hand */ virtad = &pgindex->buffer[ofs-intofs]; /* page table index */ page=virt_to_page(virtad); get_page(page); /* increment page use counter */ *nopage_type = VM_FAULT_MINOR; /* new in kernel 2.6 */ return page; }
struct page *scullv_vma_nopage(struct vm_area_struct *vma, unsigned long address, int write) { unsigned long offset; ScullV_Dev *ptr, *dev = scullv_vma_to_dev(vma); struct page *page = NOPAGE_SIGBUS; void *pageptr = NULL; /* default to "missing" */ pgd_t *pgd; pmd_t *pmd; pte_t *pte; unsigned long lpage; down(&dev->sem); offset = (address - vma->vm_start) + VMA_OFFSET(vma); if (offset >= dev->size) goto out; /* out of range */ /* * Now retrieve the scullv device from the list,then the page. * If the device has holes, the process receives a SIGBUS when * accessing the hole. */ offset >>= PAGE_SHIFT; /* offset is a number of pages */ for (ptr = dev; ptr && offset >= dev->qset;) { ptr = ptr->next; offset -= dev->qset; } if (ptr && ptr->data) pageptr = ptr->data[offset]; if (!pageptr) goto out; /* hole or end-of-file */ /* * After scullv lookup, "page" is now the address of the page * needed by the current process. Since it's a vmalloc address, * first retrieve the unsigned long value to be looked up * in page tables. */ lpage = VMALLOC_VMADDR(pageptr); #ifdef LINUX_24 spin_lock(&init_mm.page_table_lock); #endif pgd = pgd_offset(&init_mm, lpage); pmd = pmd_offset(pgd, lpage); pte = pte_offset(pmd, lpage); #ifdef LINUX_24 page = pte_page(*pte); spin_unlock(&init_mm.page_table_lock); #else page = mem_map + MAP_NR(pte_page(*pte)); #endif /* got it, now increment the count */ get_page(page); out: up(&dev->sem); return page; }
int scullv_mmap(struct file *filp, struct vm_area_struct *vma) { struct inode *inode = INODE_FROM_F(filp); if (VMA_OFFSET(vma) & (PAGE_SIZE-1)) return -ENXIO; /* need aligned offsets */ /* don't do anything here: "nopage" will fill the holes */ vma->vm_ops = &scullv_vm_ops; vma->vm_flags |= VM_RESERVED; #ifdef LINUX_24 vma->vm_private_data = scullv_devices + MINOR(inode->i_rdev); #else vma->vm_file = filp; #endif scullv_vma_open(vma); return 0; }
/* vm_operations, die das eigentliche mmap über die nopage-methode vornehmen */ static struct page *dmar_vm_nopage(struct vm_area_struct * area, unsigned long address, int write_access) { struct page *page = NOPAGE_SIGBUS; /* for debug, gives mempage */ /* address relative to dma memory */ unsigned long ofs = (address - area->vm_start) + VMA_OFFSET(area); unsigned long intofs; unsigned char * virtad = NULL; /* start ad of page in kernel space */ struct dma_page_pointer *pgindex; #ifdef bla_nopage void * pga; /* for tests */ #endif /* pgd_t *pgd; pmd_t *pmd; pte_t *pte; for getting mapping to real bufs unsigned long lpage; */ /* find right page */ pgindex = dma_main_pointer; /* start with first mem piece */ intofs=0; /* linear offset of current mempiece start */ while (intofs+pgindex->fullsize<=ofs) { intofs +=pgindex->fullsize; pgindex=pgindex->next; if (pgindex == dma_main_pointer) return NOPAGE_SIGBUS; /* ofs not mapped */ }; /* pgindex contains now the relevant page index */ /* do remap by hand */ virtad = &pgindex->buffer[ofs-intofs]; /* virtad = dma_main_pointer->buffer; for tests only */ /* page table index */ page=virt_to_page(virtad); get_page(page); /* increment page use counter */ #ifdef bla_nopage pga = page_address(page); /* for tests */ printk("nopage-Zugriff; adr=%x, phys=%x, page=%x\n ofs=%x, intofs=%x, pgindex=%x, virtad = %x, pga= %x\n", (int)address, (int)pgindex->physbuf,(int)page,(int)ofs, (int)intofs,(int)pgindex, (int)virtad, (int) pga); #endif return page; }
/* don't do anything here: "nopage" will fill the holes */ vma->vm_ops = &scullv_vm_ops; vma->vm_flags |= VM_RESERVED; #ifdef LINUX_24 vma->vm_private_data = scullv_devices + MINOR(inode->i_rdev); #else vma->vm_file = filp; #endif scullv_vma_open(vma); return 0; } #else /* LINUX_20 */ int scullv_mmap(struct inode *inode, struct file *filp, struct vm_area_struct *vma) { if (VMA_OFFSET(vma) & (PAGE_SIZE-1)) return -ENXIO; /* need aligned offsets */ /* * A pointer to init_mm is needed to access page tables */ if (!init_mm_ptr) retrieve_init_mm_ptr(); /* don't do anything here: "nopage" will fill the holes */ vma->vm_ops = &scullv_vm_ops; vma->vm_inode = inode; inode->i_count++; scullv_vma_open(vma); return 0; }