2,860
社区成员




在 Linux 驱动中,内存映射(Memory Mapping)是实现用户空间与内核空间高效交互的关键机制,允许用户态程序直接访问内核空间的物理内存或虚拟内存区域,避免了数据复制的开销。以下是其核心实现原理和步骤:
read/write
系统调用。物理连续内存(如设备寄存器):
使用 dma_alloc_coherent()
或 ioremap()
分配物理连续的内存区域。
void *vaddr;
dma_addr_t dma_handle;
vaddr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
虚拟内存(如缓冲区):
使用 vmalloc()
分配非连续的虚拟内存。
void *vaddr = vmalloc(size);
mmap
方法在设备驱动的 file_operations
结构体中定义 mmap
回调函数:
static int my_driver_mmap(struct file *filp, struct vm_area_struct *vma) {
unsigned long size = vma->vm_end - vma->vm_start;
// 检查用户请求的映射长度是否合法
if (size > MY_BUFFER_SIZE) return -EINVAL;
// 将内核虚拟地址映射到用户空间
return remap_vmalloc_range(vma, vaddr, vma->vm_pgoff);
}
物理地址映射:
使用 remap_pfn_range()
将物理页帧号(PFN)映射到用户空间:
unsigned long pfn = virt_to_phys(kernel_vaddr) >> PAGE_SHIFT;
remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot);
虚拟地址映射:
使用 remap_vmalloc_range()
映射 vmalloc
分配的虚拟内存。
pgprot_noncached()
或 pgprot_writecombine()
设置非缓存或写合并属性,避免缓存一致性问题。vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
用户空间调用:
用户程序通过 mmap()
系统调用发起映射:
void *addr = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
内核 API:
remap_pfn_range()
:物理地址映射。remap_vmalloc_range()
:虚拟地址映射。dma_alloc_coherent()
:分配一致性 DMA 内存。spin_lock()
)保护共享数据,防止并发访问冲突。mb()
、rmb()
。mmap
回调中验证用户参数,避免非法访问。// 驱动初始化时映射物理寄存器
request_mem_region(base_addr, reg_size, "my_driver");
regs = ioremap(base_addr, reg_size);
// 用户空间通过 mmap 访问寄存器
static int my_mmap(struct file *filp, struct vm_area_struct *vma) {
return remap_pfn_range(vma, vma->vm_start, virt_to_phys(regs) >> PAGE_SHIFT, size, vma->vm_page_prot);
}
// 分配一致性 DMA 内存
dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
// 用户空间映射
remap_pfn_range(vma, vma->vm_start, dma_handle >> PAGE_SHIFT, size, vma->vm_page_prot);
// 使用 vmalloc 分配帧缓冲
struct fb_info *info;
info->screen_base = vmalloc(fb_size);
// 实现 mmap 支持
static int fb_mmap(struct file *filp, struct vm_area_struct *vma) {
return remap_vmalloc_range(vma, info->screen_base, vma->vm_pgoff);
}
PROT_READ | PROT_WRITE
)。pgprot_noncached()
或 dma_sync_*
函数同步缓存。Linux 驱动中的内存映射通过 mmap
系统调用和内核 API(如 remap_pfn_range
)实现,核心在于将内核内存(物理或虚拟)映射到用户空间虚拟地址。需注意内存类型(物理/DMA/虚拟)、缓存策略及同步机制,以确保数据一致性和性能。典型应用包括设备寄存器访问、DMA 缓冲区和帧缓冲区管理。