Linux内核---15.启动分析3之arch/arm/kernel/head.S

一、从__create_page_tables返回后,寄存器如下:
r4= pgtbl (0x30004000)
r8 = machine_info    
r9 = cpu_ID
r10 =  proc_info (arch/arm/mm/proc-arm920.S中的__arm920_proc_info )
在arch/arm/kernel/head.S中
  1. 99  ldr r13, __switch_data     @ address to jump to after            //L99-L102 每个函数的调用顺序是:
  2. 100 @ mmu has been enabled                                            // L102的arm920_setup--> L101 __enable_mmu --> L99 switch_data --> b start_kernel
  3. 101 adr lr, __enable_mmu        @ return (PIC) address                
  4. 102 add pc, r10, #PROCINFO_INITFUNC                                   
首先执行L102, pc= r10(__arm920_proc_info)+PROCINFO_INITFUNC(16)=  b    __arm920_setup
在arm920_setup结束时会调用mov pc, lr, 而此时的lr是L101的__enable_mmu, 
L101 __enable_mmu结束时会调用mov pc, r13,  而此时的r13是L99的__switch_data
L99 __switch_data结束时会调用 b start_kernel

二、  arch/arm/mm/proc-arm920.S中 __arm920_setup
函数的作用是关闭I-cache D-cache, 清write_buffer, 清TLB, 获取控制寄存器之后,修改状态
注意: 这个函数只是配置好状态并保存在r0中,真正的状态不是在这个函数中完成的,
  1. 385 .type __arm920_setup, #function
  2. 386 __arm920_setup:
  3. 387      mov r0, #0
  4. 388      mcr p15, 0, r0, c7, c7         @ invalidate I,D caches on v4    //关闭I-cache D-cache
  5. 389      mcr p15, 0, r0, c7, c10, 4     @ drain write buffer on v4       //清write_buffer
  6. 390 #ifdef CONFIG_MMU
  7. 391     mcr p15, 0, r0, c8, c7          @ invalidate I,D TLBs on v4      //清TLB
  8. 392 #endif
  9. 393     adr r5, arm920_crval                                             //
  10. 394     ldmia r5, {r5, r6}                                               //把状态读到寄存器中,r5=clear, r6=mmuset
  11. 395     mrc p15, 0, r0, c1, c0          @ get control register v4        //获取当前状态
  12. 396     bic r0, r0, r5                                                   //把状态保存到r0中
  13. 397     orr r0, r0, r6                                                   //到时候用mcr设置
  14. 398     mov pc, lr
  15. 399 .size __arm920_setup, . - __arm920_setup
  16. 400 
  17. 401 /*
  18. 402 * R
  19. 403 * .RVI ZFRS BLDP WCAM
  20. 404 * ..11 0001 ..11 0101
  21. 405 * 
  22. 406 */
  23. 407     .type arm920_crval, #object
  24. 408 arm920_crval:
  25. 409     crval clear=0x00003f3f, mmuset=0x00003135, ucset=0x00001130
  26. 410 
  27. 411 __INITDATA

arch/arm/mm/proc-macros.S中定义了宏crval
  1.  53 .macro crval, clear, mmuset, ucset
  2.  54 #ifdef CONFIG_MMU
  3.  55     .word \clear
  4.  56     .word \mmuset
  5.  57 #else
  6.  58    .word \clear
  7.  59     .word \ucset
  8.  60 #endif
  9.  61 .endm
三、 __enable_mmu,打开MMU
程序返回后进入到上一次
 在arch/arm/kernel/head.S中 
101 adr lr, __enable_mmu
102   add pc, r10, #PROCINFO_INITFUNC
L102行执行完后  mov  pc ,  lr, 而lr中保存的是__enable_mmu,所以下一步进入__enable_mmu中
  1. 154 .type __enable_mmu, %function
  2. 155 __enable_mmu:                                                     //L155-L176根据不同的config,修改r0, 的r0是要配置的控制寄存器的内容
  3. 156 #ifdef CONFIG_ALIGNMENT_TRAP
  4. 157      orr r0, r0, #CR_A
  5. 158 #else
  6. 159     bic r0, r0, #CR_A
  7. 160 #endif
  8. 161 #ifdef CONFIG_CPU_DCACHE_DISABLE
  9. 162      bic r0, r0, #CR_C
  10. 163 #endif
  11. 164 #ifdef CONFIG_CPU_BPREDICT_DISABLE
  12. 165      bic r0, r0, #CR_Z
  13. 166 #endif
  14. 167 #ifdef CONFIG_CPU_ICACHE_DISABLE
  15. 168      bic r0, r0, #CR_I
  16. 169 #endif
  17. 170      mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
  18. 171      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
  19. 172     domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
  20. 173     domain_val(DOMAIN_IO, DOMAIN_CLIENT))
  21. 174     mcr p15, 0, r5, c3, c0, 0 @ load domain access register
  22. 175     mcr p15, 0, r4, c2, c0, 0 @ load page table pointer
  23. 176      b __turn_mmu_on
  24. ...
  25. 189     .align  5
    190     .type   __turn_mmu_on, %functionr10, #PROCINFO_INITFUNC
    191 __turn_mmu_on:
    192     mov r0, r0
    193     mcr p15, 0, r0, c1, c0, 0       @ write control reg            //r0是控制寄存器的内容,把r0写到控制寄存器中,使生效
    194     mrc p15, 0, r3, c0, c0, 0       @ read id reg
    195     mov r3, r3
    196     mov r3, r3
    197     mov pc, r13
四、完成数据保存并跳转到start_kernel中
        __turn_mmu_on 的最后是: mov pc, r13, 
       而在arch/arm/head.S中 ldr r13, __switch_data
        所以下一步要执行__switch_data
在 arch/arm/kernel/head-common.S中
  1.  14 #define ATAG_CORE 0x54410001
  2.  15 #define ATAG_CORE_SIZE ((2*+ 3*4) >> 2)
  3.  16 
  4.  17 .type __switch_data, %object
  5.  18 __switch_data:
  6.  19 .long __mmap_switched
  7.  20 .long __data_loc @ r4
  8.  21 .long __data_start @ r5
  9.  22 .long __bss_start @ r6
  10.  23 .long _end @ r7
  11.  24 .long processor_id @ r4
  12.  25 .long __machine_arch_type @ r5
  13.  26 .long __atags_pointer @ r6
  14.  27 .long cr_alignment @ r7
  15.  28 .long init_thread_union + THREAD_START_SP @ sp
  16.  29
  17.  30 /*
     31  * The following fragment of code is executed with the MMU on in MMU mode,
     32  * and uses absolute addresses; this is not position independent.
     33  *
     34  *  r0  = cp#15 control register
     35  *  r1  = machine ID
     36  *  r2  = atags pointer
     37  *  r9  = processor ID
     38  */
     39     .type   __mmap_switched, %function
     40 __mmap_switched:
     41     adr r3, __switch_data + 4
     42 
     43     ldmia   r3!, {r4, r5, r6, r7}
     44     cmp r4, r5              @ Copy data segment if needed
     45 1:  cmpne   r5, r6
     46     ldrne   fp, [r4], #4
     47     strne   fp, [r5], #4
     48     bne 1b
     49 
     50     mov fp, #0              @ Clear BSS (and zero fp)
     51 1:  cmp r6, r7
     52     strcc   fp, [r6],#4
     53     bcc 1b
     54 
     55     ldmia   r3, {r4, r5, r6, r7, sp}
     56     str r9, [r4]            @ Save processor ID
     57     str r1, [r5]            @ Save machine type
     58     str r2, [r6]            @ Save atags pointer
     59     bic r4, r0, #CR_A           @ Clear 'A' bit
     60     stmia   r7, {r0, r4}            @ Save control register values
     61     b   start_kernel
     62 
最终跳到start_kernel中。

附: 调试方法
对于苦B青年来说,其实没啥好说的, 直接打印
  1. //函数会以16进制形式打印r0中的数值
  2. __right_p:
  3.     adr r13, spbuf1
  4.     STMIA r13, {R0-R4,R7}
  5.     mov r7, lr
  6.     mov r4, r0
  7.     adr r0, str_p3
  8.     bl    printascii
  9.     mov r0 ,r4
  10.     bl printhex8
  11.     adr r0,str_p4
  12.     bl printascii
  13.     mov lr,r7
  14.     ldmia r13,{R0-R4,R7}
  15.     mov pc,lr
  16.     str_p3: .asciz "\nTNND:kernel boot step 0x"
  17.     str_p4:      .asciz     "\n"
  18.  .align
  19. ENDPROC(__right_p)
  20. spbuf1: .space 20
比如: arch/arm/head.S中__create_page_tables
  1. 248 add r0, r4, #(KERNEL_START & 0xff000000) >> 18
  2. 249 
  3. 250 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
  4. 251
想知道L250前后r0, 有没有变化, 加上如下打印(因为是在函数中,所以要保存lr的值)
  1.     mov r6, lr
  2.     bl __right_p
  3.     mov lr, r6
  4. 248 add r0, r4, #(KERNEL_START & 0xff000000) >> 18
  5. 249 
  6.     mov r6, lr
  7.     bl __right_p
  8.     mov lr, r6
  9. 250 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值