我尝试了解Linux中使用mmap
将内核模式空间映射到用户模式空间的机制。
首先,我有一个可加载的内核模块(LKM),它为字符设备提供mmap
功能。然后,用户空间应用程序打开设备并调用mmap
LKM在内核模式空间(虚拟高地址)内的LKM堆上分配内存空间。在用户空间方面,数据指针指向虚拟低地址。
下图显示了我如何想象记忆的解剖结构。这是对的吗?
如果问题不明确,请告诉我,我会尝试添加更多细节。
编辑:图片是针对Gil Hamilton编辑的。黑色箭头现在指向物理地址。
答案 0 :(得分:0)
图纸缺少一些重要的基本假设。
内核不需要mmap()
来访问用户空间内存。如果用户进程具有内存,则它已根据定义映射到地址空间中。从这个意义上说,内存已经在用户和内核之间共享。
mmap()
在用户的虚拟地址空间中创建一个新区域,以便在以后访问时可以通过物理内存填充地址区域。实际的内存分配和修改页表条目是由内核完成的。
mmap()
仅对管理虚拟地址空间的用户一半有意义。内核 - 地址空间的一半管理完全不同。
此外,内核半部分由系统中的所有进程共享。每个进程都有其专用的虚拟地址空间,但页面表的编程方式使得内核半部的页表条目对所有进程设置完全相同。
同样,内核不mmap()
才能访问用户空间内存。 mmap()
是内核向用户提供的服务,用于修改用户虚拟地址空间中的当前映射。
首先,内核有一个专用的内核地址空间区域(作为其内核空间的一部分),它以连续的方式映射整个物理内存。 (在所有64位系统中都是如此。在32位系统中,内核必须重新映射才能实现此目的。)
其次,如果内核是通过系统调用或异常而非硬件中断进入的,那么你就拥有了有效的进程上下文,因此内核可以直接"取消引用"用户空间指针获取正确的值。
第三,如果内核想要在借用的上下文(例如中断处理程序)中执行时依赖于进程的用户空间指针,则内核可以通过遍历vm_area_struct
树来跟踪进程的虚拟地址。权限和遍历页面表以查找实际的物理页面框架。
答案 1 :(得分:0)
您可以通过当前迭代vma的“struct vm_area_struct”来检查内存区域。
如果您遍历pagetables并导出与用户空间无关的虚拟地址的映射物理地址,那么内存布局将更加清晰。
除了这个图中的微小修正, BSS不是段,而是嵌入到数据段的段,有关更多详细信息,请参阅ELF规范,链接描述文件