Example of Linux kernel and application Data communication (four): Mapping device kernel space to user state

Source: Internet
Author: User

"copyright notice: respect for the original, reproduced please retain the source: blog.csdn.net/shallnet. The article is for academic communication only and should not be used for commercial purposes "
    the memory image of a process consists of the following parts: code snippet, data segment, BSS segmentand Stack segments. And the area of the memory map,memory-mapped function mmap (), which is responsible for mapping the contents of the file to the virtual memory space of the process, through reading and altering the memory. To implement the read and change of the file, and the file can be a device-driven file node.

By mapping the kernel-driven memory space to the application layer. Enables data exchange between applications and kernel space.

three types of Linux devices, character devices, block devices, network interfaces equipment. Each character device or block device is a corresponding device file in the/dev folder.

The Linux User program uses a device file (or device node) to manipulate character devices and block devices using a driver.

This section uses the character device driver as an example to implement the mapping. For more information about character device drivers, refer to the author of this article:
http://blog.csdn.net/shallnet/article/details/17734309
The key to implementing memory mapping is to implement the character device-driven mmap () function, and the mmap () function prototype is:
#include <sys/mman.h>void *mmap (void *addr, size_t length, int prot, int flags,  int fd, off_t offset);
This function is responsible for mapping the contents of the file to the virtual address space of the process, through reading and changing the memory to realize the read and change of the file, without the need to call read and write;
The Mmap method is a member of the file_operations struct that is called when the MMAP system call is issued. the mmap device method needs to do is to establish a virtual address to the physical address of the page table .

In fact, when we call mmap, the Sys_mmap function in the kernel first creates a new VMA based on the parameters that the user provides to mmap, such as start address, space size, behavior modifier, and so on . The Mmap function in the file_operations of the corresponding file is then called.

process virtual address space related content you can refer to the author of this article:
http://blog.csdn.net/shallnet/article/details/47701225
Use the Remap_pfn_range () function to map device memory linearly to the user address space. The function prototype is:
/** * Remap_pfn_range-remap kernel memory to userspace * @vma: User VMA to map to * @addr: Target user address to start At * @pfn: Physical Address of kernel memory * @size: Size of Map area * @prot: page protection, flags for this mapping * *  Note:this is only safe if the mm semaphore are held when called. */int remap_pfn_range (struct vm_area_struct *vma, un Signed long addr,            unsigned long pfn, unsigned long size, pgprot_t prot)
The VMA is the virtual memory area. Pages within a certain range will be mapped to the region.
Addr is the start address when the mapping is another time. This function establishes a page table for the virtual address between addr and addr+size.

PFN is the page frame number for the physical memory for, the page frame number is simply the physical address shifted to the right page_shift bit.
Size is in bytes and is mapped again.


Prot the "protection" attribute required for the new VMA.

Here's a look at The implementation of MMAP members in File_operations:
static struct vm_operations_struct sln_remap_vm_ops = {. open = Sln_vma_open,. Close = sln_vma_close};static int Chrmem_dev_mmap (struct file*filp, struct vm_area_struct *vma) {struct Mem_dev *dev = fil           p->private_data; if (Remap_pfn_range (Vma,vma->vm_start,virt_to_phys (dev->data) >>page_shift, VMA->VM_END-VMA->VM                    _start, Vma->vm_page_prot)) Return-eagain;    Vma->vm_ops = &sln_remap_vm_ops;      Sln_vma_open (VMA); return 0;} 
function in this function PAGE_TO_PFN Span style= "font-family:"microsoft yahei"; Color: #1a1a1a; Font-style:normal; Font-weight:700 "> ( shm_page ) The main idea of this character device driver is to create a character device, request a piece of physical memory in its driver, and use Mmap to map this area of physical memory to the address space of the process. The driver source code such as the following:
#include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/errno.h > #include <linux/mm.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/ cdev.h> #include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> #include <linux/ kernel.h> #include "chr_memdev.h" int chrmem_major;struct chrmem_dev *chrmem_devp;int chrmem_open (struc        T inode *inode, struct file *filp) {filp->private_data = CHRMEM_DEVP; return 0;} ... void Sln_vma_open (struct vm_area_struct *vma) {PRINTK ("===vma_open:%s===\n", chrmem_devp->data);} void Sln_vma_close (struct vm_area_struct *vma) {PRINTK ("===vma_close:%s===\n", chrmem_devp->data);} static struct Vm_operations_struct Sln_remap_vm_ops = {. open = Sln_vma_open,. Close = Sln_vma_close};int chrmem_ Release (struct inode *inode, struct file *filp) {return 0;} static int Chrmem_dev_mmap (struct FILE*FILP, struct Vm_area_struct *vma) {struct Chrmem_dev *dev = filp->private_data; if (Remap_pfn_range (Vma,vma->vm_start,virt_to_phys (dev->data) >>page_shift, VMA-&GT;VM_END-VMA-&GT;VM                    _start, Vma->vm_page_prot)) Return-eagain;    Vma->vm_ops = &sln_remap_vm_ops;      Sln_vma_open (VMA); return 0;} static const struct File_operations chrmem_fops ={. Owner = This_module,. Open = Chrmem_open,. Release = Chrmem _release,. Read = Chrmem_read,. Write = Chrmem_write,. Llseek = Chrmem_llseek,. IOCTL = Chrmem_ioctl,. mm    AP = chrmem_dev_mmap};static int Chrmem_dev_init (void) {int result;    dev_t Devno;    /* Assign the device number */result = Alloc_chrdev_region (&devno, 0, 1, "Chrmem_dev");    if (Result < 0) {return result;    }//Assign memory space for yourself to define the device structure MEM_DEVP = kmalloc (Memdev_nr_devs * sizeof (struct mem_dev), gfp_kernel);        if (!MEM_DEVP) {result =-enomem;    Goto err; } memset (Mem_DEVP, 0, sizeof (struct mem_dev));    /* Initialize the character device */Cdev_init (&mem_devp->cdev, &mem_fops);     Mem_devp->cdev.owner = This_module;    /* Join the registration character device */mem_major = major (Devno);       Cdev_add (&mem_devp->cdev, MKDEV (mem_major, 0), Memdev_nr_devs);    /* Initialize yourself to define device data contents */Mem_devp->data = Kmalloc (memdev_size, Gfp_kernel);        memset (Mem_devp->data, ' * ', memdev_size/100);   Return 0;err:unregister_chrdev_region (Devno, 1); return result;}    static int chrmem_dev_init (void) {int result;    dev_t Devno;    /* Assign the device number */result = Alloc_chrdev_region (&devno, 0, 1, "Chrmem_dev");    if (Result < 0) {return result;    }//define the device structure for yourself allocate memory empty CHRMEM_DEVP = Kmalloc (chr_memdev_num * sizeof (struct chrmem_dev), gfp_kernel);        if (!CHRMEM_DEVP) {result =-enomem;    Goto err;     } memset (CHRMEM_DEVP, 0, sizeof (struct chrmem_dev));    /* Initialize the character device */Cdev_init (&chrmem_devp->cdev, &chrmem_fops); Chrmem_devp->cdEv.owner = This_module;    /* Join the registration character device */chrmem_major = major (Devno);       Cdev_add (&chrmem_devp->cdev, MKDEV (chrmem_major, 0), chr_memdev_num);    /* Initialize yourself to define device data contents */Chrmem_devp->data = Kmalloc (chr_memdev_data_size, Gfp_kernel);        memset (Chrmem_devp->data, ' * ', chr_memdev_data_size/100);   Return 0;err:unregister_chrdev_region (Devno, 1); return result;} static void Chrmem_dev_exit (void) {Cdev_del (&chrmem_devp->cdev);//delete device Kfree (CHRMEM_DEVP);//Relea SE device Memory unregister_chrdev_region (MKDEV (chrmem_major, 0), 1); Unregister char device No.} Module_init (Chrmem_dev_init); Module_exit (Chrmem_dev_exit); Module_license ("GPL"); Module_author ("Shallnet"); Module_description ("Blog.csdn.net/shallnet");
Mmap is called in the application to implement memory-mapped, application code such as the following:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include <errno.h               > #include <sys/ioctl.h> #define shr_memsize 4096#define mem_clear 0x0#define mem_reset    0x1#define mem_dev_filename "/dev/sln_memdev" int main () {int fd;        char *shm = NULL;    FD = open (Mem_dev_filename, O_RDWR);        if (FD < 0) {printf ("open ():%s\n", Strerror (errno));    return-1; } SHM = Mmap (NULL, Shr_memsize, prot_read|    Prot_write, map_shared, FD, 0);    if (map_failed = = SHM) {printf ("Mmap:%s\n", Strerror (errno));    } printf ("Before Write, SHM =%s\n", SHM);        strcpy (SHM, "User write to share memory!");    printf ("after write, SHM =%s\n", SHM);  if (0 > ioctl (FD, Mem_clear, NULL)) {printf ("IOCTL:%s\n", Strerror (errno));      return-1;    } printf ("After clear, SHM =%s\n", SHM);        if (0 > ioctl (FD, Mem_reset, NULL)) {printf ("IOCTL:%s\n", Strerror (errno));    return-1;    } printf ("After reset, SHM =%s\n", SHM);    Munmap (SHM, shr_memsize);      Close (FD);    return 0; }
After the application implements the mapping, the output shared memory content is read first and then written. The shared memory content is then emptied and the shared memory is reset.

After compiling the driver and application, insert the driver first. When the device node is created, the final execution of the application looks successful. For example, the following:

# Insmod memdev.ko# cat/proc/devices | grep chrmem_dev248 chrmem_dev# mknod  /dev/sln_memdev C 248 0# lsapp  app_read  DRV  Makefile  Mem_app  Memdev.ko  read_app#./mem_appbefore Write, SHM = ****************************************after Write, SHM = User write to share memory! After clear, SHM =after reset, SHM = Hello, user!#
You can see that the character device-driven kernel space is successfully mapped to the user state, and now a piece of memory in the user space is associated to device memory. Reading and writing to the user space is equivalent to reading and writing to the character device.

This section source code download:http://download.csdn.net/detail/gentleliu/9035831

Example of Linux kernel and application Data communication (four): Mapping device kernel space to user state

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.