使用remap_pfn_range在启动时将映射存储器映射到用户空间

时间:2016-06-20 09:41:45

标签: linux-device-driver mmap ioremap chardev

我正在尝试使用remap_pfn_range将启动时(启动内核参数mem = 2G memmap = 30M $ 2G)的保留内存(30M偏移量为2G)映射到用户空间,下面是我的驱动程序代码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <asm/uaccess.h>
// #include <asm/error.h>

#define MAP_MAJOR 150

#define RAW_DATA_SIZE 0x1E00000 // 30 Mo
#define RAW_DATA_OFFSET 0x80000000 //2G

int results;
static void *rawdataStart = NULL;

static int map_mmap(struct file *filp, struct vm_area_struct *vma);

struct file_operations map_fops = {
        .open = nonseekable_open,
        .mmap = map_mmap
};

static int map_mmap(struct file *filp, struct vm_area_struct *vma) {
    if (rawdataStart == NULL) {
        printk(KERN_ERR "Memory not mapped!\n");
        return -EAGAIN;
    }
    if ((vma->vm_end - vma->vm_start) != RAW_DATA_SIZE) {
        printk(KERN_ERR "Error: sizes don't match (buffer size = %d, requested size = %lu)\n", RAW_DATA_SIZE, vma->vm_end - vma->vm_start);
        return -EAGAIN;
    }
    results = remap_pfn_range(vma, vma->vm_start, RAW_DATA_OFFSET >> PAGE_SHIFT, RAW_DATA_SIZE, PAGE_SHARED);
    if (results != 0) {
        printk(KERN_ERR "Error in calling remap_pfn_range: returned %d\n", results);
        return -EAGAIN;
    }

    return 0;
}

static int __init map_init(void)
{

    printk("init map module\n");

    if (register_chrdev(MAP_MAJOR,"mapReserved", &map_fops) <0 )
    {
        printk("unable to get major for map module\n");
        return -EBUSY;
    }


    rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE);
    if (rawdataStart == NULL) {
        printk(KERN_ERR "Unable to remap memory\n");
        return 1;
    }
    printk(KERN_INFO "ioremap returned %p\n", rawdataStart);

    return 0;
}

void __exit map_cleanup(void)
{
    printk("exit map module\n");
    unregister_chrdev(MAP_MAJOR,"mapReserved");
    if (rawdataStart != NULL) {
        printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart);
        iounmap(rawdataStart);
    } else {
        printk(KERN_WARNING "No memory to unmap!\n");
    }

    return;
}

MODULE_LICENSE("GPL");

module_init( map_init);
module_exit( map_cleanup);

我的用户空间应用程序位于

之下
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

#define RAW_DATA_SIZE 0x1E00000


int main(void)
{
  void * data;
  int fd = open("/dev/mapReserved", O_RDWR);
  if (fd == -1) {
         perror("open error...\n");
         return -1;
  }
  data = mmap(NULL, RAW_DATA_SIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 4096);
  close(fd);
  return 0;
}

当我插入模块时,它会返回

[  873.621763] init map module
[  873.623175] ioremap returned fb580000

但是当我执行用户空间应用程序时,它返回错误

open error...

1 个答案:

答案 0 :(得分:1)

我已经在这些引用后解决了这个问题:

1- Reserve memory in Linux driver module and share it using driver mmap

2- mmap of several GB of reserved memory using

在我的情况下,我从偏移量2G预留30M,而下面是代码

模块:

// #include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/debugfs.h>
#include <linux/kernel.h>   /* printk() */
#include <linux/slab.h>   /* kmalloc() */
#include <linux/fs.h>       /* everything... */
#include <linux/errno.h>    /* error codes */
#include <linux/types.h>    /* size_t */
#include <linux/mm.h>
#include <linux/kdev_t.h>
#include <asm/page.h>
#include <linux/cdev.h>

#include <linux/device.h>

#ifndef VM_RESERVED
# define  VM_RESERVED   (VM_DONTEXPAND | VM_DONTDUMP)
#endif

#define RAW_DATA_SIZE 31457280
#define RAW_DATA_OFFSET 0x80000000UL

void *rawdataStart;

struct dentry  *file;



/*
 * Open the device; in fact, there's nothing to do here.
 */
int simple_open (struct inode *inode, struct file *filp)
{
    return 0;
}


/*
 * Closing is just as simpler.
 */
static int simple_release(struct inode *inode, struct file *filp)
{
    return 0;
}



static int simple_remap_mmap(struct file *filp, struct vm_area_struct *vma)
{

    int ret;
        unsigned long mapoffset;
        mapoffset = RAW_DATA_OFFSET + (vma->vm_pgoff << PAGE_SHIFT);
        ret = remap_pfn_range(vma, vma->vm_start, mapoffset >> PAGE_SHIFT,
                              vma->vm_end - vma->vm_start, PAGE_SHARED);

        if ( ret != 0 ) {
            printk("Error remap_pfn_range. \n");
            return -EAGAIN;
        }
        return 0;
}

/* Device  uses remap_pfn_range */
static struct file_operations simple_remap_ops = {
    .owner   = THIS_MODULE,
    .open    = simple_open,
    .release = simple_release,
    .mmap    = simple_remap_mmap,
};

/*
 * Module housekeeping.
 */
static int simple_init(void)
{
    file = debugfs_create_file("mmap_example", 0644, NULL, NULL, &simple_remap_ops);
    rawdataStart = ioremap(RAW_DATA_OFFSET, RAW_DATA_SIZE);
    if (rawdataStart!=NULL){
        printk("rawdataStart at:%p  \n", rawdataStart);
        memset(rawdataStart, 'c', 20971520);
        memset(rawdataStart+20971520, '$', 100);

    }else{
        printk("rawdataStart is NULL \n");
        return -1;
    }



    return 0;
}


static void simple_cleanup(void)
{
    debugfs_remove(file);
    if (rawdataStart != NULL) {
            printk(KERN_INFO "Unmapping memory at %p\n", rawdataStart);
            iounmap(rawdataStart);
        } else {
            printk(KERN_WARNING "No memory to unmap!\n");
        }
}


module_init(simple_init);
module_exit(simple_cleanup);
MODULE_AUTHOR("Jonathan Corbet");
MODULE_LICENSE("Dual BSD/GPL");

和用户空间App:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>

#define RAW_DATA_SIZE 31457280

int main(int argc, char **argv) {
    int configfd;
    char * address = NULL;
    unsigned long chkSum;
    FILE *fp = fopen("results.log", "w+");

    configfd = open("/sys/kernel/debug/mmap_example", O_RDWR);
    if (configfd < 0) {
        perror("Open call failed");
        return -1;
    }

    address = (unsigned char*) mmap(NULL, RAW_DATA_SIZE, PROT_WRITE,
            MAP_PRIVATE, configfd, 0);
    if (address == MAP_FAILED) {
        perror("mmap operation failed");
        return -1;
    }

    fputs(address, fp);
    fclose(fp);

    close(configfd);
    return 0;
}