1. read_mem 和 write_mem
这两个函数比较容易理解,主要是使用copy_to_user和copy_frome_user对数据时行拷贝,其他的函数也都类似,较容易理解
/* * This funcion reads the *physical* memory. The f_pos points directly to the * memory location. */ static ssize_t read_mem(struct file * file, char __user * buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; ssize_t read, sz; char *ptr; if (!valid_phys_addr_range(p, count)) return -EFAULT; read = 0; #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED /* we don't have page 0 mapped on sparc and m68k.. */ if (p < PAGE_SIZE) { sz = PAGE_SIZE - p; if (sz > count) sz = count; if (sz > 0) { if (clear_user(buf, sz)) return -EFAULT; buf += sz; p += sz; count -= sz; read += sz; } } #endif while (count > 0) { /* * Handle first page in case it's not aligned */ if (-p & (PAGE_SIZE - 1)) sz = -p & (PAGE_SIZE - 1); else sz = PAGE_SIZE; sz = min_t(unsigned long, sz, count); if (!range_is_allowed(p >> PAGE_SHIFT, count)) return -EPERM; /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached * by the kernel or data corruption may occur */ ptr = xlate_dev_mem_ptr(p); if (!ptr) return -EFAULT; if (copy_to_user(buf, ptr, sz)) { unxlate_dev_mem_ptr(p, ptr); return -EFAULT; } unxlate_dev_mem_ptr(p, ptr); buf += sz; p += sz; count -= sz; read += sz; } *ppos += read; return read; } static ssize_t write_mem(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { unsigned long p = *ppos; ssize_t written, sz; unsigned long copied; void *ptr; if (!valid_phys_addr_range(p, count)) return -EFAULT; written = 0; #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED /* we don't have page 0 mapped on sparc and m68k.. */ if (p < PAGE_SIZE) { unsigned long sz = PAGE_SIZE - p; if (sz > count) sz = count; /* Hmm. Do something? */ buf += sz; p += sz; count -= sz; written += sz; } #endif while (count > 0) { /* * Handle first page in case it's not aligned */ if (-p & (PAGE_SIZE - 1)) sz = -p & (PAGE_SIZE - 1); else sz = PAGE_SIZE; sz = min_t(unsigned long, sz, count); if (!range_is_allowed(p >> PAGE_SHIFT, sz)) return -EPERM; /* * On ia64 if a page has been mapped somewhere as * uncached, then it must also be accessed uncached * by the kernel or data corruption may occur */ ptr = xlate_dev_mem_ptr(p); if (!ptr) { if (written) break; return -EFAULT; } copied = copy_from_user(ptr, buf, sz); if (copied) { written += sz - copied; unxlate_dev_mem_ptr(p, ptr); if (written) break; return -EFAULT; } unxlate_dev_mem_ptr(p, ptr); buf += sz; p += sz; count -= sz; written += sz; } *ppos += written; return written; }
static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) return -EINVAL; if (!private_mapping_ok(vma)) return -ENOSYS; if (!range_is_allowed(vma->vm_pgoff, size)) return -EPERM; if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size, &vma->vm_page_prot)) return -EINVAL; vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); vma->vm_ops = &mmap_mem_ops; /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot)) { return -EAGAIN; } return 0; }