在 Linux 驱动开发中,mmap()
系统调用和 file_operations
结构中的 mmap()
方法虽然功能相关,但原型和用途有显著区别。以下是两者的详细对比:
1. 系统调用 mmap()
的原型
这是用户空间程序调用的系统调用接口,定义在 <sys/mman.h>
中:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
• 参数说明:
• addr
:用户希望映射的起始地址(通常设为 NULL
,由内核选择)。
• length
:映射的长度(字节)。
• prot
:内存保护标志(如 PROT_READ
、PROT_WRITE
)。
• flags
:映射类型(如 MAP_SHARED
、MAP_PRIVATE
)。
• fd
:文件描述符(若映射文件)。
• offset
:文件的偏移量。
• 作用:用户空间通过此调用请求内核将文件或设备内存映射到进程地址空间。
2. file_operations
中的 mmap()
方法原型
这是内核驱动中实现的回调函数,定义在 <linux/fs.h>
中:
int (*mmap) (struct file *filp, struct vm_area_struct *vma);
• 参数说明:
• filp
:指向文件的 file
结构体(表示被映射的设备或文件)。
• vma
:指向 vm_area_struct
的指针,描述用户空间的虚拟内存区域(VMA)。
• 作用:驱动通过此函数实现具体的内存映射逻辑,将设备内存或文件内容关联到用户空间的 VMA。
关键区别
特性 | 系统调用 mmap() | file_operations->mmap |
---|---|---|
调用者 | 用户空间程序 | 内核(由系统调用触发) |
参数 | 用户空间参数(如 fd , offset ) | 内核结构体(struct file , vm_area_struct ) |
返回值 | 成功返回映射的起始地址,失败返回 MAP_FAILED | 成功返回 0 ,失败返回负的错误码 |
功能 | 用户请求映射操作 | 驱动实现映射的具体逻辑 |
头文件 | <sys/mman.h> | <linux/fs.h> |
工作流程
- 用户调用
mmap()
系统调用,传递参数(如文件描述符、偏移量等)。 - 内核处理系统调用,通过文件系统的
file_operations
找到对应的mmap
方法。 - 驱动的
mmap
函数被调用,利用vma
和filp
完成映射(如设置页表、关联设备内存)。 - 驱动返回结果,内核通知用户空间操作成功/失败。
驱动中 mmap
的典型实现
int my_mmap(struct file *filp, struct vm_area_struct *vma) {
unsigned long pfn = virt_to_phys(my_device_mem) >> PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;
if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot))
return -EAGAIN;
return 0; // 成功
}
• 使用 remap_pfn_range
将物理内存映射到用户空间。
总结
• 系统调用是用户空间的接口,参数面向应用层。
• 驱动的 mmap
是内核实现,操作内核数据结构(如 vm_area_struct
),完成底层映射。
• 驱动需通过 file_operations
注册 mmap
方法,供系统调用触发。