摘要:
相对于上一篇測试程序CMA连续物理内存用户空间映射---(一)
添加功能:
1、分配和映射统一放在IOCTL,一次完毕,能够连续多次分配并映射到用户空间,提高操作性;
2、驱动添加链表,使分配的多块内存在链表中管理,方便加入删除;
3、添加内存释放和解除映射;
4、使用rmmod删除驱动模块时。将释放全部内存。
映射流程:
1、用户通过IOCTL分配大小传给驱动ioctl------------------------------------->
2、驱动依据用户是否使用 writebuffer。来使用dma_alloc_writecombine或者dma_alloc_coherent。物理内存---------------------------->
3、通过vm_mmap,在用户空间找一块空暇空间来供映射使用-------------------------------->
vm_mmap在大于linux3.7内核版本号中才干使用。在老内核中能够使用sys_mmap
參考mmap的call stack
[ 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将会调用驱动中的mmap接口函数
在mmap中通过remap_pfn_range实现物理内存到用户空间的映射.;
5、讲映射好的用户空间及内核空间虚拟内核和物理内存保存到链表中;
6、删除操作时,查询链表,解除映射,释放内存。从链表移除;
7、驱动模块释放时,释放全部内存;
源代码:
驱动:
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 1 enum 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 ",__func__, memory_block->name); printk("%s:CMA id:%d ",__func__, memory_block->id); printk("%s:Is usebuf:%d ",__func__, memory_block->is_use_buffer); printk("%s:PHY Base:0x%08lx ",__func__, memory_block->phy_base); printk("%s:KER Base:0x%08x ",__func__, (unsigned int)(memory_block->kernel_base)); printk("%s:USR Base:0x%08lx ",__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 ", ret); return -1; } if(cma_info_temp.name[0] == '