linux mmap驱动实现

来源:互联网 发布:制作闪光字软件 编辑:程序博客网 时间:2024/05/16 09:30

近几天有个项目需要实现用户层与内核共享内存。在前几篇博客中找到的均是kernel2.4的。实现过程中,改的痛苦。对kernel源码才,勉强搞定。

后来在此网站(http://www.scs.ch/~frey/linux/memorymap.html)发现原来有一个demo:

#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
#ifdef MODVERSIONS
#  include<linux/modversions.h>
#endif
#include <asm/io.h>



static dev_t mmap_dev;
static struct cdev mmap_cdev;



static int mmap_open(struct inode *inode, struct file *filp);
static int mmap_release(struct inode *inode, struct file*filp);
static int mmap_mmap(struct file *filp, struct vm_area_struct*vma);



static struct file_operations mmap_fops = {
       .open = mmap_open,
       .release = mmap_release,
       .mmap = mmap_mmap,
       .owner = THIS_MODULE,
};


// internal data
// length of the two memory areas
#define NPAGES 16
// pointer to the vmalloc'd area - alway page aligned
static int *vmalloc_area;
// pointer to the kmalloc'd area, rounded up to a pageboundary
static int *kmalloc_area;
// original pointer for kmalloc'd area as returned by kmalloc
static void *kmalloc_ptr;



static int mmap_open(struct inode *inode, struct file *filp)
{
       return 0;
}

static int mmap_release(struct inode *inode, struct file*filp)
{
       return 0;
}


// helper function, mmap's the kmalloc'd area which is physicallycontiguous
int mmap_kmem(struct file *filp, struct vm_area_struct *vma)
{
       int ret;
       long length = vma->vm_end -vma->vm_start;


      
       if (length > NPAGES *PAGE_SIZE)
              return -EIO;


      
       if ((ret = remap_pfn_range(vma,
                             vma->vm_start,
                             virt_to_phys((void *)kmalloc_area)>> PAGE_SHIFT,
                             length,
                             vma->vm_page_prot))< 0) {
              return ret;
       }
       
       return 0;
}
// helper function, mmap's the vmalloc'd area which is notphysically contiguous
int mmap_vmem(struct file *filp, struct vm_area_struct *vma)
{
       int ret;
       long length = vma->vm_end -vma->vm_start;
       unsigned long start =vma->vm_start;
       char *vmalloc_area_ptr = (char*)vmalloc_area;
       unsigned long pfn;


      
       if (length > NPAGES *PAGE_SIZE)
              return -EIO;


      
       while (length > 0) {
              pfn =vmalloc_to_pfn(vmalloc_area_ptr);
              if ((ret =remap_pfn_range(vma, start, pfn, PAGE_SIZE,
                                    PAGE_SHARED)) < 0) {
                     returnret;
              }
              start += PAGE_SIZE;
              vmalloc_area_ptr +=PAGE_SIZE;
              length -= PAGE_SIZE;
       }
       return 0;
}



static int mmap_mmap(struct file *filp, struct vm_area_struct*vma)
{
      
       if (vma->vm_pgoff == 0) {
              return mmap_vmem(filp,vma);
       }
      
       if (vma->vm_pgoff == NPAGES){
              return mmap_kmem(filp,vma);
       }
      
       return -EIO;
}



static int __init mmap_init(void)
{
       int ret = 0;
       int i;


      
       if ((kmalloc_ptr = kmalloc((NPAGES + 2) *PAGE_SIZE, GFP_KERNEL)) == NULL) {
              ret = -ENOMEM;
              goto out;
       }
      
       kmalloc_area = (int *)((((unsignedlong)kmalloc_ptr) + PAGE_SIZE - 1) &PAGE_MASK);


      
       if ((vmalloc_area = (int *)vmalloc(NPAGES *PAGE_SIZE)) == NULL) {
              ret = -ENOMEM;
              goto out_kfree;
       }


      
       if ((ret =alloc_chrdev_region(&mmap_dev, 0, 1, "mmap"))< 0) {
              printk(KERN_ERR "could notallocate major number for mmap\n");
              goto out_vfree;
       }


      
       cdev_init(&mmap_cdev,&mmap_fops);
       if ((ret = cdev_add(&mmap_cdev,mmap_dev, 1)) < 0) {
              printk(KERN_ERR "could notallocate chrdev for mmap\n");
              gotoout_unalloc_region;
       }


      
       for (i = 0; i < NPAGES *PAGE_SIZE; i+= PAGE_SIZE) {
             SetPageReserved(vmalloc_to_page((void *)(((unsignedlong)vmalloc_area) + i)));
             SetPageReserved(virt_to_page(((unsigned long)kmalloc_area) +i));
       }


      
       for (i = 0; i < (NPAGES *PAGE_SIZE / sizeof(int)); i += 2) {
              vmalloc_area[i] = (0xaffe<< 16) + i;
              vmalloc_area[i + 1] = (0xbeef<< 16) + i;
              kmalloc_area[i] = (0xdead<< 16) + i;
              kmalloc_area[i + 1] = (0xbeef<< 16) + i;
       }
       
       return ret;
       
  out_unalloc_region:
       unregister_chrdev_region(mmap_dev, 1);
  out_vfree:
       vfree(vmalloc_area);
  out_kfree:
       kfree(kmalloc_ptr);
  out:
       return ret;
}



static void __exit mmap_exit(void)
{
       int i;


      
       cdev_del(&mmap_cdev);
       unregister_chrdev_region(mmap_dev, 1);


      
       for (i = 0; i < NPAGES *PAGE_SIZE; i+= PAGE_SIZE) {
             SetPageReserved(vmalloc_to_page((void *)(((unsignedlong)vmalloc_area) + i)));
             SetPageReserved(virt_to_page(((unsigned long)kmalloc_area) +i));
       }
      
       vfree(vmalloc_area);
       kfree(kmalloc_ptr);
}


module_init(mmap_init);
module_exit(mmap_exit);
MODULE_DESCRIPTION("mmap demo driver");
MODULE_AUTHOR("Martin Frey<frey@scs.ch>");
MODULE_LICENSE("BSD");

0 0