0%

修复内核驱动 mmap 4K对齐问题

问题描述

编写内核驱动,使用mmap共享内存。发现读取到的数据不对。
联想到mmaplength会自动调整为PAGE_SIZE的倍数,猜测是因为mmap返回的是对应page的起始地址,导致存在偏移。

修复方式:初始化时,单独申请一块大小为PAGE_SIZE的内存,不使用数组。
并调用SetPageReserved,保留该页。

问题代码

内核驱动

结构体

1
2
3
4
5
struct ShareData{
bool isCompleted;
int data[20];
}
ShareData * g_ShareData;

初始化

1
g_ShareData = kmalloc(sizeof(struct ShareData), GFP_KERNEL);

mmap

1
2
3
4
if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(g_ShareData->data) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot)) {
return -EAGAIN;
}

应用层

1
(int *) data_mapped = (int *)mmap(0, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

测试

计算偏移值:offset = (uint64_t)g_ShareData->data % PAGE_SIZE

加上该偏移值后,读取data_mapped + offset/4,发现确实是要读取的数据。

修复

结构体

1
2
3
4
5
struct ShareData{
bool isCompleted;
int* data;
}
ShareData * g_ShareData;

初始化

1
2
3
g_ShareData = kmalloc(sizeof(struct ShareData), GFP_KERNEL);
g_ShareData->data = kmalloc(PAGE_SIZE, GFP_KERNEL);
SetPageReserved(virt_to_page(g_ShareData->data));

参考

例说linux内核与应用数据通信(四):映射设备内核空间到用户态
例說核心層與使用層通訊/4_memdev/drv/chr_memdev.c
linux/memory/mmap/kernel/hello.c