CMA continuous physical memory user space ing --- (2)

Source: Internet
Author: User

Abstract:

User space ing relative to the CMA continuous physical memory of the previous test program --- (1)

Added features:

1. Allocation and ing are centrally placed in ioctl, which can be allocated and mapped to user space multiple times in a row to improve operability;

2. The drive adds a linked list, so that the allocated multiple blocks are managed in the linked list to facilitate addition and deletion;

3. increase memory release and un ing;

4. When you use rmmod to delete the driver module, all memory will be released;

Ing process:

1. the user allocates the size via IOCTL to the driver IOCTL --------------------------------------->

2. The driver uses dma_alloc_writecombine or dma_alloc_coherent based on whether the user uses writebuffer, and the physical memory ------------------------>

3. Use vm_mmap to find a free space in the user space for ing -------------------------------->

Vm_mmap can be used in kernel Versions later than linux3.7, and sys_mmap can be used in the old kernel.

Refer to call stack of MMAP

[  409.762850] [<c00184c4>] (unwind_backtrace+0x0/0xf8) from [<bf000020>] (cmamem_mmap+0x20/0xd0 [cma_mem])[  409.774141] [<bf000020>] (cmamem_mmap+0x20/0xd0 [cma_mem]) from [<c0095ab8>] (mmap_region+0x310/0x540)[  409.774771] [<c0095ab8>] (mmap_region+0x310/0x540) from [<c0095f80>] (do_mmap_pgoff+0x298/0x330)[  409.784230] [<c0095f80>] (do_mmap_pgoff+0x298/0x330) from [<c00886d0>] (vm_mmap_pgoff+0x64/0x94)[  409.792291] [<c00886d0>] (vm_mmap_pgoff+0x64/0x94) from [<c00947a8>] (sys_mmap_pgoff+0x54/0xa8)[  409.800962] [<c00947a8>] (sys_mmap_pgoff+0x54/0xa8) from [<c0013940>] (ret_fast_syscall+0x0/0x30)

4. vm_mmap will call the MMAP interface function in the driver.

Map physical memory to user space through remap_pfn_range in MMAP .;

5. The ing user space, kernel space, virtual kernel, and physical memory are stored in the linked list;

6. During the delete operation, query the linked list, unmap, release the memory, and remove from the linked list;

7. All memory is released when the driver module is released;

Source code:

Driver:

Cma_mem.c

#include <linux/miscdevice.h>#include <linux/platform_device.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/mm.h>#include <linux/list.h>#include <linux/mutex.h>#include <linux/debugfs.h>#include <linux/mempolicy.h>#include <linux/sched.h>#include <linux/module.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/cacheflush.h>#include <linux/dma-mapping.h>#include <linux/export.h>#include <linux/syscalls.h>#include <linux/mman.h>#include "cma_mem.h"#define DEVICE_NAME "cma_mem" #define MEM_DEBUG 1enum cma_status{UNKNOW_STATUS = 0,HAVE_ALLOCED = 1,HAVE_MMAPED =2,};struct cmamem_dev {unsigned int count;struct miscdevice dev;struct mutex cmamem_lock;};struct cmamem_block {char name[10];char is_use_buffer;char is_free;int id;unsigned long offset;unsigned long len;unsigned long phy_base;unsigned long mem_base;void *kernel_base;struct list_head memqueue_list;};struct current_status{int status;int id_count;dma_addr_t phy_base;};static struct current_status cmamem_status;static struct cmamem_dev cmamem_dev;static struct cmamem_block *cmamem_block_head;static int mem_block_count = 0;static void dump_mem(struct cmamem_block *memory_block){printk("%s:CMA name:%s\n",__func__,  memory_block->name);printk("%s:CMA id:%d\n",__func__,  memory_block->id);printk("%s:Is usebuf:%d\n",__func__,  memory_block->is_use_buffer);printk("%s:PHY Base:0x%08lx\n",__func__,  memory_block->phy_base);printk("%s:KER Base:0x%08x\n",__func__,  (unsigned int)(memory_block->kernel_base));printk("%s:USR Base:0x%08lx\n",__func__,  memory_block->mem_base);}static long cmamem_alloc(struct file *file, unsigned long arg){struct cmamem_block *memory_block;struct mem_block cma_info_temp;int size;int ret;if ((ret = copy_from_user(&cma_info_temp, (void __user *)arg,sizeof(struct mem_block)))){printk(KERN_ERR"cmamem_alloc:copy_from_user error:%d\n", ret);return -1;}if(cma_info_temp.name[0] == '\0'){printk(KERN_ERR "%s, no set mem name, please set\n", __func__);return -1;}if(cma_info_temp.len){size = PAGE_ALIGN(cma_info_temp.len);cma_info_temp.len = size;#ifdefMEM_DEBUG//printk(KERN_INFO "%s len:%ld, is_use_buffer:%d\n", __func__, cma_info_temp.len, cma_info_temp.is_use_buffer);#endifif(cma_info_temp.is_use_buffer)cma_info_temp.kernel_base = dma_alloc_writecombine(NULL, size, (dma_addr_t *)(&(cma_info_temp.phy_base)), GFP_KERNEL);elsecma_info_temp.kernel_base = dma_alloc_coherent(NULL, size, (dma_addr_t *)(&(cma_info_temp.phy_base)), GFP_KERNEL);if (!cma_info_temp.phy_base){printk(KERN_ERR "dma alloc fail:%d!\n", __LINE__);return -ENOMEM;}cma_info_temp.id = ++mem_block_count;cmamem_status.phy_base = cma_info_temp.phy_base;cmamem_status.id_count =  cma_info_temp.id;cmamem_status.status = HAVE_ALLOCED;cma_info_temp.mem_base = vm_mmap(file, 0, size, PROT_READ | PROT_WRITE, MAP_SHARED, 0);if(cma_info_temp.mem_base < 0){printk(KERN_ERR "do_mmap fail:%d!\n", __LINE__);cma_info_temp.id = --mem_block_count;return -ENOMEM;}printk(KERN_INFO "cma_info_temp.mem_base:0x%lx\n", cma_info_temp.mem_base);//mem_block_count ++;}else{printk(KERN_ERR"cmamem_alloc: the len is NULL\n");return -1;}if(copy_to_user((void __user *)arg, (void *)(&cma_info_temp), sizeof(struct mem_block)))return -EFAULT;/* setup the memory block */memory_block = (struct cmamem_block *)kmalloc(sizeof(struct cmamem_block), GFP_KERNEL);if(memory_block == NULL){printk(KERN_ERR "%s error line:%d\n", __func__, __LINE__);mem_block_count --;return -1;}if(cma_info_temp.name[0] != '\0')memcpy(memory_block->name, cma_info_temp.name, 10);memory_block->id=cma_info_temp.id;memory_block->is_free=0;memory_block->is_use_buffer=cma_info_temp.is_use_buffer;memory_block->mem_base =cma_info_temp.mem_base;memory_block->kernel_base =cma_info_temp.kernel_base;memory_block->phy_base =cma_info_temp.phy_base;memory_block->len=cma_info_temp.len;#ifdefMEM_DEBUGdump_mem(memory_block);#endif#ifdef CMA_TESTint i;for(i = 0; i < 10; i++)((char *)(cma_info_temp.kernel_base))[i] = (cma_info_temp.id * i);#endif/* add to memory block queue */list_add_tail(&memory_block->memqueue_list, &cmamem_block_head->memqueue_list);return 0;}static int cmamem_free(struct file *file, unsigned long arg){struct cmamem_block *memory_block;struct mem_block cma_info_temp;int ret;if ((ret = copy_from_user(&cma_info_temp, (void __user *)arg,sizeof(struct mem_block)))){printk(KERN_ERR"cmamem_alloc:copy_from_user error:%d\n", ret);return -1;}printk(KERN_INFO "will delete the mem name:%s\n", cma_info_temp.name);list_for_each_entry(memory_block, &cmamem_block_head->memqueue_list, memqueue_list){if(memory_block){//if(memory_block->id == cma_info_temp.id || !strcmp(cma_info_temp.name, memory_block->name)){if(!strcmp(cma_info_temp.name, memory_block->name)){if(memory_block->is_free == 0){printk(KERN_INFO "delete the mem id:%d, name:%s\n", cma_info_temp.id, cma_info_temp.name);vm_munmap(memory_block->mem_base, memory_block->len);if(memory_block->is_use_buffer)dma_free_coherent(NULL,memory_block->len, memory_block->kernel_base, memory_block->phy_base);elsedma_free_writecombine(NULL, memory_block->len, memory_block->kernel_base, memory_block->phy_base);memory_block->is_free = 1;list_del(&memory_block->memqueue_list);        break;}}}}  return 0;}static int cmamem_freeall(void){struct cmamem_block *memory_block;printk(KERN_INFO "will delete all cma mem\n");list_for_each_entry(memory_block, &cmamem_block_head->memqueue_list, memqueue_list){if(memory_block && memory_block->id > 0){if(memory_block->is_free == 0){printk(KERN_INFO "delete the mem id:%d, name:%s\n", memory_block->id, memory_block->name);if(memory_block->is_use_buffer)dma_free_coherent(NULL, memory_block->len, memory_block->kernel_base, memory_block->phy_base);elsedma_free_writecombine(NULL, memory_block->len, memory_block->kernel_base, memory_block->phy_base);memory_block->is_free = 1;}}}  return 0;}static long cmamem_ioctl(struct file *file, unsigned int cmd, unsigned long arg){int ret = 0;switch(cmd){case CMEM_ALLOCATE:{printk(KERN_ERR"cmamem_ioctl:CMEM_ALLOCATE\n");mutex_lock(&cmamem_dev.cmamem_lock);cmamem_alloc(file, arg);if(ret < 0)goto alloc_err;mutex_unlock(&cmamem_dev.cmamem_lock);break;}case CMEM_UNMAP:{printk(KERN_ERR"cmamem_ioctl:CMEM_UNMAP\n");mutex_lock(&cmamem_dev.cmamem_lock);ret = cmamem_free(file, arg);if(ret < 0)goto free_err;mutex_unlock(&cmamem_dev.cmamem_lock);break;}default:{printk(KERN_INFO "cma mem not support command\n");break;}}return 0;alloc_err:mutex_unlock(&cmamem_dev.cmamem_lock);printk(KERN_ERR "%s alloc error\n", __func__);return ret;free_err:mutex_unlock(&cmamem_dev.cmamem_lock);printk(KERN_ERR "%s free error\n", __func__);return ret;}static int cmamem_mmap(struct file *filp, struct vm_area_struct *vma){unsigned long start = vma->vm_start;unsigned long size = vma->vm_end - vma->vm_start;unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;unsigned long page, pos;//if(size > MMAP_MEM_SIZE)//return -EINVAL; if(cmamem_status.status != HAVE_ALLOCED){printk(KERN_ERR"%s, you should allocted memory firstly\n", __func__);return -EINVAL; }//printk( "cmamem_mmap:vma:start=0x%08x offset=0x%08x\n", (unsigned int)start, (unsigned int)offset );pos = (unsigned long)cmamem_status.phy_base + offset;page = pos >> PAGE_SHIFT ;//printk( "cmamem_status.phy_base:0x%08x\n", (unsigned int)cmamem_status.phy_base);if( remap_pfn_range( vma, start, page, size, PAGE_SHARED )) {return -EAGAIN;}else{//printk( "remap_pfn_range %u\n success\n", (unsigned int)page );}vma->vm_flags &= ~VM_IO; vma->vm_flags |=  (VM_DONTEXPAND | VM_DONTDUMP);cmamem_status.status = HAVE_MMAPED;return 0;}static struct file_operations dev_fops = {      .owner          = THIS_MODULE,      .unlocked_ioctl = cmamem_ioctl,  .mmap = cmamem_mmap,};static int __init cmamem_init(void){printk(KERN_INFO "%s\n", __func__);mutex_init(&cmamem_dev.cmamem_lock);//NIT_LIST_HEAD(&cmamem_dev.info_list);cmamem_dev.count = 0;cmamem_dev.dev.name = DEVICE_NAME;cmamem_dev.dev.minor = MISC_DYNAMIC_MINOR;cmamem_dev.dev.fops = &dev_fops;cmamem_block_head = (struct cmamem_block *)kmalloc(sizeof(struct cmamem_block), GFP_KERNEL);cmamem_block_head->id = -1;mem_block_count = 0;INIT_LIST_HEAD(&cmamem_block_head->memqueue_list);/* cmamem_status.status = UNKNOW_STATUS;cmamem_status.id_count = -1;cmamem_status.phy_base = 0;*/return misc_register(&cmamem_dev.dev);}static void __exit cmamem_exit(void)  {      printk(KERN_ERR"%s\n", __func__);cmamem_freeall();misc_deregister(&cmamem_dev.dev);  } module_init(cmamem_init);module_exit(cmamem_exit);MODULE_LICENSE("GPL");

Cma_mem.h

#ifndef _CMA_MEM_H_#define _CMA_MEM_H_#define CMEM_IOCTL_MAGIC 'm'#define CMEM_GET_PHYS_IOW(CMEM_IOCTL_MAGIC, 1, unsigned int)#define CMEM_MAP_IOW(CMEM_IOCTL_MAGIC, 2, unsigned int)#define CMEM_GET_SIZE_IOW(CMEM_IOCTL_MAGIC, 3, unsigned int)#define CMEM_UNMAP_IOW(CMEM_IOCTL_MAGIC, 4, unsigned int)#define CMEM_ALLOCATE_IOW(CMEM_IOCTL_MAGIC, 5, unsigned int)#define CMEM_CONNECT_IOW(CMEM_IOCTL_MAGIC, 6, unsigned int)#define CMEM_GET_TOTAL_SIZE_IOW(CMEM_IOCTL_MAGIC, 7, unsigned int)#define CMEM_CACHE_FLUSH_IOW(CMEM_IOCTL_MAGIC, 8, unsigned int)struct mem_block {char name[10];char is_use_buffer;int id;unsigned long offset;unsigned long len;unsigned long phy_base;unsigned long mem_base;void *kernel_base;};#endif

User Testing Program:

# Include <stdio. h> # include <stdarg. h> # include <string. h> # include <errno. h> # include <stdlib. h> # include <sys/types. h> # include <sys/STAT. h> # include <fcntl. h> # include <time. h> # include <sys/Mman. h> # include <assert. h> # include <Linux/videodev2.h> # include <Linux/FB. h> # include <pthread. h> # include <poll. h> # include <semaphore. h> # define cmem_ioctl_magic 'M' # define cmem_get_phys_iow (cmem_ioctl_magic, 1, unsigne D INT) # define cmem_map_iow (cmem_ioctl_magic, 2, unsigned INT) # define evaluate (cmem_ioctl_magic, 3, unsigned INT) # define evaluate (cmem_ioctl_magic, 4, unsigned INT) # define evaluate (Measures, 5, unsigned INT) # define cmem_connect_iow (cmem_ioctl_magic, 6, unsigned INT) # define evaluate (cmem_ioctl_magic, 7, unsigned INT) # define evaluate Tl_magic, 8, unsigned INT) struct cmamem_info {char name [10]; char is_use_buffer; int ID; unsigned long offset; unsigned long Len; unsigned long phy_base; unsigned long mem_base; void * kernel_base;}; struct mem_block {char name [10]; char is_use_buffer; int ID; unsigned long offset; unsigned long Len; unsigned long phy_base; unsigned long mem_base; void * kernel_base;}; int main () {int cmem_fd; void * cmem_base; unsigne D int size; struct mem_block region; int I, j; char STR [10]; memset (& region, 0x00, sizeof (struct mem_block )); cmem_fd = open ("/dev/cma_mem", o_rdwr, 0); // open the device. To operate the hardware engine, printf ("cmem_fd: % d \ n ", cmem_fd); j = 0; If (cmem_fd> = 0) while (j <= 2) {J ++; sprintf (STR, "mem % d", J ); memset (& region, 0x00, sizeof (struct mem_block); region. len = 800*480*4; region. is_use_buffer = 1; memcpy (region. name, STR, STR Len (STR); printf ("sizeof (struct mem_block): % d \ n", sizeof (struct mem_block); printf ("region. mem_base: 0x % 08x \ n ", region. mem_base); If (IOCTL (cmem_fd, cmem_allocate, & Region) <0) // obtain all space {perror ("pmem_get_total_size failed \ n"); Return-1 ;} // size = region. len; printf ("region. len: 0x % 08x offset: 0x % 08x \ n ", region. len, region. offset); printf ("region. mem_base: 0x % 08x \ n ", region. mem_base); for (I = 0; I <10; I + +) Printf ("% d \ n", (char *) (region. mem_base) [I]);/* cmem_base = MMAP (0, size, prot_read | prot_write, map_shared, cmem_fd, 0); // MMAP operation if (cmem_base = map_failed) {cmem_base = 0; close (cmem_fd); cmem_fd =-1; perror ("MMAP pmem error! \ N ") ;}for (I = 0; I <10; I ++) (unsigned int *) cmem_base) [I] = I; printf (" pmem_base: 0x % 08x \ n ", cmem_base); for (I = 0; I <10; I ++) printf (" % d \ n ", (unsigned int *) cmem_base) [I]); */printf ("\ n ********************* \ n ");} printf ("free the mem \ n"); getchar (); j = 0;/* While (j <= 2) // release test {J ++; sprintf (STR, "mem % d", J); memset (& region, 0x00, sizeof (struct mem_block); region. id = J; region. is_use_buffer = 1; memcpy (region. name, STR, strlen (STR); printf ("user will DEL: % s, id = % d \ n", STR, region. ID); If (IOCTL (cmem_fd, cmem_unmap, & Region) <0) // obtain all space {perror ("pmem_get_total_size failed \ n"); Return-1 ;}} getchar (); */close (cmem_fd); Return 0 ;}




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.