Arm 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:
c0007010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0007020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0007030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
由于字节序的原因,上面的每一个表项应该颠倒一下顺序来看,以第一项为例,应该是:
50
高12位地址是0x500,因为s3c6410的内存物理地址就是从0x50000000开始。
启动到C函数start_kernel()之后,在arch_setup()中会重写映射表,映射所有内存。这时的页表会如下所示:
c0007000:
c0007010: 0e 04 40 50 0e 04 50 50 0e 04 60 50 0e 04 70 50
c0007020: 0e 04 80 50 0e 04 90 50 0e 04 a0 50 0e 04 b0 50
c0007030: 0e 04 c0 50 0e 04 d0 50 0e 04 e0 50 0e 04 f0 50
......
注意,每一个表项的最后两个bit指明了映射方式,00表示段式映射。在内存重新映射之后,这一映射方式并没有变化。
再来看一段应该程序的pgd表内容,这段内容是从其pgd表开始位置打印的,所以是为用户程序虚拟进程空间建立的映射:
c0d98000:
c0d98010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0d98020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
c0d98030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
可以看到,表项最后两位是01,这已经是二级页式映射了。
这说明,尽管内核为应用程序建立的是二级粗粒度页式映射,但Linux内核自身一直是运行在段映射模式下。两种映射在同一张pgd表里面可以同时使用,映射方式不必全表统一。
ArmLinux内核页表段式映 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)