linux mmap映射内存问题
有一个项目需要将寄存器地址映射到用户态,由用户态对寄存器进行配置,决定使用mmap来进行映射。
我先写了一个驱动和一个用户态程序来验证mmap是否可行。
驱动程序添加了一个misc-device,并申请了一段内存,并将这段内存映射给用户态程序,并将该mmap函数挂给misc设备的file_operations。
int cdma_mmap(struct file *file, struct vm_area_struct *vma)
{
printk("%s %d\r\n", __FUNCTION__, __LINE__);
vma->vm_flags |= VM_READ | VM_WRITE;
if(remap_pfn_range(vma, vma->vm_start, virt_to_phys(global_mem) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, PAGE_COPY))
return -EAGAIN;
return 0;
}
static struct file_operations oper =
{
.owner = THIS_MODULE,
.open = cdma_open,
.read = cdma_read,
.write = cmda_write,
.release = cdma_release,
.unlocked_ioctl = cdma_unlocked_ioctl,
.mmap = cdma_mmap,
};
struct miscdevice cdma_dev =
{
.module = THIS_MODULE,
.name = "XilinxCdma",
.fops = &oper,
};
用户态程序我首先打开misc设备在/dev目录下的设备节点,然后使用mmap进行映射,然后将映射后的内存进行了输出字符串。
int main(void)
{
int fd = open("/dev/XilinxCdma", O_RDWR);
char *buf;
if(fd < 0)
{
printf("open /dev/XilinxCdma failed, return %d\r\n", fd);
}
printf("%s %d fd:%d\r\n", __FUNCTION__, __LINE__, fd);
buf = mmap(NULL, 1024, PROT_READ, MAP_PRIVATE, fd, 0);
if(buf == MAP_FAILED)
{
printf("mmap failed, return %d", *buf);
close(fd);
return 0;
}
else
{
printf("mmap success\r\n");
}
printf("Mem:\r\n%s\r\n", buf);
munmap(buf, 1024);
close(fd);
return 0;
}
我通过echo 1122345455 > /dev/XilinxCdma对该块内存写入数据。
然后执行用户态程序,但是发现映射后的内存没有办法读出我写入的数据,感觉应该是映射返回的地址不对造成的。
问题来了:
1、内核态驱动程序在mmap的时候,为啥将内核态的虚拟地址转换成物理地址后,还需要右移>>PAGE_SHIFT?是因为映射必须以page的方式映射吗?
2、如果是以当前内存所在的page进行映射,这样我实际的内存地址会有偏差,我用户态程序mmap后,如何获得我内核态内存的地址呢?