Arm Linux 内核页表的段式映射

来源:互联网 发布:模拟报关软件 编辑:程序博客网 时间:2024/04/30 03:08
Linux启动之初,内核为自己建立的是段式内存映射,而不是页式映射。
映射表(PGD)从虚拟地址0xc0004000开始,每项4字节,每项对应1M内存空间,每项的高12位就是这1M内存的高12位地址。
一开始,内核不会为所有内存建立映射,只会映射必要的一部分,这部分代码在arch/arm/kernel/head.S中由汇编代码完成。

以S3C6410为例,下面是在刚刚进入start_kernel()后打印出来的一段内核映射表。注意内核自身的映射表项是从0xc0007000地址开始。因为从0xc0004000开始的是整个4G空间的表,内核内存只占最高的那1G,所以要加一个偏移量:3G/1M* 4bytes = 0x3000。
c0007000: 0e 0c 0050 0e 0c 10 50 0e 0c 20 50 00 00 0000
c0007010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000
c0007020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000
c0007030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000

由于字节序的原因,上面的每一个表项应该颠倒一下顺序来看,以第一项为例,应该是:
50 00 0c 0e
高12位地址是0x500,因为s3c6410的内存物理地址就是从0x50000000开始。

启动到C函数start_kernel()之后,在arch_setup()中会重写映射表,映射所有内存。这时的页表会如下所示:
c0007000: 0e 04 0050 0e 04 10 50 0e 04 20 50 0e 04 3050
c0007010: 0e 04 40 50 0e 04 50 50 0e 04 60 50 0e 04 7050
c0007020: 0e 04 80 50 0e 04 90 50 0e 04 a0 50 0e 04 b050
c0007030: 0e 04 c0 50 0e 04 d0 50 0e 04 e0 50 0e 04 f050
......
注意,每一个表项的最后两个bit指明了映射方式,00表示段式映射。在内存重新映射之后,这一映射方式并没有变化。

再来看一段应该程序的pgd表内容,这段内容是从其pgd表开始位置打印的,所以是为用户程序虚拟进程空间建立的映射:
c0d98000: 31 c8 d850 31 cc d8 50 00 00 00 00 00 00 0000
c0d98010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000
c0d98020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000
c0d98030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000
可以看到,表项最后两位是01,这已经是二级页式映射了。

这说明,尽管内核为应用程序建立的是二级粗粒度页式映射,但Linux内核自身一直是运行在段映射模式下。两种映射在同一张pgd表里面可以同时使用,映射方式不必全表统一。

原创粉丝点击