博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核和用户空间通信的方式— proc文件和mmap共享内存
阅读量:2427 次
发布时间:2019-05-10

本文共 5290 字,大约阅读时间需要 17 分钟。

动态的将内核空间的物理地址和大小传给用户空间。本文也演示了内核空间和用户空间进行通信可以使用的两种常用方法:proc文件系统和mmap共享内存。

整个内核模块,在模块插入时建立proc文件,分配内存。卸载模块的时候将用户空间写入的内容打印出来。
以下是内核模块的代码和用户空间的测试代码。

/*This program is used to allocate memory in kernel

and pass the physical address to userspace through proc file.*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/mm.h>
#define PROC_MEMSHARE_DIR"memshare"
#define PROC_MEMSHARE_PHYADDR"phymem_addr"
#define PROC_MEMSHARE_SIZE"phymem_size"
/*alloc one page. 4096 bytes*/
#define PAGE_ORDER 0
/*this value can get from PAGE_ORDER*/
#define PAGES_NUMBER 1
struct proc_dir_entry *proc_memshare_dir ;
unsigned long kernel_memaddr= 0;
unsigned long kernel_memsize= 0;
static int proc_read_phymem_addr(char*page, char **start, off_t off,int count)
{
        return sprintf(page,"%08lx\n", __pa(kernel_memaddr));
}
static int proc_read_phymem_size(char*page, char **start, off_t off,int count)
{
        return sprintf(page,"%lu\n", kernel_memsize);
}
static int __init init(void)
{
        /*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);
        if(!kernel_memaddr)
        {
                 printk("Allocate memory failure!\n");
        }
        else
        {
                 SetPageReserved(virt_to_page(kernel_memaddr));

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

                 kernel_memsize = PAGES_NUMBER * PAGE_SIZE;
                 printk("Allocate memory success!. The phy mem addr=%08lx, size=%lu\n", __pa(kernel_memaddr), kernel_memsize);
        }
        return 0;
}
static void __exit fini(void)
{
         printk("The content written by user is: %s\n",(unsigned char *) kernel_memaddr);
         ClearPageReserved(virt_to_page(kernel_memaddr));
         free_pages(kernel_memaddr, PAGE_ORDER);
         remove_proc_entry(PROC_MEMSHARE_PHYADDR, proc_memshare_dir);
         remove_proc_entry(PROC_MEMSHARE_SIZE, proc_memshare_dir);
         remove_proc_entry(PROC_MEMSHARE_DIR,NULL);
        return;
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Godbach ([email]nylzhaowei@163.com[/email])");
MODULE_DESCRIPTION("Kernel memory share module.");

用户空间的测试代码:

#include<stdio.h>

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
int main(int argc,char* argv[])
{
        if(argc!= 2)
        {
                printf("Usage: %s string\n", argv[0]);
                return 0;
        }
        
        unsigned long phymem_addr, phymem_size;
        char *map_addr;
        char s[256];
        int fd;
        
        /*get the physical address of allocated memory in kernel*/
         fd = open("/proc/memshare/phymem_addr", O_RDONLY);
        if(fd < 0)
        {
                printf("cannot open file /proc/memshare/phymem_addr\n");
                return 0;
        }
        read(fd, s,sizeof(s));
        sscanf(s,"%lx", &phymem_addr);
        close(fd);
        /*get the size of allocated memory in kernel*/
         fd = open("/proc/memshare/phymem_size", O_RDONLY);
        if(fd < 0)
        {
                printf("cannot open file /proc/memshare/phymem_size\n");
                return 0;
        }
        read(fd, s,sizeof(s));
        sscanf(s,"%lu", &phymem_size);
        close(fd);
        
        printf("phymem_addr=%lx, phymem_size=%lu\n", phymem_addr, phymem_size);
        /*memory map*/
        int map_fd =open("/dev/mem", O_RDWR);
        if(map_fd< 0)
        {
                printf("cannot open file /dev/mem\n");
                return 0;
        }
        
         map_addr = mmap(0, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr);
        strcpy(map_addr, argv[1]);
         munmap(map_addr, phymem_size);
        close(map_fd);
        return 0;
        
}

测试的内核是2.6.25.以下是执行结果。

debian:/home/km/memshare# insmod memshare_kernel.ko

debian:/home/km/memshare# ./memshare_user 'hello,world!'
phymem_addr=e64e000, phymem_size=4096
debian:/home/km/memshare# cat /proc/memshare/phymem_addr
0e64e000
debian:/home/km/memshare# cat /proc/memshare/phymem_size
4096
debian:/home/km/memshare# rmmod memshare_kernel
debian:/home/km/memshare# tail /var/log/messages
Sep 27 18:14:24 debian kernel: [50527.567931] Allocate memory success!. The phy mem addr=0e64e000, size=4096
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);
   [color=royalblue]        order = get_order(4000000);
         kernel_memaddr =__get_free_pages(GFP_KERNEL, order);
[/color]
         if(!kernel_memaddr)
         {
                 printk("Allocate memory failure!\n");
         }
         else
         {
                 SetPageReserved(virt_to_page(kernel_memaddr));
                 //kernel_memsize = PAGES_NUMBER * PAGE_SIZE;
                [color=royalblue] kernel_memsize = ((4000000 - 1) >> PAGE_SHIFT)* PAGE_SIZE;[/color]
[color=#4169e1][/color]
[color=black]...[/color]
[color=black]}[/color]
[color=black][/color]
[color=black][/color]
我在内核中往第一页(4k范围内)写数据,在用户态是能够读出来的,但是如果向以后的其它页写数据时,用户态就读不出了,
用户态写也这样。

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

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

转载地址:http://rebmb.baihongyu.com/

你可能感兴趣的文章
苹果公司揭秘首批列入 Swift 源代码兼容性开源项目清单
查看>>
Python 玩转物联网之 Micropython GPIO IRQ 处理
查看>>
移动周刊第 188 期:Android 安全性要点与规范核心详析
查看>>
手机为基础的 IoT 布局已经失效,下一代操作系统是什么模样?
查看>>
无线传感器网络使用指南
查看>>
Unity 脚本优化的那些坑
查看>>
《近匠》专访机智云 CTO 刘琰——从 0 到 1 开启智能化硬件开发
查看>>
深度对话微软,解读 HoloLens 技术设计细节
查看>>
移动周刊第 191 期:如何看待 Kotlin 成为 Android 官方支持开发语言?
查看>>
物联网浪潮之下,前端工程师如何迎刃而上?
查看>>
从端到云——工业物联网项目全栈快速开发
查看>>
LoRa vs NB-IOT:哪个物联网标准更具优势?
查看>>
移动周刊第 205 期:Google 正式发布 ARCore 预览版、iOS 工程打包速度提升十倍的解决方案...
查看>>
八大 IoT 安全关键技术解析
查看>>
有钱 Python,没钱 PHP,编程语言也嫌贫爱富
查看>>
Docker是啥?容器变革的火花?
查看>>
假如从餐饮店的角度来看架构…
查看>>
这个充电宝太黑科技了,又小又不用自己带线,长见识了~
查看>>
HDC.2019后再发力,AppGallery Connect服务新升级
查看>>
网易云音乐热评的规律,44万条数据告诉你
查看>>