微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux (S3C6410架构/2.6.35内核)的内存映射(三)

ARM Linux (S3C6410架构/2.6.35内核)的内存映射(三)

时间:11-09 来源:互联网 点击:

这一段执行完之后,页表有了,但页表还是空的,下面要给指定的表项填充内容:

[c]pte = pte_offset_kernel(pmd, addr);do {set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);pfn  ;} while (pte  , addr  = PAGE_SIZE, addr != end);}[/c] 

addr是需要映射的页面的物理地址,pte_offset_kernel(pmd, addr)计算出这个物理地址在页表中对应的位置,不过需要注意的是,这里计算出的pte值指的是这个页面所对应的页表项在硬件页表中的位置。接下来调用set_pte_ext(),这是一个依硬件而不同的函数,比如在S3C6410上,它的实现是armv6_set_pte_ext(),是在arch/arm/mm/proc-macros.S文件中用汇编代码实现的。set_pte_ext()的作用是同时填充硬件页表和内核页表。

看一下在skyeye模拟器上运行这个内核的log:
vectors = 0xc02aa000
init_mm.pgd = 0xc0004000, addr = 0xffff0000, pgd_index() = 0x7ff, PGDIR_SHIFT = 21
alloc_init_pte()
pmd is still blank, pte = 0xc02ab000
will populate pmd
__pmd_populate():
&pmdp[0] = 0xc0007ff8, pmdp[0] = 0x502ab021
&pmdp[1] = 0xc0007ffc, pmdp[1] = 0x502ab421
pmd has been populated, pte = 0xc02abfc0, pfn = 0x502aa, pfn_pte = 0x502aa34b
before set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x0, linux_pte = 0xc02abfc0, *linux_pte = 0x0
after set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x502aa02a, linux_pte = 0xc02abfc0, *linux_pte = 0x502aa34b

我们通过bootmem申请到的中断向量表页的位置是0xc02aa000,这已经是一个虚拟地址,但我们需要把它重新映射到指定地址0xffff0000去。在alloc_init_pte()中,首先确认PGD为空,于是申请一页内存做为页表,得到的页面是0xc02ab000,紧挨着中断向量表那一样。

接下来填充PGD。我们要映射的的目标虚拟地址是0xffff0000,它在PGD表中的序号是0xffff0000/1M=0xfff,每个PGD占4字节,而PGD表的开始位置是0xc0004000,所以0xffff0000所对应的PGD的位置是0xc0004000 ((0xffff0000/1M) * 4) =0xc0007ffc。它是相邻两个PGD中的第二个,前一个PGD在0xc0007ff8。真给PGD的内容呢,先看前一项0xc0007ff8,向这里填的内容是(页表基地址 属性),新得到的页表地址为0xc02ab000,物理地址为0x502ab000,加上属性值0x21,所以向0xc0007ff8填充的PGD内容为0x502ab021。那么相应地,相邻的下一张页表的基地址要加上256*4=1024/1K,即0x400,所以向一个PGD(0xc0007ffc)填充的内容为0x502ab021 0x400 =0x502ab421。

现在页表有了,下面要做的就是填充指定的页表项。目标虚拟地址0xffff0000在Linux页表中表项的地址是0xc02abfc0,这是由pte_offset_kernel(pmd, addr)计算出来的,然后调用set_pte_ext()写入页表项,汇编代码的细节这里先不深究,只看写入的内容。最后两行打印分别是调用set_pte_ext()前后硬件页表和内核页表的内容,可以看到两张表里的内容都已经填好:

before set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x0, linux_pte = 0xc02abfc0, *linux_pte = 0x0
after set_pte_ext(): hw_pte = 0xc02ab7c0, *hw_pte = 0x502aa02a, linux_pte = 0xc02abfc0, *linux_pte = 0x502aa34b

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top