平台
TQ2440
Qemu+vexpress-ca9
Linux-4.10.17
正文
继续分析head.S:
此时r2存放的是设备树镜像的物理起始地址,r8是物理内存的起始地址,r9是从CP15的C0中读到的cpu id,r10是与该cpu id匹配的proc_info_list的物理地址
TQ2440:
r8: 0x3000_0000,r9: 0x41129200
vexpress:
r8: 0x6000_0000,r9: 0x414FC091
8、第30行调用__create_page_tables建立段式页表。
下面是__create_page_tables的定义: 其中涉及到几个宏定义:
PG_DIR_SIZE: 0x4000
PROCINFO_MM_MMUFLAGS:0x8
SECTION_SHIFT:20
PMD_ORDER:2
1 /*
2 * Setup the initial page tables. We only setup the barest
3 * amount which are required to get the kernel running, which
4 * generally means mapping in the kernel code.
5 *
6 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
7 *
8 * Returns:
9 * r0, r3, r5-r7 corrupted
10 * r4 = physical page table address
11 */
12 __create_page_tables:
13 pgtbl r4, r8 @ page table address
14
15 /*
16 * Clear the swapper page table
17 */
18 mov r0, r4
19 mov r3, #0
20 add r6, r0, #PG_DIR_SIZE
21 1: str r3, [r0], #4
22 str r3, [r0], #4
23 str r3, [r0], #4
24 str r3, [r0], #4
25 teq r0, r6
26 bne 1b
27
28 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
29
30 /*
31 * Create identity mapping to cater for __enable_mmu.
32 * This identity mapping will be removed by paging_init().
33 */
34 adr r0, __turn_mmu_on_loc
35 ldmia r0, {r3, r5, r6}
36 sub r0, r0, r3 @ virt->phys offset
37 add r5, r5, r0 @ phys __turn_mmu_on
38 add r6, r6, r0 @ phys __turn_mmu_on_end
39 mov r5, r5, lsr #SECTION_SHIFT
40 mov r6, r6, lsr #SECTION_SHIFT
41
42 1: orr r3, r7, r5, lsl #SECTION_SHIFT @ flags + kernel base
43 str r3, [r4, r5, lsl #PMD_ORDER] @ identity mapping
44 cmp r5, r6
45 addlo r5, r5, #1 @ next section
46 blo 1b
47
48 /*
49 * Map our RAM from the start to the end of the kernel .bss section.
50 */
51 add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER)
52 ldr r6, =(_end - 1)
53 orr r3, r8, r7
54 add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER)
55 1: str r3, [r0], #1 << PMD_ORDER
56 add r3, r3, #1 << SECTION_SHIFT
57 cmp r0, r6
58 bls 1b
59
60 /*
61 * Then map boot params address in r2 if specified.
62 * We map 2 sections in case the ATAGs/DTB crosses a section boundary.
63 */
64 mov r0, r2, lsr #SECTION_SHIFT
65 movs r0, r0, lsl #SECTION_SHIFT
66 subne r3, r0, r8
67 addne r3, r3, #PAGE_OFFSET
68 addne r3, r4, r3, lsr #(SECTION_SHIFT - PMD_ORDER)
69 orrne r6, r7, r0
70 strne r6, [r3], #1 << PMD_ORDER
71 addne r6, r6, #1 << SECTION_SHIFT
72 strne r6, [r3]
73
74 ret lr
75 ENDPROC(__create_page_tables)
76 .ltorg
77 .align
78 __turn_mmu_on_loc:
79 .long .
80 .long __turn_mmu_on
81 .long __turn_mmu_on_end
第13行,计算段式页表在物理内存当中的起始地址,方法如下:
.macro pgtbl, rd, phys
add rd, phys, #TEXT_OFFSET
sub rd, rd, #PG_DIR_SIZE
.endm
r4 = r8 + 0x8000 - 0x4000,通过前文知道r8存放的是物理内存的起始地址,所以对于TQ2440,r4为0x3000_4000,对于vexpress是0x6000_4000,也就是段式页表占据了kernel代码段(0x3000_8000或0x6000_8000)之前的16KB的物理内存
第18到第26行,将段式页表的占据的那16KB的物理内存清零
第28行,加载MMU Flags到r7中。通过之前的分析知道,r10中存放的是与cpu id匹配的proc_info_list的首地址,这里访问的是proc_info_list->__cpu_mm_mmu_flags。
对于TQ2440,是0x00000c1e, 对于vexpress来说是0x00011c0e。下面以TQ2440为例说明。参考手册 ARM920T Technical Reference Manual 的 3.3.3 Level one descriptor
对于段式页表,bit[1:0]是0x10,对于TQ2440的0xC1E,满足这一条件,所以是段式页表。具体段式页表的页表项的含义如下:
每个bit位的含义如下:
对于段式页表,只需要一级,地址转换过程如下:
理解了段式页表地址翻译的过程,也就容易理解接下来建立段式页表的代码了。
可以现在start_kernel的入口处将段式页表中的内容打印出来:
diff --git a/init/main.c b/init/main.c
index 09beb7f..fa6edd6 100644
--- a/init/main.c
+++ b/init/main.c
@@ -484,6 +484,18 @@ asmlinkage __visible void __init start_kernel(void)
char *command_line;
char *after_dashes;
+
+ unsigned int i, addr, value;
+ for (i=0; i < 0x1000; i++) {
+ addr = 0xC0004000 + i*4;
+ value = *((unsigned int *)addr);
+ if (value) {
+ pr_notice("0x%04x: hw: 0x%08x, virt: 0x%08x, value: 0x%08x map: [0x%08x ~ 0x%08x ==> 0x%08x ~ 0x%08x]n",
+ i, __pa(addr), addr, *((int *)addr), i*(1<<20), i*(1<<20)+(1<<20)-1,
+ ((value>>20)<<20), ((value>>20)<<20)+(1<<20)-1);
+ }
+ }
+
set_task_stack_end_magic(&init_task);
smp_setup_processor_id();
debug_objects_early_init();
上面加的代码会将段式表中建立了映射的段表项的编号、存放每个段表项的物理地址和虚拟地址以及段表项的内容、该段表实现的虚拟地址跟物理地址之间的映射关系都打印出来。
对于TQ2440,段表内容如下:
1 0x0300: hw: 0x30004c00, virt: 0xc0004c00, value: 0x30000c1e map: [0x30000000 ~ 0x300fffff ==> 0x30000000 ~ 0x300fffff]
2 0x0c00: hw: 0x30007000, virt: 0xc0007000, value: 0x30000c1e map: [0xc0000000 ~ 0xc00fffff ==> 0x30000000 ~ 0x300fffff]
3 0x0c01: hw: 0x30007004, virt: 0xc0007004, value: 0x30100c1e map: [0xc0100000 ~ 0xc01fffff ==> 0x30100000 ~ 0x301fffff]
4 0x0c02: hw: 0x30007008, virt: 0xc0007008, value: 0x30200c1e map: [0xc0200000 ~ 0xc02fffff ==> 0x30200000 ~ 0x302fffff]
5 0x0c03: hw: 0x3000700c, virt: 0xc000700c, value: 0x30300c1e map: [0xc0300000 ~ 0xc03fffff ==> 0x30300000 ~ 0x303fffff]
6 0x0c04: hw: 0x30007010, virt: 0xc0007010, value: 0x30400c1e map: [0xc0400000 ~ 0xc04fffff ==> 0x30400000 ~ 0x304fffff]
7 0x0c05: hw: 0x30007014, virt: 0xc0007014, value: 0x30500c1e map: [0xc0500000 ~ 0xc05fffff ==> 0x30500000 ~ 0x305fffff]
8 0x0c06: hw: 0x30007018, virt: 0xc0007018, value: 0x30600c1e map: [0xc0600000 ~ 0xc06fffff ==> 0x30600000 ~ 0x306fffff]
9 0x0c07: hw: 0x3000701c, virt: 0xc000701c, value: 0x30700c1e map: [0xc0700000 ~ 0xc07fffff ==> 0x30700000 ~ 0x307fffff]
10 0x0c3a: hw: 0x300070e8, virt: 0xc00070e8, value: 0x33a00c1e map: [0xc3a00000 ~ 0xc3afffff ==> 0x33a00000 ~ 0x33afffff]
11 0x0c3b: hw: 0x300070ec, virt: 0xc00070ec, value: 0x33b00c1e map: [0xc3b00000 ~ 0xc3bfffff ==> 0x33b00000 ~ 0x33bfffff]
12 0x0f70: hw: 0x30007dc0, virt: 0xc0007dc0, value: 0x50000c12 map: [0xf7000000 ~ 0xf70fffff ==> 0x50000000 ~ 0x500fffff]
对于vexpress,段表内容如下:
1 0x0601: hw: 0x60005804, virt: 0xc0005804, value: 0x60111c0e map: [0x60100000 ~ 0x601fffff ==> 0x60100000 ~ 0x601fffff]
2 0x0c00: hw: 0x60007000, virt: 0xc0007000, value: 0x60011c0e map: [0xc0000000 ~ 0xc00fffff ==> 0x60000000 ~ 0x600fffff]
3 0x0c01: hw: 0x60007004, virt: 0xc0007004, value: 0x60111c0e map: [0xc0100000 ~ 0xc01fffff ==> 0x60100000 ~ 0x601fffff]
4 0x0c02: hw: 0x60007008, virt: 0xc0007008, value: 0x60211c0e map: [0xc0200000 ~ 0xc02fffff ==> 0x60200000 ~ 0x602fffff]
5 0x0c03: hw: 0x6000700c, virt: 0xc000700c, value: 0x60311c0e map: [0xc0300000 ~ 0xc03fffff ==> 0x60300000 ~ 0x603fffff]
6 0x0c04: hw: 0x60007010, virt: 0xc0007010, value: 0x60411c0e map: [0xc0400000 ~ 0xc04fffff ==> 0x60400000 ~ 0x604fffff]
7 0x0c05: hw: 0x60007014, virt: 0xc0007014, value: 0x60511c0e map: [0xc0500000 ~ 0xc05fffff ==> 0x60500000 ~ 0x605fffff]
8 0x0c06: hw: 0x60007018, virt: 0xc0007018, value: 0x60611c0e map: [0xc0600000 ~ 0xc06fffff ==> 0x60600000 ~ 0x606fffff]
9 0x0c07: hw: 0x6000701c, virt: 0xc000701c, value: 0x60711c0e map: [0xc0700000 ~ 0xc07fffff ==> 0x60700000 ~ 0x607fffff]
10 0x0c08: hw: 0x60007020, virt: 0xc0007020, value: 0x60811c0e map: [0xc0800000 ~ 0xc08fffff ==> 0x60800000 ~ 0x608fffff]
11 0x0c09: hw: 0x60007024, virt: 0xc0007024, value: 0x60911c0e map: [0xc0900000 ~ 0xc09fffff ==> 0x60900000 ~ 0x609fffff]
12 0x0c0a: hw: 0x60007028, virt: 0xc0007028, value: 0x60a11c0e map: [0xc0a00000 ~ 0xc0afffff ==> 0x60a00000 ~ 0x60afffff]
13 0x0c80: hw: 0x60007200, virt: 0xc0007200, value: 0x68011c0e map: [0xc8000000 ~ 0xc80fffff ==> 0x68000000 ~ 0x680fffff]
14 0x0c81: hw: 0x60007204, virt: 0xc0007204, value: 0x68111c0e map: [0xc8100000 ~ 0xc81fffff ==> 0x68100000 ~ 0x681fffff]
15 0x0f80: hw: 0x60007e00, virt: 0xc0007e00, value: 0x10000c12 map: [0xf8000000 ~ 0xf80fffff ==> 0x10000000 ~ 0x100fffff]