Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存

动态的将内核空间的物理地址和大小传给用户空间。本文也演示了内核空间和用户空间进行通信可以使用的两种常用方法: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>
#include <asm/uaccess.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;
//int size_length;
char mem_addr[12];
char mem_size[12];

static int proc_read_phymem_addr(struct file * file, char __user  *page, size_t size,  loff_t *pos)
{
//		printk("READ: size = %d\n", size);
		char *data;
		static int len = -1;
		data = PDE_DATA(file_inode(file));
		if(!data)
		{
			printk("NULL data\n");
			return 0;
		}

//		printk("len = %d\n", len);		
		if(len == -1)
			len = strlen(data);
		else if(len == 0) {
			len = strlen(data);
			return 0;
		}
			
		if(size > len)
			size = len;

		len -= size;
		//printk("before copy: size = %d\n", size);
		copy_to_user(page, data, size);
		printk("%s\n", kernel_memaddr);
		//printk("after copy, ret = %d\n", ret);
		if(size == 0)
			len = 0;
		return size;
       // return sprintf(page, "%08lx\n", __pa(kernel_memaddr));
}
static int proc_read_phymem_size(struct file *file, char __user *page, size_t size, loff_t *pos)
{
//		printk("READ_SIZE: size = %d\n", size);
		static int length = -1;
		char *data = PDE_DATA(file_inode(file));
		if(!data) {
			printk("NULL size data\n");
			return 0;
		}

		if(length  == -1) {
			length = strlen(data);
		}
		else if (length == 0) {
			length = strlen(data);
			return 0;
		}

		if(size > length)
			size = length;

		length -= size;
		copy_to_user(page, data, size);
		if(size == 0) 
			length = size;
		return size;
        //return sprintf(page, "%lu\n", kernel_memsize);
}

static const struct file_operations test_ops1 = {
	.owner = THIS_MODULE,
	.read = proc_read_phymem_addr,
};

static const struct file_operations test_ops2 = {
	.owner = THIS_MODULE,
	.read = proc_read_phymem_size,
};

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);
         //proc_create_data(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, &test_ops1, NULL);
         //proc_create_data(PROC_MEMSHARE_SIZE, 0, proc_memshare_dir, &test_ops2, NULL);

        /*alloc one page*/
         kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER);
        if(!kernel_memaddr)
        {
                 printk("Allocate memory failure!\n");
        }
        else
        {
				memset(kernel_memaddr, 0, 4096);
                 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);

			sprintf(mem_addr, "0x%08lx\n", __pa(kernel_memaddr));
			sprintf(mem_size, "%lu\n", kernel_memsize);
			//addr_length = strlen(mem_addr);
			//size_length = strlen(mem_size);	
			//printk("addr length: %d size lenght:%d\n", addr_length, size_length);

			proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL);
			proc_create_data(PROC_MEMSHARE_PHYADDR, 0, proc_memshare_dir, &test_ops1, mem_addr);
			proc_create_data(PROC_MEMSHARE_SIZE, 0, proc_memshare_dir, &test_ops2, mem_size);
        }
		

        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;
        
}
测试的内核是3.10.28. 以下是执行结果。
root@taotao:/mnt/code/modules#insmod  testproc.ko 
Allocate memory success!. The phy mem addr=65849000, size=4096
root@taotao:/mnt/code/modules#../testproc "hello, world"

phymem_addr=65849000, phymem_size=4096
root@taotao:/mnt/code/modules#cat /proc/memshare/phymem_addr 
root@taotao:/mnt/code/modules#cat /proc/memshare/phymem_addr 
hello, world
0x65849000
root@taotao:/mnt/code/modules#cat /proc/memshare/phymem_size 
root@taotao:/mnt/code/modules#cat /proc/memshare/phymem_size 
4096
root@taotao:/mnt/code/modules#
www.cnblogs.com/shaoguangleo/archive/2010/08/20/2805883.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值