您的位置:首页 > 运维架构 > Linux

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

2014-11-05 00:19 405 查看
动态的将内核空间的物理地址和大小传给用户空间。本文也演示了内核空间和用户空间进行通信可以使用的两种常用方法: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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐