21764
查看DevMem note的源代码
DevMem note
0
←
DevMem note
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
你被禁止执行你刚才请求的操作。
您可以查看并复制此页面的源代码:
1.devmem ADDRESS [WIDTH [VALUE]] <source lang="awk"> Read/write from physical address ADDRESS Address to act upon WIDTH Width (8/16/...) VALUE Data to be written </source> 2. devmem -> mmap <source lang="c"> int devmem_main(int argc UNUSED_PARAM, char **argv) { fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC)); //根据第三个参数确定是以只读形式打开,还是以读写形式打开。 mapped_size = page_size = getpagesize(); //4K bytes //if cross page, mapped_size *=2 map_base = mmap(NULL, mapped_size, // argv[3] ? (PROT_READ | PROT_WRITE) : PROT_READ, MAP_SHARED, fd, target & ~(off_t)(page_size - 1)//offset from 0x0000, page start address ); virt_addr = (char*)map_base + offset_in_page; } </source> 3. mmap <source lang="c"> #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); int munmap(void *addr, size_t length); </source> 详细参数如下: {| class="wikitable" style="width:100%" ! 参数 !! 详细说明 |- || addr || 需要映射的虚拟内存地址;如果为NULL,系统会自动选定。映射成功后返回该地址 |- || length || 需要映射多大的数据量. Mus be multiple of PAGE SIZE |- || prot||描述映射区域内存保护方式,包括:PROT_EXEC、PROT_READ、PROT_WRITE、PROT_NONE. |- ||flags||描述映射区域的特性,比如是否对其他进程共享,是否建立匿名映射,是否创建私有的cow. |- ||fd||要映射到内存中的文件描述符 |- ||offset||文件映射的偏移量 |} 4. mmap to /dev/mem Questions: offset 如何变成是物理地址? offset 跟vma->pgoff 的关系? vma->vm_start = addr ? 若 addr=NULL 如何给址? 系统调用的入口是entry_SYSCALL_64_fastpath,然后根据系统调用号在sys_call_table中找到对应的函数。 mmap()和munmap()对应的系统调用分别是SyS_mmap()和SyS_munmap() arch/arc/kernel/sys.c <source lang="c"> #define __SYSCALL(nr, call) [nr] = (call), void *sys_call_table[NR_syscalls] = { [0 ... NR_syscalls-1] = sys_ni_syscall, #include <asm/unistd.h> }; </source> include/uapiasm-generic/unistd.h <source lang="c"> </source> 5./dev/mem driver in inux-kernel/drivers/char/mem.c <source lang="c"> static int mmap_mem(struct file *file, struct vm_area_struct *vma) { size_t size = vma->vm_end - vma->vm_start; if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))//没检查 return -EINVAL; if (!private_mapping_ok(vma))//vm_flags must have VM_MAYSHARE return -ENOSYS; if (!range_is_allowed(vma->vm_pgoff, size))//check each page is allowed by calling devmem_is_allowed. ARCH_HAS_VALID_PHYS_ADDR_RANGE return -EPERM; if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size, &vma->vm_page_prot))//没检查 return -EINVAL; vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot);// 跟 cache 有关 先不管 vma->vm_ops = &mmap_mem_ops; /* Remap-pfn-range will mark the range VM_IO */ if (remap_pfn_range(vma, vma->vm_start, //Virt 开头位址 vma->vm_pgoff, size, vma->vm_page_prot)) { return -EAGAIN; } return 0; } </source> remap_pfn_range im ./mm/memory.c <source lang="c"> remap_pfn_range(vma, //user vma to map to addr, //target user address pfn, //physic address of kernel memory. Page #? size, //size of map area prot //page protection flags for this mapping ) { vma->vm_pgoff = pfn; vma->flags |= VM_IO|VM_PFNMAP|VM_DONTEXPAD |VM_DONTDUMP; mm = vma->mm; do { //for each page, update mm next = pgd_addr_end(addr, end) remap_pud_range(mm, pgd, addr, next, pfn+page#, prot) pgd++, addr = next, }while (addr != end) </source> Question: 如何确认offset 合理区域? length 可以有多大? Reference: https://blog.csdn.net/junllee/article/details/82146351
返回
DevMem note
。
导航菜单
个人工具
   
个人维基
注册
登录
名字空间
页面
变换
查看
阅读
查看源代码
统计
查看历史
操作
搜索
导航
首页
最近更改
随机页面
工具箱
所有页面
文件列表
特殊页面