copy_to_user、copy_from_user
unsigned long copy_to_user (void __user * to, const void * from, unsigned long n);
to: Destination address, in user space.
from: Source address, in kernel space.
n: Number of bytes to copy.
unsigned long copy_from_user (void * to, const void __user * from, unsigned long n);
to: Destination address, in kernel space.
from: Source address, in user space.
n: Number of bytes to copy.
If the function receives a pointer to user-space data, you have to use copy_from_user() to copy the pointed-to data from user space into kernel space (and vice versa). Note that the pointer value itself is passed by value (like all C parameters), so you don't have to do a copy_from_user() to obtain the pointer value before you can copy_from_user() the data it points to
mmap
将用户空间地址和内核驱动空间地址做映射
static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
{
int ret;
struct vm_struct *area;
struct binder_proc *proc = filp->private_data;
const char *failure_string;
struct binder_buffer *buffer;
// 最多只分配 4M 的内存
if ((vma->vm_end - vma->vm_start) > SZ_4M)
vma->vm_end = vma->vm_start + SZ_4M;
// 申请内核虚拟内存空间
area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
// 将申请到的内存地址保存到 binder_proc 对象中
proc->buffer = area->addr;
proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
// 根据请求到的内存空间大小,分配给 binder_proc 对象的 pages, 用于保存指向物理页的指针
proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
proc->buffer_size = vma->vm_end - vma->vm_start;
// 分配一个页的物理内存
binder_update_page_range(proc, 1, proc->buffer, proc->buffer + PAGE_SIZE, vma)
return 0;
}
static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
{
struct ashmem_area *asma = file->private_data;
int ret = 0;
mutex_lock(&ashmem_mutex);
...
if (!asma->file) {
char *name = ASHMEM_NAME_DEF;
struct file *vmfile;
if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0')
name = asma->name;
<!--校准真正操作的文件-->
vmfile = shmem_file_setup(name, asma->size, vma->vm_flags);
asma->file = vmfile;
}
...
return ret;
}
void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset)
第一个参数是映射区的首地址,传NULL,让内核去指定,返回值用来指定映射区的首地址
第二个参数是映射区的大小,由于32bit的linux内核虚拟地址空间是由4KB大小的页面组织的,实际大小是4KB的整数倍。不能指定为0,否则调用失败!一般来讲,文件多大,length就指定多大
第三个参数是映射区的权限,PROT_READ(映射区必须要有读权限)、PROT_WRITE
第四个参数指示标志位参数,MAP_SHARED数据会同步到磁盘、MAP_PRIVATE数据不会同步到磁盘,MAP_ANONYMOUS代表匿名映射,映射区不与任何文件关联,为了兼容问题,fd值应为-1
第五个参数是文件描述符,要映射的文件对应的文件描述符fd。使用open系统调用获取文件描述符
第六个参数代表映射文件描述符的偏移量,偏移量必须是4KB的整数倍,一般传入0即可,除非有特殊的需求