Linux内存管理学习2 —— head.S中的段页表的建立

发布时间:2023-06-20  

平台

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]

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>