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

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时可以映射到用户空间

 


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值