首页 > 编程知识 正文

内存映射是什么意思,oracle数据库默认端口

时间:2023-05-04 13:38:19 阅读:22712 作者:219

1.mmap摘要mmap可以将文件或其他对象映射到内存。 这意味着将一个文件或其他对象的地址空间映射到进程的地址空间,从而实现文件磁盘地址与进程虚拟地址之间的映射关系。 实现这种映射关系后,进程可以通过指针方式读写该内存,系统自动将映射文件读取到映射的内存空间中,同时将脏页写回相应的文件磁盘,从而实现reaary 相反,内核空间中对此区域的更改将直接反映在用户空间中,从而允许不同进程之间共享文件。 函数的原型如下:

void*mmap(void*addr,size_t length,int prot,int flags,int fd,off_t offset ); addr :映射虚拟地址空间的起始地址,如果为NULL,则由内核自动分配。 length (映射虚拟地址空间的大小,系统自动映射页面的整数倍、少于一页、每页。 端口:描述映射内存的权限,可以取PROT_EXEC、PROT_READ、PROT_WRITE、PROT_NONE。 flags :描述映射的区域更新后,映射同一区域的进程是否可见,以及是否写回文件。 经常使用选项。 MAP_SHARED :映射的区域更新后,它看起来像映射同一区域的进程。 MAP_PRIVATE :一种写入时专用复制映射方法,可以将脏页写回映射文件,写入时复制副本,然后用副本更新。 这些数据不会写回到文件中,映射的区域更新后,在同一区域中映射的过程中看不到这些数据。 软盘:要映射的文件句柄在映射之前必须打开对象以获得文件描述符。 offset :要映射的地址空间的偏移值。 返回值:映射成功,返回映射的虚拟地址空间的起始地址,如果失败(void * )-1 )。 关于长度length和偏移值offset的说明:

length :传递的长度大于0即可,也可以不是页面的整数倍。 但是,内核是以最大页面的整数倍进行映射的,不到一页,而是以一页进行映射。 测试表明,映射长度为100字节,如果读取的字节小于或等于4096字节,则会成功读取。 映射长度为4096字节,读取4000-4500之间的数据。 4000-4096之间的数据读取正常,超过4096时显示乱码,读取的字节数不正确。 指示内核已在整个页面上映射。

offset :测试结果表明,offset必须是页面的整数倍。 如果不是页面的整数倍,映射将失败,错误代码为22,显示无效参数。

2.mmap在内核上运行的过程mmap是在POSIX标准中定义的系统调用,内核调用的是call(obsolete(sys_old_mmap ) ),在相对较早的系统调用中Linux内核从版本2.3.31开始提供进行内存映射的私有系统调用mmap2。

两者差异很小,mmap在进入内核时将用户空间参数复制到内核空间,检查偏移值是否是页面的整数倍,否则返回错误并指示无效参数。 这与以前的测试结果匹配,之后执行的函数与mmap2匹配。 map和mmap2函数在内核中的执行流程如图1所示。 主要流程如下。

根据传入的软盘,找到与打开的文件对应的file结构。 从进程的虚拟地址空间分配虚拟地址范围检查如果分配的虚拟地址范围无法与现有虚拟内存区域合并,分配的内存区域将调用在特定设备上实现的mmap函数,其中/dev/mem设备

对于每个特定(虚拟)设备,在系统中注册操作函数的结构。 如果常见的open、write和read函数是美丽的母鸡,则mmap函数包含美丽的母鸡,设备必须实现mmap函数才能支持内存映射。

/dev/mem设备中登录的结构体如下图所示。

对于/dev/mem设备,APP应用层调用mmap系统调用,最终调用/dev/mem设备在内核中注册的mmap函数。 其执行过程如下图所示。 主要过程是检查映射的物理地址是否在支持的物理地址范围之外支持专用映射,并检查默认情况下CPU是否允许映射MMU (如果有) 此选项由CONFIG_STRICT_DEVMEM控制,如果已定义,则严格检查映射的地址,如果未定义,则不检查。 (CONFIG_STRICT_DEVMEM配置路径: kernel hacking-- [ ]如果选中了filteraccessemem检查选项,则映射的物理地址是设备的独占保留I/o映射通过后,将设置对页面的访问权限,并将内核中的物理地址映射到用户区域。

3 .内核中的mmap运行进程mem设备节点位于dev目录下,/dev/mem是物理地址空间的完整映像,可用于访问CPU的物理地址空间。 常用用法为open('/dev/mem ',O_RDWR ),它获取mem设备的文件描述符,并在mmap中映射物理内存。mem的驱动程序文件名为mem.c,内核源驱动程序/chem

4.mmap驱动程序源可以实现自己的mmap驱动程序,并映射想要映射的地址空间,除非使用/dev/mem设备。

# include Linux/misc设备. h

>#include <linux/delay.h>#include <linux/kthread.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/mm.h>#include <linux/fs.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/slab.h>#include <linux/errno.h>#include <linux/ioctl.h>#include <linux/cdev.h>#include <linux/string.h>#include <linux/list.h>#include <linux/pci.h>#include <linux/gpio.h>#include <linux/interrupt.h>#include <linux/time.h>#define DEVICE_NAME1 "mem_mmap1"#define DEVICE_NAME2 "mem_mmap2"static const char drv_name1[] = "mem_mmap-program1";static const char drv_name2[] = "mem_mmap-program2";#define MEM_MMAP_ADDR1 (0x90000000) /* 映射内存的物理基地址 */#define MEM_MMAP_ADDR2 (MEM_MMAP_ADDR1 + MEM_MMAP_LEN)#define MEM_MMAP_LEN (0x4000000) /* 映射内存的最大长度 *///#define DBG_INFOstatic int mem_mmap_open1(struct inode *inode, struct file *file) {#ifdef INFO pr_info("mem_mmap_open1: memory mmap module open okn");#endif return 0; } static int mem_mmap1(struct file *filp, struct vm_area_struct *vma) { unsigned long page; // 偏移地址必须按PAGE_SIZE对齐,vm_pgoff为偏移的PAGE数量 // 右移PAGE_SHIFT,表示偏移的字节数 unsigned long offset = (unsigned long)vma->vm_pgoff << PAGE_SHIFT; unsigned long start = (unsigned long)vma->vm_start; unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start); #ifdef INFO pr_info("mem_mmap1: vm_pgoff %lx, offset %lx, start %lx, " "end is %lx, size is %lxn", (unsigned long)vma->vm_pgoff, offset, start, vma->vm_end ,size);#endif if(size > MEM_MMAP_LEN) {#ifdef INFO pr_info("mem_mmap1: mmap size is too big, size %lx, max size %lxn", size, (unsigned long)MEM_MMAP_LEN);#endif return -ENXIO; } if(offset + size > MEM_MMAP_LEN) {#ifdef INFO pr_info("mem_mmap1: offset is too big, size %lx, offset %lx, max size %lxn", size, offset, (unsigned long)MEM_MMAP_LEN);#endif return -ENXIO; } /* 映射的起始物理地址 */ page = MEM_MMAP_ADDR1 + offset; vma->vm_flags |= VM_IO | VM_SHARED; // 关闭cache vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* mmap the request addr */ if(remap_pfn_range(vma, start, page >> PAGE_SHIFT, size, vma->vm_page_prot)) { pr_err("mem_mmap1: mem_mmap:mmap faildn"); return -EAGAIN; } #ifdef INFO pr_info("mem_mmap1: mmap okn");#endif return 0; } static struct file_operations dev_fops_mem_mmap1 = { .owner = THIS_MODULE, .open = mem_mmap_open1, .mmap = mem_mmap1, };static struct miscdevice misc_mem_mmap1 = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME1, .fops = &dev_fops_mem_mmap1,};static int mem_mmap_open2(struct inode *inode, struct file *file) { #ifdef INFO pr_info("mem_mmap_open2: memory mmap module open okn");#endif return 0; } static int mem_mmap2(struct file *filp, struct vm_area_struct *vma) { unsigned long page; // 偏移地址必须按PAGE_SIZE对齐,vm_pgoff为偏移的PAGE数量 // 右移PAGE_SHIFT,表示偏移的字节数 unsigned long offset = (unsigned long)vma->vm_pgoff << PAGE_SHIFT; unsigned long start = (unsigned long)vma->vm_start; unsigned long size = (unsigned long)(vma->vm_end - vma->vm_start); #ifdef INFO pr_info("mem_mmap2: vm_pgoff %lx, offset %lx, start %lx, " "end is %lx, size is %lxn", (unsigned long)vma->vm_pgoff, offset, start, vma->vm_end ,size);#endif if(size > MEM_MMAP_LEN) {#ifdef INFO pr_info("mem_mmap2: mmap size is too big, size %lx, max size %lxn", size, (unsigned long)MEM_MMAP_LEN);#endif return -ENXIO; } if(offset + size > MEM_MMAP_LEN) {#ifdef INFO pr_info("mem_mmap2: offset is too big, size %lx, offset %lx, max size %lxn", size, offset, (unsigned long)MEM_MMAP_LEN);#endif return -ENXIO; } /* 映射的起始物理地址 */ page = MEM_MMAP_ADDR2 + offset; vma->vm_flags |= VM_IO | VM_SHARED; // 关闭cache vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* mmap the request addr */ if(remap_pfn_range(vma, start, page >> PAGE_SHIFT, size, vma->vm_page_prot)) { pr_err("mem_mmap2: mem_mmap:mmap faildn"); return -EAGAIN; } #ifdef INFO pr_info("mem_mmap2: mmap okn");#endif return 0; } static struct file_operations dev_fops_mem_mmap2 = { .owner = THIS_MODULE, .open = mem_mmap_open2, .mmap = mem_mmap2, };static struct miscdevice misc_mem_mmap2 = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME2, .fops = &dev_fops_mem_mmap2,};static int __init mem_mmap_init(void){ int ret = 0; /*register misc device for sharemem*/ ret = misc_register(&misc_mem_mmap1); if (ret != 0) { pr_err("mem_mmap_init: misc_mem_mmap1 register error...n"); ret = -ENOENT; return ret; } ret = misc_register(&misc_mem_mmap2); if (ret != 0) { pr_err("mem_mmap_init: misc_mem_mmap2 register error...n"); ret = -ENOENT; misc_deregister(&misc_mem_mmap1); return ret; }#ifdef INFO pr_info("mem_mmap_init: mem_mmap_init okn" );#endif return ret; }static void __exit mem_mmap_exit(void){ misc_deregister(&misc_mem_mmap1); misc_deregister(&misc_mem_mmap2);}module_init(mem_mmap_init);module_exit(mem_mmap_exit);MODULE_DESCRIPTION("memory mmap module");MODULE_AUTHOR("liyang.plus@foxmail.com");MODULE_LICENSE("GPL");

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。