Hi, I am writing a toy driver to understand a few memory mapping principles. This character driver is supposed to be able to mmap any part of physical memory to userspace, in a similar fashion to /dev/mem. The driver provides a .mmap interface to physical memory using two different methods. - in the first method, the mmap implementation calls remap_pfn_range to map all physical pages together. I believe this is similar to what /dev/mem does - in the second method, I use a .fault handler in vm_area_operations to map each individual requested page when its page fault happens. The mmap method for the device is simple: static int memphys_mmap(struct file *filp, struct vm_area_struct *vma) { unsigned long physaddr = vma->vm_pgoff << PAGE_SHIFT; struct page *pageptr; unsigned long size = vma->vm_end - vma->vm_start; unsigned long virtualaddr; printk("%s mmaping physical memory at: %llx (page number %d) \n", __FUNCTION__, physaddr, vma->vm_pgoff); if (physaddr + size > __pa(high_memory) { printk("%s invalid memory location for device \n", __FUNCTION__); return -EINVAL; } /* this call is uncommented in the first method remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, vma->vm_end - vma->vm_start, vma->vm_page_prot); */ vma->vm_flags |= VM_RESERVED; vma->vm_ops = &memphys_vmops; return 0; } The .fault handler code is: ... /* installing function in the vm_operations_struct */ .fault = memphys_vma_fault; ... static int memphys_vma_fault( struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *pageptr; unsigned long offset = vmf->vm_pgoff << PAGE_SHIFT; unsigned long physaddr = vmf->virtual_address - vma->vm_start + offset; unsigned long pfn = physaddr >> PAGE_SHIFT; unsigned long virtualaddr; printk("%s vmastart:%llx vmaend:%llx offset:%llx physical_address:%llx pfn: %d\n", __FUNCTION__, vma->vm_start, vma->vm_end, offset, physaddr, pfn); if (!pfn_valid(pfn)) return NULL; pageptr = pfn_to_page (pfn); get_page(pageptr); vmf->page = pageptr; return pageptr; } The remap_pfn_range method works as expected. The .fault handler method works fine when mmaping a small number of pages (up until 5 pages). However, for >5 of pages, the user process gets stuck. Using printk in my .fault handler, I see that the handler keeps trying to map the the 6th page but never succeeds. [14349.275138] memphys_open [14349.275147] memphys_mmap requested physical memory at: 41400000 (page number 267264) [14349.275154] memphys_vma_fault offset:41400000 physical_address:41400000 pfn: 267264 [14349.275186] memphys_vma_fault offset:41400000 physical_address:41401000 pfn: 267265 [14349.275217] memphys_vma_fault offset:41400000 physical_address:41402000 pfn: 267266 [14349.275248] memphys_vma_fault offset:41400000 physical_address:41403000 pfn: 267267 [14349.275261] memphys_vma_fault offset:41400000 physical_address:41404000 pfn: 267268 [14349.275272] memphys_vma_fault offset:41400000 physical_address:41405000 pfn: 267269 [14349.275295] memphys_vma_fault offset:41400000 physical_address:41405000 pfn: 267269 [14349.275301] memphys_vma_nofault vmastart:7f6499046000 vmaend:7f649904c000 ... [nonstop continuing retries to map pfn: 267269, the 6th page) ... [14349.275330] memphys_vma_nofault offset:41400000 physical_address:41405000 pfn: 267269 [14349.275330] memphys_vma_nofault offset:41400000 physical_address:41405000 pfn: 267269 [...forever...] At other times, the system hangs as soon as I enter the command (I haven't tried kgdb here yet) The test user program calls mmap with the following flags: fd = open("/dev/memphys", O_RDONLY); buf = mmap(0, size, PROT_READ | PROT_WRITE , MAP_PRIVATE , fd, offset); [use buf in some way...] close(fd); - Can anyone help me understand what the driver code is doing wrong? Are either the mmap or the .fault handler implementation missing something crucial? I have tried mapping several different physical memory locations, but I always get the fault handler to fail on the 6th page or the system to hang. The remap_pfn_range method never crashes or hangs. This is on a dual-core x86_64 machine with 3GB of physical RAM. I am wondering whether there is a standard I/O memory hole that my handler doesn't take into account, resulting in the hang. Also note that currently I set the VM_RESERVED flag, though I am not sure this is needed for the functionality of this driver. - bonus question: ldd 3rd edition mentions that remap_pfn_range won't allow you to remap conventional addresses (chapter 15, p.430, section remapping RAM). Is this section obsolete? It seems that /dev/mem (drivers/char/mem.c) uses remap_pfn_range, and therefore the function allows mapping conventional memory now. I just wanted to confirm that this part of the book is obsolete. thanks for any help, - Vasilis -- To unsubscribe from this list: send an email with "unsubscribe kernelnewbies" to ecartis@xxxxxxxxxxxx Please read the FAQ at http://kernelnewbies.org/FAQ