Memory Programming Interface

Source: Internet
Author: User

In Linux, there is usually a 32-bit (4 GB) address space, and the 4 GB memory space of a process is divided into two parts: user space and kernel space, the user space address is generally 0 ~ 3 GB (that is, PAGE_OFFSET, usually equal to 0xc0000000), the remaining 3 ~ 4 GB is the kernel space. The process and the kernel do not use 4 GB of space separately. The advantage is that the process does not need to switch the page table when it enters the kernel, reducing the consumption of the incoming and outgoing kernel. Kernel space ranges from low address to high address, including physical memory ing area, vmalloc virtual memory allocation area, high-end memory ing area, and reserved area. The user space of each process is completely independent, and the user process has different page tables. The kernel space is mapped by the kernel, which does not change with the process and is fixed. The kernel space address has its own page table, and the kernel virtual address space is independent of other user processes.
I. Data Structure
After a user process is created, it can access the virtual address of the entire user space. This space is a linear unsegmented address range, in the kernel, the process address space and all related information are stored in mm_struct, which appears in the process control structure task_struct. The continuous valid address range used by each process is called the memory zone. A memory zone is represented by the vm_area_struct descriptor, and each memory zone descriptor describes a continuous address range. Different memory zones have different protection schemes and features. For example, some parts of a program code segment are marked as read-only, while others are marked as Writable or executable.
1. mm_struct
[Cpp]
Struct mm_struct {
Struct vm_area_struct * mmap;/* list of VMAs */
Struct rb_root mm_rb;
Struct vm_area_struct * mmap_cache;/* last find_vma result */
...
Pgd_t * pgd;
Atomic_t mm_users;/* How many users with user space? */
Atomic_t mm_count;/* How many references to "struct mm_struct" (users count as 1 )*/
Int map_count;/* number of VMAs */
Struct rw_semaphore mmap_sem;
Spinlock_t page_table_lock;/* Protects page tables and some counters */
 
Struct list_head mmlist;/* List of maybe swapped mm's. These are globally strung
* Together off init_mm.mmlist, and are protected
* By mmlist_lock
*/
...
Unsigned long total_vm, locked_vm, shared_vm, exec_vm;
Unsigned long stack_vm, reserved_vm, def_flags, nr_ptes;
Unsigned long start_code, end_code, start_data, end_data; // the start and end addresses of the Process Code segment and data segment in the memory.
Unsigned long start_brk, brk, start_stack; // process heap start and end addresses, and stack Start Addresses
Unsigned long arg_start, arg_end, env_start, env_end; // parameter, start and end address of the stage
...
};
The mmap parameter indicates the header Node Address of the linked list consisting of all memory area descriptors of the process. mm_struct accesses the linked list through mmap, And the vm_next pointer in vm_area_struct links each memory area; mmap_cache points to the memory zone descriptor pointer accessed by the process for improved access efficiency. mm_users stores the number of processes that access the address space of the process. mm_count is the usage statistics of mm_struct, when the value is 0, it indicates that no process is used. map_count indicates the number of memory partitions in the process address space, that is, the number of vm_area_struct descriptors.
2. vm_area_struct
[Cpp]
Struct vm_area_struct {
Struct mm_struct * vm_mm;/* The address space we belong .*/
Unsigned long vm_start;/* Our start address within vm_mm .*/
Unsigned long vm_end;/* The first byte after our end address
Within vm_mm .*/
 
/* Linked list of VM areas per task, sorted by address */
Struct vm_area_struct * vm_next;
 
Pgprot_t vm_page_prot;/* Access permissions of this VMA .*/
Unsigned long vm_flags;/* Flags, see mm. h .*/
 
Struct rb_node vm_rb;
...
/* Function pointers to deal with this struct .*/
Const struct vm_operations_struct * vm_ops;
...
};
Vm_mm points to the process address space of the memory area. vm_start and vm_end indicate the start and end addresses of the virtual memory area. Considering performance problems, the starting address of the memory area must be an integer multiple of the page size. vm_next points to the next virtual memory area of the process. vm_ops is used to operate on a specific virtual memory area, including opening, closing, and reflecting the memory area.
Ii. Programming Interface
The function for dynamically applying for memory in the user space is malloc, and the function for releasing the memory is free. The main functions involved in applying for memory in the kernel space include kmalloc, _ get_free_pages, and vmalloc. The memory applied for by kmalloc and _ get_free_pages is located in the physical memory ing area and is physically continuous. They have only one fixed offset from the real physical address, therefore, there is a simple conversion relationship. Vmalloc provides a continuous memory area in the virtual memory space. In fact, the physical memory in this continuous virtual space is not necessarily continuous, there is no simple Conversion Relationship Between the applied virtual memory and the physical memory.
1. kmalloc
[Cpp]
/**
* Kmalloc-allocate a specified memory size
* @ Size: memory size
* @ Flags: indicates the allocation flag. Possible values include GFP_ATOMIC and GFP_KERNEL.
*
* Note: A GFP_KERNEL may cause sleep.
*/
 
Void * kmalloc (size_t size, int flags );
The memory allocated with kmalloc should be released with kfree.
2. mmap
[Cpp]
/**
* Mmap-maps physical addresses to user Spaces
* @ Addr: Specifies the starting address for the file to be mapped to the process space. Generally, this parameter is set to NULL. In this case, the task of selecting the starting address is left to the kernel for completion.
* @ Len: number of bytes mapped to the user space
* @ Prot: Specifies the access permission of the ing space. The following values can be obtained:
* PROT_READ (readable), PROT_WRITE (writable), PROT_EXEC (executable), PROT_NONE (inaccessible)
* @ Flags: this parameter is specified by the following common values: MAP_SHARED, MAP_PRIVATE, MAP_FIXED, and MAP_ANON.
* @ Fd: the descriptor of the file mapped to the user space, which is generally returned by open ().
* At the same time, fd can be specified as-1. In this case, MAP_ANON must be specified in the flags parameter, indicating that anonymous ing is performed.
* @ Offset: The offset Value of the mapped memory area in the file.
*/
 
Void * mmap (void * addr, size_t len, int prot, int flags, int fd, off_t offset );
This function maps the file descriptor fd to the virtual memory area of the [offset, offset + len] physical memory of the specified file to the user space of the calling process [addr, addr + len, it is usually used for Memory sharing or user space program control of hardware devices. The return value of the function is the address mapped to the user space by the last file. The process can directly operate on the address. When you call mmap, the kernel will find the file_operations of the corresponding device driver or file system based on fd. For example, in camera, it is v4l2_file_operations, and then call the mmap operation defined in it, A common process is as follows:
[Cpp]
Static int xxx_mmap (struct file * file, struct vm_area_struct * vma)
{
Int ret;
Unsigned long size = vma-> vm_end-vma-> vm_start; // calculate the memory size to be mapped.
Unsigned long offset = vma-> vm_pgoff <PAGE_SHIFT; // calculates the offset Value of the ing memory area.
Struct xxx_info * info = file-> private_data;
 
Mutex_lock (& info-> lock );
 
If (size> info-> gbuffers * info-> gbufsize-offset) {// if the region to be mapped is too large, an error value is returned.
Mutex_unlock (& info-> lock );
Return-EINVAL;
}
 
If (! Info-> mmap_start_base) {// check whether the physical address is valid
Mutex_unlock (& info-> lock );
Return-EIO;
}
 
Vma-> vm_page_prot = pgprot_noncached (vma-> vm_page_prot); // Add the nocache attribute to the ing area
Ret = remap_pfn_range (vma, vma-> vm_start, // call the remap_pfn_range function to create a page table
(Uint32_t) (info-> mmap_start_base + offset)> PAGE_SHIFT,
Size, vma-> vm_page_prot );
If (ret ){
Mutex_unlock (& info-> lock );
Return-EAGAIN;
}
 
Mutex_unlock (& info-> lock );
Return 0;
}
In the driver, we can use the remap_pfn_range ing memory to map the reserved pages and device I/O memory. In addition, to map the memory applied by kmalloc to a user space, you can use mem_map_reserve to set it to a reserved page. The sample code is as follows:
[Cpp]
Buffer = kmalloc (size, GFP_KERNEL); // request the buffer
 
For (page = pai_to_page (buffer); page <pai_to_page (buffer + size); page ++)
Mem_map_reserve (page); // set the page to a reserved page
Let's take a look at the remap_pfn_range description:
[Cpp]
/**
* Remap_pfn_range- ing physical addresses to user Spaces
* @ Vma: indicates the virtual memory area pointer, which is automatically filled by the kernel according to user requests. The function maps the physical address area to the virtual memory area.
* @ Addr: Starting address of the virtual memory area. The function will be addr ~ Addr + size: Create a page table in the virtual address area
* @ Pfn: The page frame number mapped to the physical address, that is, the physical address is shifted to PAGE_SHIFT (12 bits, generally PAGE_SIZE is 4 kb)
* @ Size: size of the memory area mapped
* @ Prot: Protection attribute of the page table
*
* Note: The caller must hold the mm semaphore.
*/
 
Int remap_pfn_range (struct vm_area_struct * vma, unsigned long addr,
Unsigned long pfn, unsigned long size, pgprot_t prot );
The execution sequence of mmap is summarized as follows:
(1) create a virtual memory zone in the user process-vma
(2) The driver calls ramap_pfn_range to construct a page table for the mapped physical memory area.
(3) Allocate the page table to the virtual memory zone-vma
3. ioremap_nocache
[Cpp]
/**
* Ioremap_nocache-maps physical addresses to kernel space
* @ Phys_addr: start value of the physical address
* @ Size: the size of the space to be mapped.
*
* Note: It must be released by iounmap ().
*/
 
Void _ iomem * ioremap_nocache (unsigned long phys_addr, unsigned long size)
{
Return _ ioremap (phys_addr | MEM_NON_CACHEABLE, size, 0 );
}
After applying a continuous physical memory in the driver, you usually need to map the physical address to the virtual address space of the kernel, then, you can directly use the virtual address in the driver code to access the physical memory. The usage is as follows:
[Cpp]
Vbase = ioremap_nocache (unsigned long) phys_start_base, cam_total_buf_size );
 

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.