设为首页 收藏本站
查看: 442|回复: 0

[经验分享] linux的页表为什么没有实现自映射

[复制链接]

尚未签到

发表于 2016-3-11 12:36:20 | 显示全部楼层 |阅读模式
  玩过windows内核的都应该知道windows为了节省4k的内存,实现了自映射,将页目录本身当作了一个页表来寻址4M的虚拟空间(将4M空间的虚 拟内存映射到物理内存),而这4m的虚拟地址空间恰恰就是从0xc0000000到0xc03FFFFF的空间,这一段空间正好是页表页目录的映射区域。下面我来说一下这怎么变成现实。   
首先有几点必须遵守的规则:1.一个页表映射的4m虚拟地址肯定是连续的;2.一个页表映射到的1024个4k的物理页不一定是连续的;3.实现自映射必须是页目录和页表结构一样。有了以上的规则,我们要想理解(或者自己实现一个)windows的自映射就必须理解实际上windows的页表虚拟地址都是 连续的,映射到0xc0000000到0xc03FFFFF,表现为一个页表数组,一共1024项,每项4096字节,一共正好4m,页目录作为这4m的 页表。我们反着想,如果页目录成为了这4m的页表,那么肯定映射0xc0000000到0xc03FFFFF的地址,我们将端点的两个地址分 解:11000000000000000000000000000000B和11000000001111111111111111111111B,仔细观察发现高10位是相等的,而这高10位正好是页目录项的索引,我们知道他是768,好了,页目录要作为第768页目录项对应的页表,现在这个页目录可以 作为一个页表插入到这个页表数组的第768项的位置了,它开始身兼两职了,CR3寄存器里面写的是它的物理地址,它作为页目录,此页面偏移768处也写入 了这个物理地址,它作为页表。   
现在考虑把这个页目录(页表)的虚拟映射地址换一下会怎样,别的页表不动。比如这个页目录映射到了0xdc000000这个虚拟地址(仅仅据个例子)。然 后分解地址1101110000 0000000000 000000000000,通过计算发现其对应于页目录的880项,那好吧,我把此页面880偏移改成此页面的物理地址,别的偏移处仍然指向 0xc0000000到0xc03FFFFF的虚拟地址对应的物理地址。看看会发生什么事情,如果把这个从0xc0000000到0xc03FFFFF游 离出来的页面当作页表的话,那么它所映射的虚拟地址应该连续,但是它自己是游离出来的,它的虚拟地址和别的页表的虚拟地址根本不连续,所以这样做是不可以的,也就是说对映射地址的连续性要求是一个必要的条件。windows之所以这么简单的实现了自映射,完全归功于它的设计思想,实际上一个设计并没有多么复杂,只要有了完备性,剩下的就是一个自然结果了,比如X系统是复杂的,而且它在unix出现很久以后才出现,但是unix却完美地支持了x系统,这就说 明unix很完备。windows的模块化作的很好,一致性作的也很好,它几乎将任何东西都标准化,每个进程的页表映射到同一个虚拟地址,在 windows看来,为每个进程提供一个一致的视图要比巧妙的杂糅式进程管理重要的多,所以它将虚拟地址空间作了很复杂的划分和规定。   
linux正好走了相反的路,它对于虚拟内存空间什么也没有规定,只是说了一下映射规则,提供了一套完备的机制,策略问题根本没有提及,内核虚存空间各个进程完全共享,各个数据结构散落在各处,内核空间仅仅提供了直接映射和高端映射的若干种映射规则和分配规则,至于说每个空间范围干什么用,linux只字 未提,所以说linux的页表可以散落在物理内存的任何地方,因为物理内存和虚拟内存在内核的很大一部分是一一映射的,所以上面的虚拟地址连续的要求就很难满足,比如这可能要求物理内存连续,在linux连续地址空间如此宝贵,浪费当作页表linux觉得这不值得,再说,页表可以随时分配,为什么要连续 呢?连续的话就要先预留4m页面,然后页表没有完全分配前会造成很多空洞,有几个进程能完全用完4m的页表呢?linux保守的回答了这个问题。我们看一 下代码就明白页表的分配了,代码来自最新的2.6.27内核:
  int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
  unsigned long address, int write_access)
  {
  pgd_t *pgd;
  pud_t *pud;
  pmd_t *pmd;
  pte_t *pte;
  __set_current_state(TASK_RUNNING);
  count_vm_event(PGFAULT);
  if (unlikely(is_vm_hugetlb_page(vma)))
  return hugetlb_fault(mm, vma, address, write_access);
  pgd = pgd_offset(mm, address);
  pud = pud_alloc(mm, pgd, address);
  if (!pud)
  return VM_FAULT_OOM;
  pmd = pmd_alloc(mm, pud, address);
  if (!pmd)
  return VM_FAULT_OOM;
  pte = pte_alloc_map(mm, pmd, address);//此处即分配页表
  if (!pte)
  return VM_FAULT_OOM;
  return handle_pte_fault(mm, vma, address, pte, pmd, write_access);
  }
  #define pte_alloc_map(mm, pmd, address) /
  ((unlikely(!pmd_present(*(pmd))) && __pte_alloc(mm, pmd, address))? /
  NULL: pte_offset_map(pmd, address))
  分配页表的策略是alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT|__GFP_ZERO, 0)好家伙,这么猛,你能保证这分配的页面和前一个页面是连续的吗?你不能,我也不能,甚至linus也不能

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-189420-1-1.html 上篇帖子: 从著名的list_head看linux内核中OO 下篇帖子: Linux开机自动挂载Windows分区的两种方法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表