linux mmap映射内存问题

花开花落_fzu 2018-07-03 06:20:20
有一个项目需要将寄存器地址映射到用户态,由用户态对寄存器进行配置,决定使用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后,如何获得我内核态内存的地址呢?
...全文
500 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
花开花落_fzu 2018-07-13
  • 打赏
  • 举报
回复
引用 3 楼 jklinux 的回复:
[quote=引用 2 楼 ma111000522 的回复:]
[quote=引用 1 楼 jklinux 的回复:]
其实楼主这个需求应不用自己写驱动了。内核里已提供相应功能的驱动。

只要通过操作设备文件"/dev/mem", 再mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了



mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了
按照你上面的说法,/dev/mem这个内核提供的驱动,是从是物理地址0地址开始的吗?然后我们用户在mmap的时候,加上寄存器偏移就可以操作了吗,是吧?[/quote]

是的,但是offset 必须是按4k对齐的寄存器物理基地址[/quote]

好的,明白了。多谢您的解答
jklinux 2018-07-06
  • 打赏
  • 举报
回复
引用 2 楼 ma111000522 的回复:
[quote=引用 1 楼 jklinux 的回复:]
其实楼主这个需求应不用自己写驱动了。内核里已提供相应功能的驱动。

只要通过操作设备文件"/dev/mem", 再mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了



mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了
按照你上面的说法,/dev/mem这个内核提供的驱动,是从是物理地址0地址开始的吗?然后我们用户在mmap的时候,加上寄存器偏移就可以操作了吗,是吧?[/quote]

是的,但是offset 必须是按4k对齐的寄存器物理基地址
花开花落_fzu 2018-07-04
  • 打赏
  • 举报
回复
引用 1 楼 jklinux 的回复:
其实楼主这个需求应不用自己写驱动了。内核里已提供相应功能的驱动。

只要通过操作设备文件"/dev/mem", 再mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了



mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了
按照你上面的说法,/dev/mem这个内核提供的驱动,是从是物理地址0地址开始的吗?然后我们用户在mmap的时候,加上寄存器偏移就可以操作了吗,是吧?
jklinux 2018-07-04
  • 打赏
  • 举报
回复
其实楼主这个需求应不用自己写驱动了。内核里已提供相应功能的驱动。

只要通过操作设备文件"/dev/mem", 再mmap(NULL, 映射长度, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 要映射的寄存器基地址)就可以操作寄存器了

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧