“DevMem note”的版本间的差异
来自个人维基
free6d1823(讨论 | 贡献) |
free6d1823(讨论 | 贡献) |
||
第1行: | 第1行: | ||
+ | <source lang="awk"> | ||
+ | devmem ADDRESS [WIDTH [VALUE]] | ||
+ | Read/write from physical address | ||
+ | |||
+ | ADDRESS Address to act upon | ||
+ | WIDTH Width (8/16/...) | ||
+ | VALUE Data to be written | ||
+ | |||
+ | </source> | ||
<source lang="c"> | <source lang="c"> | ||
#include <sys/mman.h> | #include <sys/mman.h> | ||
第23行: | 第32行: | ||
|} | |} | ||
+ | |||
+ | /dev/mem mmap operator: | ||
+ | <source lang="c"> | ||
+ | static int mmap_mem(struct file *file, struct vm_area_struct *vma) | ||
+ | { | ||
+ | size_t size = vma->vm_end - vma->vm_start; | ||
+ | phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT; | ||
+ | |||
+ | /* It's illegal to wrap around the end of the physical address space. */ | ||
+ | if (offset + (phys_addr_t)size - 1 < offset) | ||
+ | return -EINVAL; | ||
+ | |||
+ | if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))return -EINVAL; | ||
+ | |||
+ | if (!private_mapping_ok(vma)) | ||
+ | return -ENOSYS; | ||
+ | |||
+ | if (!range_is_allowed(vma->vm_pgoff, size)) | ||
+ | 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); | ||
+ | |||
+ | vma->vm_ops = &mmap_mem_ops; | ||
+ | |||
+ | /* Remap-pfn-range will mark the range VM_IO */ | ||
+ | if (remap_pfn_range(vma,---------------------------------------------将内核中vma->vm_pgoff对应的size个页面,映射到vma区域,返回的虚拟空间起始地址是vma->vm_start。 | ||
+ | vma->vm_start, | ||
+ | vma->vm_pgoff, | ||
+ | size, | ||
+ | vma->vm_page_prot)) { | ||
+ | return -EAGAIN; | ||
+ | } | ||
+ | return 0; | ||
+ | } | ||
+ | </source> | ||
vm_area_struct结构体 | vm_area_struct结构体 |
2019年11月5日 (二) 15:34的版本
devmem ADDRESS [WIDTH [VALUE]] Read/write from physical address ADDRESS Address to act upon WIDTH Width (8/16/...) VALUE Data to be written
#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);
详细参数如下:
参数 | 详细说明 |
---|---|
addr | 需要映射的虚拟内存地址;如果为NULL,系统会自动选定。映射成功后返回该地址 |
length | 需要映射多大的数据量 |
prot | 描述映射区域内存保护方式,包括:PROT_EXEC、PROT_READ、PROT_WRITE、PROT_NONE. |
flags | 描述映射区域的特性,比如是否对其他进程共享,是否建立匿名映射,是否创建私有的cow. |
fd | 要映射到内存中的文件描述符 |
offset | 文件映射的偏移量 |
/dev/mem mmap operator:
static int mmap_mem(struct file *file, struct vm_area_struct *vma) { size_t size = vma->vm_end - vma->vm_start; phys_addr_t offset = (phys_addr_t)vma->vm_pgoff << PAGE_SHIFT; /* It's illegal to wrap around the end of the physical address space. */ if (offset + (phys_addr_t)size - 1 < offset) return -EINVAL; if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))return -EINVAL; if (!private_mapping_ok(vma)) return -ENOSYS; if (!range_is_allowed(vma->vm_pgoff, size)) 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); vma->vm_ops = &mmap_mem_ops; /* Remap-pfn-range will mark the range VM_IO */ if (remap_pfn_range(vma,---------------------------------------------将内核中vma->vm_pgoff对应的size个页面,映射到vma区域,返回的虚拟空间起始地址是vma->vm_start。 vma->vm_start, vma->vm_pgoff, size, vma->vm_page_prot)) { return -EAGAIN; } return 0; }
vm_area_struct结构体