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

2023-06-20  

平台

TQ2440


Qemu+vexpress-ca9


Linux-4.10.17


正文

继续分析head.S:


1     ldr    r13, =__mmap_switched        @ address to jump to after

2                         @ mmu has been enabled

3     badr    lr, 1f                @ return (PIC) address

4     mov    r8, r4                @ set TTBR1 to swapper_pg_dir

5     ldr    r12, [r10, #PROCINFO_INITFUNC]

6     add    r12, r12, r10

7     ret    r12

8 1:    b    __enable_mmu


第1行将__mmp_switched标号的虚拟地址赋给r13,后面从__turn_mmu_on返回时会用到


第3行将1f标号的物理地址赋给lr,后面从__arm920_setup返回时会用到


第4行将段式页表的物理起始地址赋给r8,对于TQ2440来说,是0x3000_4000,对于vexpress是0x6000_4000


第5行,因为r10指向匹配到的proc_info_list结构体的首地址,对于TQ2440来说,偏移#PROCINFO_INITFUNC得到的是__arm920_setup 与__arm920_proc_info的差值,存放到r12中,此时r10存放的就是__arm920_proc_info物理地址


第6行,r10加r12就得到了__arm920_setup的物理地址,对于vexpress来说是__v7_ca9mp_setup


第7行,开始执行__arm920_setup,定义在arch/arm/mm/proc-arm920.S中


 1     .type    __arm920_setup, #function

 2 __arm920_setup:

 3     mov    r0, #0

 4     mcr    p15, 0, r0, c7, c7        @ invalidate I,D caches on v4

 5     mcr    p15, 0, r0, c7, c10, 4        @ drain write buffer on v4

 6 

 7     mcr    p15, 0, r0, c8, c7        @ invalidate I,D TLBs on v4

 8 

 9     adr    r5, arm920_crval

10     ldmia    r5, {r5, r6}

11     mrc    p15, 0, r0, c1, c0        @ get control register v4

12     bic    r0, r0, r5

13     orr    r0, r0, r6

14     ret    lr

15     .size    __arm920_setup, . - __arm920_setup

16 

17     /*

18      *  R

19      * .RVI ZFRS BLDP WCAM

20      * ..11 0001 ..11 0101

21      * 

22      */

23     .type    arm920_crval, #object

24 arm920_crval:

25     crval    clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130


这个函数执行一些开启MMU之前的准备工作。上面对cache、tlb的操作可以参考手册 ARM920T Technical Reference Manual 的2.3.11 Register 7, cache operations register和2.3.12 Register 8, TLB operations register


第14行执行完毕后,会跳转到前面所说的head.S中的1f标号处,也就是   b __enable_mmu 


关于MMU的操作,可以参考手册 ARM920T Technical Reference Manual 的2.3.5 Register 1, control register


回到head.S继续分析。


 1 __enable_mmu:

 2 #if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6

 3     orr    r0, r0, #CR_A

 4 #else

 5     bic    r0, r0, #CR_A

 6 #endif

 7 

 8     mov    r5, #DACR_INIT

 9     mcr    p15, 0, r5, c3, c0, 0        @ load domain access register

10     mcr    p15, 0, r4, c2, c0, 0        @ load page table pointer

11 

12     b    __turn_mmu_on


第10行将段表的物理起始地址设置到CP15的C2寄存器中,即0x30004000或者0x60004000,可以参考ARM920T Technical Reference Manual 的2.3.6 Register 2, translation table base (TTB) register


第12行准备打开MMU


下面开始打开MMU:


 1     .align    5

 2     .pushsection    .idmap.text, "ax"

 3 ENTRY(__turn_mmu_on)

 4     mov    r0, r0

 5     instr_sync

 6     mcr    p15, 0, r0, c1, c0, 0        @ write control reg

 7     mrc    p15, 0, r3, c0, c0, 0        @ read id reg

 8     instr_sync

 9     mov    r3, r3

10     mov    r3, r13

11     ret    r3

12 __turn_mmu_on_end:

13 ENDPROC(__turn_mmu_on)

14     .popsection


第6行开启MMU, 由于之前已经建立了映射这部分的段表,所以程序可以继续执行,不会出错


第10行,r13中存放的是__mmap_switched的虚拟地址


第11行,开始跳到__mmap_switched处执行,自此以后的虚拟地址就跟链接地址相同了


__mmap_switched定义在arch/arm/kernel/head-common.S中:


 1 __mmap_switched:

 2     adr    r3, __mmap_switched_data

 3 

 4     ldmia    r3!, {r4, r5, r6, r7}

 5     cmp    r4, r5                @ Copy data segment if needed

 6 1:    cmpne    r5, r6

 7     ldrne    fp, [r4], #4

 8     strne    fp, [r5], #4

 9     bne    1b

10 

11     mov    fp, #0                @ Clear BSS (and zero fp)

12 1:    cmp    r6, r7

13     strcc    fp, [r6],#4

14     bcc    1b

15 

16  ARM(    ldmia    r3, {r4, r5, r6, r7, sp})

17 

18     str    r9, [r4]            @ Save processor ID

19     str    r1, [r5]            @ Save machine type

20     str    r2, [r6]            @ Save atags pointer

21     cmp    r7, #0

22     strne    r0, [r7]            @ Save control register values

23     b    start_kernel

24 ENDPROC(__mmap_switched)

25 

26     .align    2

27     .type    __mmap_switched_data, %object

28 __mmap_switched_data:

29     .long    __data_loc            @ r4

30     .long    _sdata                @ r5

31     .long    __bss_start            @ r6

32     .long    _end                @ r7

33     .long    processor_id            @ r4

34     .long    __machine_arch_type        @ r5

35     .long    __atags_pointer            @ r6

36     .long    cr_alignment            @ r7

37     .long    init_thread_union + THREAD_START_SP @ sp

38     .size    __mmap_switched_data, . - __mmap_switched_data


这里主要关注一下第16到第23行,这里将r9中存放的CPU ID赋给processor_id, 将dtb所在的物理地址赋给__atags_pointer,将sp设置为init_thread_union + THREAD_START_SP, 这里init_thread_union定义在init/init_task.c中,THREAD_START_SP的值是(8KB-8),也就是sp指向init进程的内核栈。然后第23行跳转到init/main.c中的start_kernel。


完。


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