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;
}
2. 很有必要看下mmep_mem
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;
}
这里主要是对内核物理内存映射到用户空间。