linux-device-drivermmapioremapchardev

map reserver memory at boot to user space using remap_pfn_range


I am trying to map reserved memory (30M with offset of 2G) at boot time (boot kernel parameters mem=2G memmap=30M$2G) to user space using the remap_pfn_range, bellow is my driver code:

#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);

and my user space app is below

#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;
}

when i insert the module it's return

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

but when i am executing the user space app it's return error

open error...

Solution

  • I've resolved this problem following those references :

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

    2- mmap of several GB of reserved memory using

    in my case i am reserving 30M from the offset 2G and bellow is the code

    module:

    // #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");
    

    and the user space 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;
    }