因为工作原因,对这个部分有接触。平时看代码和一些文档的细节感觉过段时间就忘记了。所以要做个记录。可能其中还有错误。吧一个对人很有启发的记录下来。不过这些内容很零散,平时也是需要才看。以下说的arm是支持mmu的arm9以上.
Linux支持三级页表,作为其默认的页表结构。ARM是两极页表。PGD和PTE。从pgtable.h里面可以可以看出一个work around的实现。PGD和PTE并不是直接对应ARM硬件的页表目录项。而是做了一些为了linux上层的要求的一个方案。首先,他把4096个pgd项变成2048个,物理上还是一个pgd指向一个256个pte项的数组的,这没办法改。但是pgd指针逻辑上合并成一个,各自指向的的pte数组也合并。并且是连续的。
pgd pte 57 * | | 58 * +--------+ +0 59 * | |-----> +------------+ +0 60 * +- - - - + +4 | h/w pt 0 | 61 * | |-----> +------------+ +1024 62 * +--------+ +8 | h/w pt 1 | 63 * | | +------------+ +2048 64 * +- - - - + | Linux pt 0 | 65 * | | +------------+ +3072 66 * +--------+ | Linux pt 1 | 67 * | | +------------+ +4096 以上内容摘自Linux ARM pgtable.h, GPL.这512个pte项合并起来,这个pte分配的页(一般linux需要一个pte表在一个页里,代码注释也写了)还剩下一半的内容,刚好可以存放arm不支持的一些标记(Linux pt 0, 1),而这些标记是linux必须的,比如dirty。这个方案还非常具有可扩展性,不依赖arm本身的标记。dirty标记的实现是通过对arm支持的权限fault的中断来写这个标记。这样方式是相当于一种模拟。
对于不同cpu版本,set_pte的实现是用宏##拼的函数,这些函数不再arch/arm/kernel而是arch/arm/mm里面,找个v6的实现里面可以看到实现:(这段代码上面的一段注释不知道是不是写错了, ptep - pointer to level 2 translation table entry (hardware version is stored at -1024 bytes),明明是2048个字节,代码也是,也许是我理解错)
这里就看到先偏移2048个字节找到“真的”pte做事。
ENTRY(cpu_v6_set_pte) 154 str r1, [r0], #-2048 @ linux version 155 156 bic r2, r1, #0x000003f0 157 bic r2, r2, #0x00000003 158 orr r2, r2, #PTE_EXT_AP0 | 2 ... tst r1, #L_PTE_PRESENT 176 moveq r2, #0 177 178 str r2, [r0] 179 mcr p15, 0, r0, c7, c10, 1 @ flush_pte 180 mov pc, lr关于ARM的模式,arm本来有7个模式,而linux只有两个user和kernel。于是Linux的实现就把包括中断处理模式页转到同一个模式下做事,就是arm的所谓超级用户(svc)模式,实现这个的办法就是改写备份寄存器spsr为svc的模式,然后movs pc到svc模式,然后再调用处理函数,这样除了用户模式其他的模式执行环境都是同一个模式了。
感觉选择svc模式作为kernel也是很自然的,swi一看就是用来做系统调用的,直接进入svc模式。
这段代码是在宏里面,然后根据不同模式进行展开在头部。
.macro vector_stub, name, mode, correction=0 885 .align 5 886 887 vector_\name: 888 .if \correction 889 sub lr, lr, #\correction 890 .endif 891 892 @ 893 @ Save r0, lr_另外,对于不支持高向量的arm,因为中断向量表从0开始,所以需要把第一页保留,不作为用户空间。(parent PC) and spsr_ 894 @ (parent CPSR) 895 @ 896 stmia sp, {r0, lr} @ save r0, lr 897 mrs lr, spsr 898 str lr, [sp, #8] @ save spsr 899 900 @ 901 @ Prepare for SVC32 mode. IRQs remain disabled. 902 @ 903 mrs r0, cpsr 904 eor r0, r0, #(\mode ^ SVC_MODE) 905 msr spsr_cxsf, r0 906 907 @ 908 @ the branch table must immediately follow this code 909 @ 910 and lr, lr, #0x0f 911 mov r0, sp 912 ldr lr, [pc, lr, lsl #2] 913 movs pc, lr @ branch to handler in SVC mode 914 .endm