专栏首页皮振伟的专栏[linux][memory]内存映射技术分析

[linux][memory]内存映射技术分析

前言: KVM的设备虚拟化,除了前文《PIO技术分析》,还有另外一个核心概念---MMIO。原计划这里分析一下KVM的MMIO虚拟化。考虑到MMIO比PIO复杂很多,涉及更多的概念,作者打算先分析几篇基本的Linux的内存管理概念,再来分析MMIO。 作者大概想了一下,主要由这几篇构成: 1,虚拟内存管理和内存映射。 2,物理内存管理。 3,内存回收。 分析: 1,虚拟内存概念 x86的CPU有两种运行模式---real mode和protected mode。在real mode下,CPU访问的是物理地址,也就是说,比如说CPU访问的地址是0x1234,那么访问的物理内存的地址就是0x1234。在protected mode下,访问的虚拟内存,如果访问0x1234这个虚拟地址,那么可能物理上是0xabcde234;从虚拟地址到物理的转换,是通过MMU完成的。 使用虚拟内存后的好处是什么呢?作者认为做大的好处是可以做到进程隔离,也就是说,每个进程都可以有自己的地址空间,互相之间不干扰。当然,还有很多高级的内存特性,例如COW(copy on write)等。 2,进程的地址空间 查看一个进程的地址空间:cat /proc/PID/maps

如图,一个进程的地址空间有多个虚拟内存区域(VMA,virtual memory area)构成,每段VMA包括:起始地址和结束地址(例如例子中的十六进制00400000-004f4000);访问权限(rwx代表读、写、运行);最后那段例如/bin/bash,代表文件映射,如果是空的,则是匿名映射。 如果访问的内存,不在区间内(比如说访问NULL,0明显不在区间内),或者权限不对(比如写了没有w权限的地址),都会发生segmentation fault。 3,VMA管理 linux-4.0.4/include/linux/mm_types.h中定义了VMA的内核态数据结构:

这个数据非常非常非常重要!!!理解Linux内核的虚拟内存管理的关键。从注释中也可以看到,vm_start就是当前这个VMA的起始虚拟地址,vm_end是结束地址后的一个byte的地址,vm_page_prot是访问权限等。 vm_next和vm_prev可以把当前进程的所有的VMA链接起来,vm_rb是给红黑树使用的。同时用链表和红黑树把进程的VMA组织起来,好处在于:可以使用链表进行遍历,可以使用红黑树进行快速查找地址是不是在VMA中。

linux-4.0.4/mm/mmap.c中实现了brk、mmap、munmap、mremap系统调用。结合上面的数据结构,仔细阅读这几个系统调用的实现,大致可以看懂vma的申请、释放、合并、拆分管理。 4,物理内存 在shell中敲dmesg:

可以看到类似的log,BIOS通过e820数据结构告诉Linux物理内存的layout情况。可能你会觉得,为什么插入的一条8G的内存条,会变成这个样子呢?据一位懂BIOS的人和我说,BIOS中也可以配置一次,再做一次映射~ 5,内存映射 看上面例子中的虚拟地址空间,和物理地址范围,二者其实不是对应的。 如上文,CPU在进入了protected mode之后,就会使用虚拟内存了。linux会组织起来一个数据叫做page table(传说中的页表),把虚拟内存和物理内存之间的映射关系保存到page table中,再把page table的地址告诉MMU,MMU就可以在CPU访问虚拟地址的时候,自动转换到物理地址了。

大概转换关系如上图(选自https://en.wikipedia.org/wiki/Page_table)。 6,/dev/mem busybox提供了一个命令---devmem。可以通过devmem直接查看或者修改物理内存。作者在这里在唠叨一下,busybox的代码比较短小精悍,非常不错,值得阅读! devmem的主要是通过/dev/mem做映射实现的。/dev/mem的代码实现在linux-4.0.4/drivers/char/mem.c:

remap_pfn_range是关键函数:函数中实现了pud、pmd、pte的运算,并把物理内存的地址填入pte中。 仔细,完整的阅读remap_pfn_range函数,大概就了解内存映射了。 后记: 因为这里主要是给后面的MMIO做铺垫,所以在这里就没有详细介绍Linux的内存映射技术。当然,还是列举了几处关键代码,如果按照上述的过程,仔细阅读代码,并尝试printk一下,用用提到的命令,作者相信应该比较容易理解。 Good Luck~

本文分享自微信公众号 - AlwaysGeek(gh_d0972b1eeb60)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-02-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [linux][memory] 内存回收

    前言: 前文《内存映射技术分析》描述了虚拟内存的管理、内存映射;《物理内存管理》介绍了物理内存管理。 本篇介绍一下内存回收。内存回收应该是整个Linux的内存管...

    皮振伟
  • [Linux][mm]TLB shootdown和读取smaps对性能的影响 ​

    作者遇到了业务的一个性能抖动问题,在这里介绍一下它的原因和解决办法。 分析 1,page fault 在Linux上,进程分配到的内存是虚拟内存,经过内核...

    皮振伟
  • [linux][fuse]fuse技术分析以及遇到的问题

    前言: 简单看了一下glusterfs,使用单节点构造glusterfs环境,导出的路径是是本地SSD在分区上。用qemu挂载glusterfs上的卷,用FIO...

    皮振伟
  • jvm分析工具和查看命令

    与unix上的ps类似,用来显示本地的java进程,可以查看本地运行着几个java程序,并显示他们的进程号。

    java思维导图
  • Java 技术路线

    用户5240466
  • GC之jstack 原

        用jstack命令jstack -l 18261>./18261jstack.txt拉取线程信息,18261是进程ID,文件18261jstack.tx...

    克虏伯
  • 【译】编程不容易

    编程不是操作键盘快速敲打。编程不是牢记键盘的快捷键并使用退化了的鼠标工作。如果首要考虑,编程并不是要学习每种编程语言。不能通过电脑的品牌、价格、性能和操作系统来...

    嘉明
  • 『高级篇』docker之微服务thrift安装使用(十)

    PS:我想开发一个快速计算的RPC服务,它主要通过接口函数getInt对外提供服务,这个RPC服务的getInt函数使用用户传入的参数,经过复杂的计算,计算出一...

    IT故事会
  • Java魔法堂:内部类详解

    一、前言                                 对于内部类平时编码时使用的场景不多,比较常用的地方应该就是绑定事件处理程序的时候了(从...

    ^_^肥仔John
  • 2952 细胞分裂 2

    2952 细胞分裂 2 时间限制: 2 s 空间限制: 16000 KB 题目等级 : 钻石 Diamond 题目描述 Description 著...

    attack

扫码关注云+社区

领取腾讯云代金券