版权声明:本文为博主原创文章,未经博主允许不得转载。



 


很久没有写博客了,由于之前的写关于OMAP3530文章还没有整理。再加上一直在找工作,找到工作后又投入到另外的平台去工作。始终在忙忙碌碌,但是对于代码确实渐渐疏远。

在做项目的时候要使用DDR3分配内存,不经意间使用要和MMU以及TLB打交道。因此特地写下这篇文章以备后用。(工作就是在和遗忘作斗争)!

 

Linux在启动之初会建立临时页表,但是在start_kerne函数中setup_arch又会建立正真的页表和页目录。那么两套方案是如何过渡的?假如在MMU开启的时候把之前的临时页表给覆盖了或者修改了,会不会影响后续的启动过程?带着这些问题分析一下。

 

首先来看一下基于ARM的页表管理和MMU的行为分析:

ARM-Linux (临时,正式) 建立页表的比较【转】_二级

 

Arm上的linux(正式)页表采用的是一级粗页表结合二级小页表实现4G空间的访问。如上图说明。

 

一级表 (1024 Entrys)

 

二级表 (1024 Entrys)

 

虚拟地址后12位Offset寻址空间是4096B 4k的空间

 

Arm上的linux(临时)页表采用的是段式页表,每一个entry可以映射1M的空间,结合后面的20bits位(寻址空间正好是1M)

 

一级表 (4096 Entrys)

 

虚拟地址的后20位offset寻址空间是1M

接着来看一下linux如何建立页表的过程。

 

Head.S中有一段使用汇编编写的初始化代码。Mmu.c中有一段使用c语言写的建立页表的代码。C语言的代码很经典,可能汇编更经典。这里不多分析了。可以百度文章很多分析。

 

关键问题在于一个变量swap_pgdir

 

1..macro    pgtbl, rd  

 

2.  

 

3.       ldr   \rd, =(KERNEL_RAM_PADDR - 0x4000)  

 

4.  

 

5..endm  

 

KERNEL_RAM_PADDR = 0 x XXXXXXXX这是内存的物理地址,那么页表的建立也在这物理地址相关的区域内。

 

临时页表使用的是段式映射,也称之为平坦映射。那么4G的空间划分为1M为单位的访问单元,需要4096个Entrys。应为Arm采用32位的数据线,因此每一个Entry占用一个32位的区段,也就是4B。

 

正式页表建立的过程分为二级映射也寻找index的过程。每次把线性地址划分为两段,每一段都作为索引根据TLB BASE的便宜寻找下一级的索引项。最后结合虚拟地址的最后偏移(10 bit)作为依据在4K的空间内寻址。

 

 

问题来了,这两种映射会不会应为后一种映射的建立把之前的映射破坏掉,导致linux一个复杂的寻址系统无法正常工作呢?答案肯定不会。

 

图示比文字描述来的直接,还是直接上两张图说明问题:

ARM-Linux (临时,正式) 建立页表的比较【转】_linux_02

ARM-Linux (临时,正式) 建立页表的比较【转】_二级_03

 

由上图可知:临时页表建立的空间和正式页表建立的空间分别部署于不同的空间,因此不会出现覆盖或者修改等现象。同时一二级页表项目录中的内容页值得研究。最后两位同时表现出来的控制逻辑,让MMU翻译地址的过程中有章可循。结合MMU中的AP位规定了访问空间的属性,是否可以访问拒绝访问等。



 

    最后希望图示可以帮助读者理解映射的意图。文中难免有些地方会引起歧义或者不足之初,希望linux大侠指正点评。


【作者】​​张昺华​




【微信公众号】 张昺华

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.