Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
来源:互联网 发布:网络电视盒子排名 编辑:程序博客网 时间:2024/05/18 01:53
动态的将内核空间的物理地址和大小传给用户空间。本文也演示了内核空间和用户空间进行通信可以使用的两种常用方法: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,相当于告诉系统,这个页面我已经占了。对于每一个申请到的页面,应该都要这样做。
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- Linux内核和用户空间通信的方式— proc文件和mmap共享内存
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap
- 内核和用户空间共享内存的实现例程-proc和mmap(zt)
- 内核和用户空间共享内存的实现例程-proc和mmap
- Linux的内核空间和用户空间通过内存共享来进行通信的实现
- Linux的内核空间和用户空间通过内存共享来进行通信的实现
- linux系统内核空间和用户空间的通信方式
- Linux\Unix IPC进程通信实例分析(一):共享内存通信---文件映射mmap方式
- 利用mmap实现用户空间与内核空间的共享内存通信
- C#写的QQ找茬外挂
- js调用webservice
- 第一帖,为了开通
- 关于mysql中orderby的几个注意事项
- Meta-Object系统-10
- Linux内核和用户空间通信的方式(一)— proc文件和mmap共享内存
- QMainWindow-11
- 二叉排序树的创建,插入,遍历
- 判断排序是否到临界值
- 6月初 gdlover.com网站更新
- QQREADERA05782A6A91E1EE5
- GAE报错“NameError: global name 'execfile' is not defined”
- www.zdwsjd.net服务器ip地址更换通知
- www.gdlover.com网站首页改版进行中