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


    作者

    彭东林

    pengdonglin137@163.com

    平台

    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。

    完。

  • 相关阅读:
    使用Cmake生成makefile
    c++模板类(一)理解编译器的编译模板过程
    C++ 模板
    c++/c 获取cpp文件行号跟文件名
    java获取代码调用位置信息
    android获取手机ip
    Cocos2d-html5游戏开发,常用工具集合
    cocos2d-html5基础
    Cocos2d-x-html5之HelloWorld深入分析与调试
    基于ndk_r7_windows编译实现ndk项目,不需要cygwin
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/7820021.html
Copyright © 2020-2023  润新知