Linux device-driven memory mapping __linux

Source: Internet
Author: User
Tags reserved

http://blog.csdn.net/chenjin_zhong/article/details/6314213


1. Memory Mapping

The so-called memory mapping is to map physical memory into the process's address space, these applications can directly use the input and output of the address space, so as to improve the efficiency of reading and writing. Linux provides the mmap () function to map physical memory.

In the driver, the application takes a device file as an object, invokes the Mmap () function, prepares the kernel for memory mapping, generates the VM_AREA_STRUCT structure, and then invokes the MMAP function defined in the device driver.

2. Types of Mappings

There are two ways to map the same physical address to a virtual address, the first of which is that the mmap () function maps the physical address to the virtual address space of the process, and the second method maps the Ioremap () function to a method on the kernel virtual address.

Mmap functions in the application:

void *mmap (void *start,size_t length,int prot,int flags,int offset);

Start is mapped to the virtual address of the process space

Size of length map space

Prot Read and Write permissions mapped to memory

Flags flags are preferable to map_shared,map_private,map_fixed, and if it is map_shared, the process of modifying content in the mapping space affects other processes, that is, visible to other processes, and map_private, The content modified by this process is not visible to other processes

FD file identifier to map the file

Offset map file location, generally starting from scratch. In the device file, the starting address that represents the mapping physical address

mmap function for device driver:

int mmap (struct file*filp,struct vm_area_struct *vma);

The MMAP function of the application is invoked first, then the kernel is properly processed, and the corresponding memory mapping is made, that is, the VM_AREA_STRUCT structure is generated and then passed to the MMAP function of the device driver.

For some of the parameter descriptions in VMA:

(1) unsigned long vm_start the starting address mapped to the process space

(2) unsigned long vm_end the end address mapped to the process space

(3) unsigned long vm_flags is the flags value contained in the mmap in the application, such as Vm_read,vm_write,vm_shared,vm_exec

(4) unsigned long vm_pgoff the offset mapped to physical memory

Methods of mmap Mapping:

There are two ways to create a page table, create a page table once, call function Remap_pfn_range, and call function Nopage each time you create a page table.

Remap_pfn_range:

This function is a one-time creation of a new page table to map the physical address.

int Remap_pfn_range (struct vma_area_struct* vma,unsigned long virt_addr,unsigned long pfn,unsigned long size,pgprot_t Prot);

Return value: Returns 0 if the mapping succeeds, or returns an incorrect negative code.

VMA the virtual memory area to which the physical address is mapped

VIRT_ADDR is mapped to the starting virtual address of the process space. The page table is established in the range of virt_addr to Virt_addr+size

PFN the page frame number corresponding to the physical address, typically the Vma->vm_pgoff field.

Size of the mapped region in bytes

Prot Vma->vm_page_prot

Nopage:

struct page * (*nopage) (struct vm_area_struct *vma,unsigned long address,int *type);

Vm_area_struct: Virtual memory Area

Address: Virtual addresses of the process space that occurred in page fault

Type page fault processing types

Get_page (struct page* pageptr);

Increases the number of times the mapped page is used.

3. The difference between Remap_pfn_range and nopage

(1) Remap_pfn_range a one-time Build page table, and nopage through the fault to find the kernel virtual address, and then through the kernel virtual address to find the corresponding physical page

(2) The Remap_pfn_range function maps only to the physical address of the reserved page and physical memory, but not to the regular Ram,remap_pfn_range function, and the Nopage function can map regular RAM.

4. Examples

The following example uses Remap_pfn_range and nopage to establish memory mappings, respectively.

Driver Memap.c:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/init.h>
#define SHARE_MEM_COUNT 4
#define SHARE_MEM_SIZE (Page_size*share_mem_count)

Module_license ("GPL");
Static char* reserve_virt_addr;
Static int major;
char* Share_memory=null;
int Mmapdrv_open (struct inode*,struct file* FILP);//driver's Open function
int mmapdrv_release (struct inode*,struct file* FILP)//Driver release function
int mmapdrv_mmap (struct file* file,struct vm_area_struct*vma);//driver mmap function
Void Simple_vma_open (struct vm_area_struct* VMA)//vm_operations_struct open function
void VMA on Simple_vma_close (virtual memory area) ( struct vm_area_struct *vma);//vma shutdown function
struct page* simple_vma_nopage (struct vm_area_struct* vma,unsigned long Address,int *type);//nopage map
struct page* simple_vma_nopage1 (struct vm_area_struct* vma,unsigned long address,int *type);
Static int simple_nopage_mmap (struct file* filp,struct vm_area_struct *vma);/The mmap in the driver and the above mmap can choose one
static struct file_operations mmapdrv_fops={
 owner:this_module,
 mmap:simple_nopage_mmap,
  Open:mmapdrv_open,
 release:mmapdrv_release,

};
static struct Vm_operations_struct simple_remap_vm_ops={
. Open=simple_vma_open,
. Close=simple_vma_close,
. Nopage=simple_vma_nopage1,

};

static int __init memc_init (void) {

if ((major= (Register_chrdev (0, "Mapdrv", &mmapdrv_fops)) <0) {
PRINTK ("register Mapdrv failure/n");
Return-eio;
}
PRINTK ("Register success,major=%d/n", major);

Share_memory=vmalloc (share_mem_size),//allocates memory by Vmalloc, returns the kernel virtual address, and then maps physical memory to the virtual address space of the process
int LP;
for (lp=0;lp<share_mem_count;lp++) {
sprintf (SHARE_MEMORY+PAGE_SIZE*LP, "Test%d", LP);
}

return 0;
}

static void __exit memc_exit (void) {
if (RESERVE_VIRT_ADDR) {
Iounmap (RESERVE_VIRT_ADDR);
}
Unregister_chrdev (Major, "mapdrv");
Return


}

int Mmapdrv_open (struct inode* inode,struct file* filp) {

Mod_inc_use_count;
return 0;

}

int mmapdrv_release (struct inode* inode,struct file* filp) {
Mod_dec_use_count;
return (0);

}

Remap_pfn_range the page table for a one-time mapping

int Mmapdrv_mmap (struct file* filp,struct vm_area_struct *vma) {

PRINTK ("vm_pgoff=0x%lx/n", Vma->vm_pgoff<<page_shift); The physical address offset is returned
PRINTK ("vm_start=0x%lx/n", vma->vm_start);//The starting address of the process address space
PRINTK ("vm_end=0x%lx/n", vma->vm_end)//The end address of the process address space
PRINTK ("vm_flags=0x%lx/n", vma->vm_flags);
unsigned long physical=vma->vm_pgoff<<page_shift;
unsigned long size=vma->vm_end-vma->vm_start; Spatial length of mappings
Vma->vm_flags|=vm_reserved;//remap can only map memory beyond vm_reserved and physical memory
vma->vm_flags|=vm_io;
if (Remap_pfn_range (vma,vma->vm_start,vma->vm_pgoff,size,page_shared)) {
PRINTK ("Remap page range failed/n");
Return-enxio;
}

PRINTK ("Remap page range success/n");
return 0;

}

Nopage Mapping
static int Simple_nopage_mmap (struct file* filp,struct vm_area_struct *vma) {
unsigned long offset=vma->vm_pgoff<<page_shift;
if (OFFSET>=__PA (high_memory) | | (Filp->f_flags&o_sync)) {
vma->vm_flags|=vm_io;
}
vma->vm_flags|=vm_reserved;
vma->vm_ops=&simple_remap_vm_ops;//When page fault occurs, the Nopage function is called for the fault handling
Simple_vma_open (VMA);
return 0;
}

void Simple_vma_open (struct vm_area_struct *vma) {
PRINTK (kern_notice "Simple VMA open virt%lx,phys%lx/n", vma->vm_start,vma->vm_pgoff<<page_shift);


}
void Simple_vma_close (struct vm_area_struct *vma) {
PRINTK (kern_notice "Simple VMA close./n");


}

Simple_vma_nopage the page is found through the physical address, and Simple_vma_nopage1 finds the page through the kernel virtual address, that is, the kernel virtual address that Vmalloc returns
struct page* simple_vma_nopage (struct vm_area_struct* vma,unsigned long address,int *type) {

PRINTK ("Call Nopage method/n");
struct page* pageptr;
unsigned long offset=vma->vm_pgoff<<page_shift;
unsigned long physaddr=address-vma->vm_start+offset; Address is the virtual address of the URL space of the page fault, Vm_start is the starting map address of the process address space, address-vma->vm_start+offset the physical address to map
unsigned long pageframe=physaddr>>page_shift;
PRINTK ("Offset is%LX, physaddr are%lx,pageframe is%lx/n", offset,physaddr,pageframe);
if (!pfn_valid (pageframe))
return nopage_sigbus;
Pageptr=pfn_to_page (pageframe)//According to the page frame number, get page
if (type)
*type=vm_fault_minor;
PRINTK ("Pageptr is%lx/n", (unsigned long) pageptr);
return pageptr;
}

First, the kernel virtual address is found based on the address space of the page fault, and then the corresponding page is found according to the kernel virtual address, i.e. the address returned by Vmalloc.

The content of the Address-vma->vm_start address range is obtained by Vmalloc () +address-vma->vm_start to the corresponding page, so for user space address-vma->vm_ The content of the start store is the content of the Vmalloc () +address-vma->vm_start corresponding page
struct page* simple_vma_nopage1 (struct vm_area_struct* vma,unsigned long address,int *type) {
struct page *page;
unsigned long offset1;
void *page_ptr;
unsigned long offset=vma->vm_pgoff<<page_shift;
unsigned long physaddr=address-vma->vm_start+offset;
unsigned long pageframe=physaddr>>page_shift;
PRINTK ("Vm_pgoff is%LX, Page_shift is%lx,page_size are%lx,offset is%LX, physaddr are%lx,pageframe is%lx/n", vma->vm_ Pgoff,page_shift, (unsigned long) page_size,offset,physaddr,pageframe);
offset1=address-vma->vm_start; Offset of mapped process address space
if (offset1>=share_mem_size) return nopage_sigbus;
page_ptr=share_memory+offset1;//the kernel virtual address of the corresponding page faults
PRINTK ("Address is%lx,vma->vm_start are%lx,offset1 is%lx,share_memory are%lx,page_ptr is%lx/n", address,vma->vm_ Start,offset1, (unsigned long) share_memory, (unsigned long) page_ptr);
Page=vmalloc_to_page (PAGE_PTR);
Get_page (page)//increase the use count of the page
if (type) *type=vm_fault_minor;
return page;

}


Module_init (Memc_init);
Module_exit (Memc_exit);

Test program:

TEST.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define SHARE_MEM_COUNT 4
#define SHARE_MEM_SIZE (4096*share_mem_count)
int main () {
int FD;
Char *data;
int loop;
Fd=open ("/dev/mapdrv", o_rdwr| O_ndelay);
if (fd>=0) {

Data= (char*) mmap (0,share_mem_size,prot_read| prot_write,map_shared,fd,0);
printf ("Data is%lx/n", (unsigned long) data);

printf ("[%s]/n", Data+4096*loop);
}
Munmap (data,share_mem_size);
Close (FD);
}
return 0;
}

Run:

(1) Put memap.c and test.c files in the/usr/src/kernels/linux-2.6.20/drivers/char directory.

and add obj-m to the makefile file +=MEMAP.O

(2) return to/usr/src/kernels/linux-2.6.20.

(3) Insert Module Insmod Memap.ko, then Mknod/dev/globalvar C 252 0

252 is the dynamically generated major value.

(4) Compiling test gcc-o test test.c

(5)./test, you can print out the written value.

[Test 0]

[Test 1]

[Test 2]

[Test 3]

Summarize:

1. For mmap memory mapping, the physical memory is mapped to the virtual address space of the process, so the process access to the file is equivalent to direct memory access, thus speeding up the efficiency of read and write operations. Here, the Remap_pfn_range function is a one-time creation of the page table, and the Nopage function is based on the process virtual address generated by page fault to find the corresponding logical address of the kernel, and then through this logical address to find page. Complete the mapping process. Remap_pfn_range can not map to regular memory, only the reserved memory and physical memory can be mapped.

2. Here, to distinguish a few addresses, one is the physical address, this is very simple, is the physical memory of the actual address. The second is the kernel virtual address, which is the address that the kernel can access directly, such as the address returned by kernel functions such as kmalloc,vmalloc, and the Kmalloc return address is also called the kernel logical address. The kernel virtual address has only one offset from the actual physical address. The third is the process virtual address, which is in user space. Instead of mapping physical addresses to kernel virtual addresses, the MMAP function maps physical addresses to process virtual addresses. The Ioremap function is to map the physical address to the kernel virtual address.

3. The user-space process calls the MMAP function, first doing the necessary processing, generating the VMA structure, and then invoking the Remap_pfn_range function to create the page table. The mmap function of the user space returns the first address mapped to the process address space. So the mmap function is different from the Remap_pfn_range function, the former only generates MMAP, and the page table is created by the Remap_pfn_range function.

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.