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

时间:2021-04-06 16:38:33
首先有如下定义
  include/asm/memory.h中
  #define PAGE_OFFSET        UL(0xc0000000)

  arch/arm/Makefile
  TEXT_OFFSET=0x00008000  // 95 textofs-y   := 0x00008000 //153 TEXT_OFFSET := $(textofs-y)

  1.  include/asm-arm/arch-s3c2410/memory.h 
  2.  14 #define PHYS_OFFSET UL(0x30000000)

  3.  arch/arm/kernel/head.S中
  4.  29 #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)        //0xc0008000 //3G都说内核的虚地址是3G,就是这么来的
  5.  30 #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)        //0x30008000
  6.  55 #define KERNEL_START    KERNEL_RAM_VADDR                    //0xc0008000
     56 #define KERNEL_END      _end
此时寄存器如下:
 * r8  = machinfo
 * r9  = cpuid
 * r10 = procinfo

一、在arch/arm/kernel/head.S中 create_page_table
214 .type __create_page_tables, %function
  1. 215 __create_page_tables:
  2. 216 pgtbl r4             @ page table address         //将页表基地址(0x30004000)存入r4中
  3. 217 
  4. 218 /*
  5. 219 * Clear the 16K level 1 swapper page table          //L221-L229:将页表基地址到页表结束地址(0x30004000--0x30008000)清零
  6. 220 */
  7. 221 mov r0, r4
  8. 222 mov r3, #0
  9. 223 add r6, r0, #0x4000
  10. 224 1: str r3, [r0], #4
  11. 225 str r3, [r0], #4
  12. 226 str r3, [r0], #4
  13. 227 str r3, [r0], #4
  14. 228 teq r0, r6
  15. 229 bne 1b
  16. 230                                                                     //L231-L241 配置内核页表项,寄存器:r3=0x0, r4=页表基地址(0x30004000), r6,r7临时变量  
    231 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS]    @ mm_mmuflags               //L231 从proc_info中得到的页表项的标志赋给r7,标志在arch/arm/mm/proc-arm920.S
  17. 239 mov r6, pc, lsr #20                     @ start of kernel section   //L232 pc>>20即pc/1M(每个页表项表示了1M的内存空间), pc/1M的结果表示了:内核地址是在页表(数组)中的第几项(索引)
    240 orr r3, r7, r6, lsl #20                 @ flags + kernel base       //L240 r7是页表项的标志位, r6是页表项的基地址,将r6与r7合并组成了一个完整的页表项r3
    241 str r3, [r4, r6, lsl #2]                @ identity mapping          //L241 r4是页表基地址,r6是页表(数组)中的索引,因为每一个页表项是4字节,所以内核所在的页表地址是: r4+r6*4
  18.                                                                         //L241 即0x30004000+0x300*4=0x30004C00, 把完整的页表项的内容r3存到r4+r6*4(0x30004C00)处
    242 
    243 /*
    244  * Now setup the pagetables for our kernel direct
    245  * mapped region.
    246  */                                                                //L247-248 填充虚拟内核页表(0xc0008000)的第0项; L249-L255填充剩余的所有虚拟页表项
    247 add r0, r4,  #(KERNEL_START & 0xff000000) >> 18                    //L247 将KERNEL_START=0xc0008000映射到r0=r4+offset=0x30007000
    248 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!                  //L248 将页表项的内容r3存到0x30007000处(KERNEL_START&0x00F00000为0),映射完第0项 
    249 ldr r6, =(KERNEL_END - 1)                                          //L249 KERNEL的结束地址存入r6
    250 add r0, r0, #4                                                     //L250 r0=r0+4即r0指向下一个页表项
    251 add r6, r4, r6, lsr #18                                            //L251 r6=r4+r6 即r6内核页表项的结束地址
    252 1:  cmp r0, r6                                                     //L252-L255 循环: 比较是否己到结束地址,将内核页表项的4字节填充
    253     add r3, r3, #1 << 20                                           //L253 1个页表项代表了1M内存,当填充下一个页表项时刚好需要填充在页表项的第20位,所以这儿只需将bit2加1即可
    254     strls   r3, [r0], #4                                           //L254 将更新后的内容填充到页表项地址中
    255     bls 1b                                                         //L255
    256 
    .....
    275 
    276     /*
    277      * Then map first 1MB of ram in case it contains our boot params.
    278      */
    279     add r0, r4, #PAGE_OFFSET >> 18                                //L279 PAGE_OFFSET=0xc000000,r0即PAGE_OFFSET所在页表项的地址
    280     orr r6, r7, #(PHYS_OFFSET & 0xff000000)                       //L280-284填充,原理同上  
    281     .if (PHYS_OFFSET & 0x00f00000)
    282     orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
    283     .endif
    284     str r6, [r0]
    285 
    ...
    327     mov pc, lr
    328     .ltorg

在arch/arm/kernel/head.S中定义了pgtbl宏
  1.  47 .macro pgtbl, rd
  2.  48 ldr \rd, =(KERNEL_RAM_PADDR - 0x4000)
  3.  49 .endm
0x30008000-0x4000=0x30004000

附录:
     1. macro指令格式如下:
         .macro      //定义一个宏: 名字是macro_name; 参数是macro_param
           body
          .endm                                                        //endm结束标志