免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 4294 | 回复: 23
打印 上一主题 下一主题

[内存管理] 映射设备内存到用户空间的问题 [复制链接]

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-24 20:54 |只看该作者 |倒序浏览
写了个简单的设备,想将设备的内存映射到用户空间,内核代码如下,
  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/mm.h>       
  5. #include <asm/io.h>       

  6. #define DEV_MAP_NAME  "dev_map"
  7. #define DEV_MAP_MAJOR 100

  8. static int dev_open(struct inode * inode, struct file *filp);
  9. static int dev_mmap(struct file *filp, struct vm_area_struct *vma);
  10. static int dev_release(struct inode *inode, struct file *filp);


  11. char * buf_addr;
  12. char buf[] = "hello world";

  13. struct file_operations dev_fops = {
  14.     .owner = THIS_MODULE,
  15.     .open = dev_open,
  16.     .mmap = dev_mmap,
  17.     .release = dev_release,
  18. };

  19. int __init map_kernel_space_init(void)
  20. {
  21.     int ret;
  22.     ret = register_chrdev(DEV_MAP_MAJOR, DEV_MAP_NAME, &dev_fops);
  23.     if (ret < 0) {
  24.         printk(KERN_ERR "register_chrdev failed\n");
  25.         return ret;
  26.     }
  27.     return 0;
  28. }

  29. void __exit map_kernel_space_exit(void)
  30. {
  31.     unregister_chrdev(DEV_MAP_MAJOR, DEV_MAP_NAME);
  32.     printk(KERN_DEBUG "exit...");
  33. }

  34. static int dev_open(struct inode *inode, struct file *filp)
  35. {
  36.     buf_addr = (char *)kmalloc(1024, GFP_KERNEL);
  37.     if (buf_addr == NULL)
  38.         printk(KERN_ERR "kmalloc error");
  39.     memcpy(buf_addr, buf, sizeof(buf));

  40.     return 0;
  41. }

  42. static int dev_mmap(struct file *filp, struct vm_area_struct *vma)
  43. {
  44.     int ret;
  45.     printk(KERN_DEBUG "begin remap_pfn_range...");
  46.     ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)buf_addr) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, PAGE_SHARED);
  47.     printk(KERN_DEBUG "after remap_pfn_range");
  48.     if (ret != 0) {
  49.         printk(KERN_ERR "remap_pfn_range failed\n");
  50.         return -EAGAIN;
  51.     }
  52.     return 0;
  53. }

  54. static int dev_release(struct inode *inode, struct file *filp)
  55. {
  56.     return 0;
  57. }

  58. module_init(map_kernel_space_init);
  59. module_exit(map_kernel_space_exit);
复制代码
用户空间代码如下:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. #include <sys/mman.h>
  5. #include <fcntl.h>

  6. int main()
  7. {
  8.         int fd;
  9.         fd = open("./dev_map", O_RDWR);
  10.         if (fd < 0) {
  11.                 perror("open failed");
  12.                 return -1;
  13.         }
  14.         char *addr = NULL;
  15.         addr = mmap(NULL, 12, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
  16.         if (addr == MAP_FAILED) {
  17.                 perror("mmap failed");
  18.                 return -1;
  19.         }
  20.         printf("%s\n", addr);
  21.         printf("string len = %u\n", strlen(addr));
  22.         return 0;
  23. }
复制代码
编译后,加载模块,多次运行用户空间程序,发现打印出的内容总是变化,这是怎么回事?
还有,我这样实现的对吗?没有找到太多合适的remap_pfn_range()的例子,求大婶指导

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
2 [报告]
发表于 2013-09-24 22:18 |只看该作者
自己定啊。。。

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
3 [报告]
发表于 2013-09-25 08:02 |只看该作者
回复 1# goingstudy
编译后,加载模块,多次运行用户空间程序,发现打印出的内容总是变化,这是怎么回事?


你打印的是mmap的返回地址,这个地址是虚拟地址,每次都变化应该没有问题吧。

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
4 [报告]
发表于 2013-09-25 08:46 |只看该作者
本帖最后由 goingstudy 于 2013-09-25 09:03 编辑

回复 3# 瀚海书香
我是以%s打印的里面的内容,在设备的open函数里我分配空间时,复制了个字符串,但是打印时却总是有变化

   

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
5 [报告]
发表于 2013-09-25 11:51 |只看该作者
求大神指导啊

论坛徽章:
2
酉鸡
日期:2013-09-26 11:11:15摩羯座
日期:2014-01-08 13:45:19
6 [报告]
发表于 2013-09-25 16:50 |只看该作者
3.6.10-4.fc18.x86_64 下运行无问题
[root@localhost testdrv]# ./test
abcdefghijklmnop

string len = 17
[root@localhost testdrv]# ./test
abcdefghijklmnop

string len = 17
[root@localhost testdrv]# ./test
abcdefghijklmnop

string len = 17
[root@localhost testdrv]# ./test
abcdefghijklmnop

string len = 17
[root@localhost testdrv]# ./test
abcdefghijklmnop

string len = 17

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
7 [报告]
发表于 2013-09-25 17:45 |只看该作者
回复 6# hejianet

大哥,你是用的我的代码吗?难道是我环境的问题?
   

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
8 [报告]
发表于 2013-09-25 19:51 |只看该作者
回复 4# goingstudy

应该和cache coherent有关
你的是什么平台?

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
9 [报告]
发表于 2013-09-25 21:33 |只看该作者
手头没有linux 机器,在xcp的一虚拟机上,centos 6, 内核2.6吧

论坛徽章:
1
IT运维版块每日发帖之星
日期:2015-12-20 06:20:00
10 [报告]
发表于 2013-09-25 21:35 |只看该作者
回复 8# arm-linux-gcc

与cache有关,那应该额外做什么操作吗?
   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP