免费注册 查看新帖 |

Chinaunix

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

Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存  关闭 [复制链接]

论坛徽章:
1
操作系统版块每日发帖之星
日期:2015-06-19 22:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-12-20 16:43 |只看该作者 |倒序浏览
本帖最后由 jlwcb 于 2011-12-20 16:46 编辑

动态的将内核空间的物理地址和大小传给用户空间。本文也演示了内核空间和用户空间进行通信可以使用的两种常用方法:proc文件系统和mmap共享内存。
整个内核模块,在模块插入时建立proc文件,分配内存。卸载模块的时候将用户空间写入的内容打印出来。
以下是内核模块的代码和用户空间的测试代码。
  1. /*This program is used to allocate memory in kernel
  2. and pass the physical address to userspace through proc file.*/

  3. #include <linux/version.h>
  4. #include <linux/module.h>
  5. #include <linux/proc_fs.h>
  6. #include <linux/mm.h>

  7. #define PROC_MEMSHARE_DIR "memshare"
  8. #define PROC_MEMSHARE_PHYADDR "phymem_addr"
  9. #define PROC_MEMSHARE_SIZE "phymem_size"

  10. /*alloc one page. 4096 bytes*/
  11. #define PAGE_ORDER 0
  12. /*this value can get from PAGE_ORDER*/
  13. #define PAGES_NUMBER 1

  14. struct proc_dir_entry *proc_memshare_dir ;
  15. unsigned long kernel_memaddr = 0;
  16. unsigned long kernel_memsize= 0;

  17. static int proc_read_phymem_addr(char *page, char **start, off_t off, int count)
  18. {
  19.         return sprintf(page, "%08lx\n", __pa(kernel_memaddr));
  20. }
  21. static int proc_read_phymem_size(char *page, char **start, off_t off, int count)
  22. {
  23.         return sprintf(page, "%lu\n", kernel_memsize);
  24. }

  25. static int __init init(void)
  26. {
  27.         /*build proc dir "memshare"and two proc files: phymem_addr, phymem_size in the dir*/
  28.          proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL);
  29.          create_proc_info_entry(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, proc_read_phymem_addr);
  30.          create_proc_info_entry(PROC_MEMSHARE_SIZE, 0, proc_memshare_dir, proc_read_phymem_size);

  31.         /*alloc one page*/
  32.          kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER);
  33.         if(!kernel_memaddr)
  34.         {
  35.                  printk("Allocate memory failure!\n");
  36.         }
  37.         else
  38.         {
  39.                  SetPageReserved(virt_to_page(kernel_memaddr));

  40. 内核中申请到页面之后,要调用一下SetPageReserved,相当于告诉系统,这个页面我已经占了。对于每一个申请到的页面,应该都要这样做

  41.                  kernel_memsize = PAGES_NUMBER * PAGE_SIZE;
  42.                  printk("Allocate memory success!. The phy mem addr=%08lx, size=%lu\n", __pa(kernel_memaddr), kernel_memsize);
  43.         }
  44.         return 0;
  45. }

  46. static void __exit fini(void)
  47. {
  48.          printk("The content written by user is: %s\n", (unsigned char *) kernel_memaddr);
  49.          ClearPageReserved(virt_to_page(kernel_memaddr));
  50.          free_pages(kernel_memaddr, PAGE_ORDER);
  51.          remove_proc_entry(PROC_MEMSHARE_PHYADDR, proc_memshare_dir);
  52.          remove_proc_entry(PROC_MEMSHARE_SIZE, proc_memshare_dir);
  53.          remove_proc_entry(PROC_MEMSHARE_DIR, NULL);

  54.         return;
  55. }
  56. module_init(init);
  57. module_exit(fini);
  58. MODULE_LICENSE("GPL");
  59. MODULE_AUTHOR("Godbach ([email]nylzhaowei@163.com[/email])");
  60. MODULE_DESCRIPTION("Kernel memory share module.");
复制代码
用户空间的测试代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <fcntl.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #include <sys/mman.h>

  9. int main(int argc, char* argv[])
  10. {
  11.         if(argc != 2)
  12.         {
  13.                 printf("Usage: %s string\n", argv[0]);
  14.                 return 0;
  15.         }
  16.         
  17.         unsigned long phymem_addr, phymem_size;
  18.         char *map_addr;
  19.         char s[256];
  20.         int fd;
  21.         
  22.         /*get the physical address of allocated memory in kernel*/
  23.          fd = open("/proc/memshare/phymem_addr", O_RDONLY);
  24.         if(fd < 0)
  25.         {
  26.                 printf("cannot open file /proc/memshare/phymem_addr\n");
  27.                 return 0;
  28.         }
  29.         read(fd, s, sizeof(s));
  30.         sscanf(s, "%lx", &phymem_addr);
  31.         close(fd);

  32.         /*get the size of allocated memory in kernel*/
  33.          fd = open("/proc/memshare/phymem_size", O_RDONLY);
  34.         if(fd < 0)
  35.         {
  36.                 printf("cannot open file /proc/memshare/phymem_size\n");
  37.                 return 0;
  38.         }
  39.         read(fd, s, sizeof(s));
  40.         sscanf(s, "%lu", &phymem_size);
  41.         close(fd);
  42.         
  43.         printf("phymem_addr=%lx, phymem_size=%lu\n", phymem_addr, phymem_size);
  44.         /*memory map*/
  45.         int map_fd = open("/dev/mem", O_RDWR);
  46.         if(map_fd < 0)
  47.         {
  48.                 printf("cannot open file /dev/mem\n");
  49.                 return 0;
  50.         }
  51.         
  52.          map_addr = mmap(0, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr);
  53.         strcpy(map_addr, argv[1]);
  54.          munmap(map_addr, phymem_size);
  55.         close(map_fd);
  56.         return 0;
  57.         
  58. }
复制代码
测试的内核是2.6.25.以下是执行结果。
  1. debian:/home/km/memshare# insmod memshare_kernel.ko
  2. debian:/home/km/memshare# ./memshare_user 'hello,world!'
  3. phymem_addr=e64e000, phymem_size=4096
  4. debian:/home/km/memshare# cat /proc/memshare/phymem_addr
  5. 0e64e000
  6. debian:/home/km/memshare# cat /proc/memshare/phymem_size
  7. 4096
  8. debian:/home/km/memshare# rmmod memshare_kernel
  9. debian:/home/km/memshare# tail /var/log/messages
  10. Sep 27 18:14:24 debian kernel: [50527.567931] Allocate memory success!. The phy mem addr=0e64e000, size=4096
  11. Sep 27 18:15:31 debian kernel: [50592.570986] The content written by user is: hello,world!
复制代码
用你这种方式,想申请4M的内存,

static int __init init(void)
{
     char * paddr;
     int order = 0;
     int offset = 0;
     int tmp = 0;
     
         /*build proc dir "memshare"and two proc files: phymem_addr, phymem_size in the dir*/
         proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL);
         create_proc_info_entry(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, proc_read_phymem_addr);
         create_proc_info_entry(PROC_MEMSHARE_SIZE,     0, proc_memshare_dir, proc_read_phymem_size);

         /*alloc one page*/
         //kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER);
           order = get_order(4000000);
         kernel_memaddr =__get_free_pages(GFP_KERNEL, order);

         if(!kernel_memaddr)
         {
                 printk("Allocate memory failure!\n");
         }
         else
         {
                 SetPageReserved(virt_to_page(kernel_memaddr));

                 //kernel_memsize = PAGES_NUMBER * PAGE_SIZE;
                kernel_memsize = ((4000000 - 1) >> PAGE_SHIFT)* PAGE_SIZE;

...
}


我在内核中往第一页(4k范围内)写数据,在用户态是能够读出来的,但是如果向以后的其它页写数据时,用户态就读不出了,
用户态写也这样。

需要对每个4k的页面执行:SetPageReserved(virt_to_page(kernel_memaddr));

内核中申请到页面之后,要调用一下SetPageReserved,相当于告诉系统,这个页面我已经占了。对于每一个申请到的页面,应该都要这样做。

转载自:http://hi.baidu.com/liuming910/b ... 85df72dab4bdbf.html

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
2 [报告]
发表于 2011-12-21 09:47 |只看该作者
唉,这个帖子经过几手的转载,原来就是我自己发的。

内核版或者驱动板就有这个帖子。

建议 LZ 不要一味的转贴,而是对于一些帖子和知识,发一些自己的见解和看法。

论坛徽章:
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 [报告]
发表于 2011-12-22 08:39 |只看该作者
呵呵。我说这哥们怎么突然发这么多高质量的帖子呢,原来都是抄袭的啊。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP