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

linux 内存映射2 内核/用户进程间通信

2007-07-24 13:41 363 查看
1、register_chrdev() 函数注册字符设备:

 if (register_chrdev(MAJOR_NUM, " gobalvar ", &gobalvar_fops))
 {
  //…注册失败
 }
 else
 {
  //…注册成功
 }
  其中,register_chrdev函数中的参数MAJOR_NUM为主设备号,"gobalvar"为设备名,gobalvar_fops为包含基本函数入口点的结构体,类型为file_operations。当gobalvar模块被加载时,gobalvar_init被执行,它将调用内核函数 register_chrdev,把驱动程序的基本入口点指针存放在内核的字符设备地址表中,在用户进程对该设备执行系统调用时提供入口地址。

2、virt_to_phys、ioremap被定义为一个Marco,其原型为__ioremap,所以在编译时要加选项 -O1(或-O2).

3、int remap_page_range(unsigned long from, unsigned long phys_addr, unsigned long size,

pgprot_t prot)

其中from是映射开始的虚拟地址。这个函数为虚拟地址空间from和from+size之间的范围构栽 页表;

phys_addr是虚拟地址应该映射到的物理地址;size是被映射区域的大小;prot是保护标志

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/wrapper.h> /* for mem_map_(un)reserve */
#include <asm/io.h> /* for virt_to_phys */
#include <linux/slab.h> /* for kmalloc and kfree */

//宏MODULE_PARM(var,type) 用于向模块传递命令行参数。
//var为接受参数值的变量名,type为采取如下格式的字符串[min[-max]]{b,h,i,l,s}。
//min及max 用于表示当参数为数组类型时,允许输入的数组元素的个数范围;
//b:byte;h:short;i:int;l:long;s:string。
//如果为MODULE_PARM(myintArray, "4i"),那么表示数组的最大长度为4

MODULE_PARM(mem_start, "i");
MODULE_PARM(mem_size, "i");

static int mem_start = 201, mem_size = 10;
static char *reserve_virt_addr;
static int major;

int mmapdrv_open(struct inode *inode, struct file *file);
int mmapdrv_release(struct inode *inode, struct file *file);
int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma);
int mmapdrv_close(struct inode *inode, struct file *file);
/*
* NOTE:
* read, write, poll, fsync, readv, writev can be called
* without the big kernel lock held in all filesystems.
*/
//struct file_operations {
// struct module *owner;
// loff_t (*llseek) (struct file *, loff_t, int);
// ssize_t (*read) (struct file *, char *, size_t, loff_t *);
// ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
// int (*readdir) (struct file *, void *, filldir_t);
// unsigned int (*poll) (struct file *, struct poll_table_struct *);
// int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
// int (*mmap) (struct file *, struct vm_area_struct *);
// int (*open) (struct inode *, struct file *);
// int (*flush) (struct file *);
// int (*release) (struct inode *, struct file *);
// int (*fsync) (struct file *, struct dentry *, int datasync);
// int (*fasync) (int, struct file *, int);
// int (*lock) (struct file *, int, struct file_lock *);
// ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
// ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
// ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
// unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
//};

static struct file_operations mmapdrv_fops = { owner: THIS_MODULE,
mmap: mmapdrv_mmap, open: mmapdrv_open,// close: mmapdrv_close,
release: mmapdrv_release
};

int init_module(void) {
if ((major = register_chrdev(0, "mmapXuangdrv", &mmapdrv_fops)) < 0) {
printk("mmapdrv: unable to register character device/n");
return ( -EIO);
}

printk("mmap device major = %d/n", major);

printk("high memory physical address 0x%ldM/n", virt_to_phys(high_memory)
/1024/ 1024);

reserve_virt_addr = ioremap(mem_start *1024* 1024, mem_size*1024* 1024 );

if (reserve_virt_addr) {
int i;
printk("reserve_virt_addr = 0x%lx/n", (unsigned long)reserve_virt_addr);
for (i = 0; i < mem_size *1024* 1024; i += 4) {
reserve_virt_addr[i] = 'a';
reserve_virt_addr[i + 1] = 'b';
reserve_virt_addr[i + 2] = 'c';
reserve_virt_addr[i + 3] = 'd';
}
} else {
printk("reserve_virt_addr = 0x%lx;so return -ENODEV;/n", (unsigned long)reserve_virt_addr);
unregister_chrdev(major, "mmapXuangdrv");
return -ENODEV;
}
return 0;
}

/* remove the module */
void cleanup_module(void) {
if (reserve_virt_addr)
iounmap(reserve_virt_addr);

unregister_chrdev(major, "mmapXuangdrv");
return;
}

int mmapdrv_open(struct inode *inode, struct file *file) {
MOD_INC_USE_COUNT;
return (0);
}
int mmapdrv_close(struct inode *inode, struct file *file) {
MOD_DEC_USE_COUNT;
return (0);
}

int mmapdrv_release(struct inode *inode, struct file *file) {
MOD_DEC_USE_COUNT;
return (0);
}

int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma) {
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long size = vma->vm_end - vma->vm_start;

if (size > mem_size *1024* 1024) {
printk("size too big/n");
return ( -ENXIO);
}

offset = offset + mem_start * 1024* 1024;

/* we do not want to have this area swapped out, lock it */
vma->vm_flags |= VM_LOCKED;
//if (remap_page_range(vma, vma->vm_start, offset, size, PAGE_SHARED)) {
if (remap_page_range(vma->vm_start, offset, size, PAGE_SHARED)) {
printk("remap page range failed/n");
return -ENXIO;
}
printk("First char is: = %c/n", *((char *)vma->vm_start));
return (0);
}

在系统能够启动的时候自动的做了预留空间,并且在用户使用mmap时可以映射到用户空间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: