linux mmap驱动实现

近几天有个项目需要实现用户层与内核共享内存。在前几篇博客中找到的均是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 page boundary
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 physically contiguous
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 not physically 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) {
                        return ret;
                }
                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 *)((((unsigned long)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 not allocate 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 not allocate chrdev for mmap\n");
                goto out_unalloc_region;
        }


       
        for (i = 0; i < NPAGES * PAGE_SIZE; i+= PAGE_SIZE) {
                SetPageReserved(vmalloc_to_page((void *)(((unsigned long)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 *)(((unsigned long)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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值