×
单片机 > 单片机程序设计 > 详情

ARM Linux启动分析headarmv.S内幕

发布时间:2020-06-20 发布时间:
|
__create_page_tables:
      pgtbl  r4, r5           @ page table address
 
      /* Clear the 16K level 1 swapper page table */
      mov        r0, r4
      mov        r3, #0
      add        r2, r0, #0x4000
1:    str        r3, [r0], #4
      str        r3, [r0], #4
      str        r3, [r0], #4
      str        r3, [r0], #4
      teq        r0, r2
      bne        1b
 
      /*
       * Create identity mapping for first MB of kernel to
       * cater for the MMU enable. This identity mapping
       * will be removed by paging_init()
       */
      krnladr r2, r4, r5         @ start of kernel
      add         r3, r8, r2         @ flags + kernel base
      str         r3, [r4, r2, lsr #18]    @ identity mapping
 
      /*
       * Now setup the pagetables for our kernel direct
       * mapped region. We round TEXTADDR down to the
       * nearest megabyte boundary.
       */
      add        r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
      bic        r2, r3, #0x00f00000
      str        r2, [r0]         @ PAGE_OFFSET + 0MB
      add        r0, r0, #(TEXTADDR & 0x00f00000) >> 18
      str        r3, [r0], #4        @ KERNEL + 0MB
      add        r3, r3, #1 << 20
      str        r3, [r0], #4        @ KERNEL + 1MB
      add        r3, r3, #1 << 20
      str        r3, [r0], #4        @ KERNEL + 2MB
      add        r3, r3, #1 << 20
      str        r3, [r0], #4        @ KERNEL + 3MB
 
      /*
       * Ensure that the first section of RAM is present.
       * we assume that:
       * 1. the RAM is aligned to a 32MB boundary
       * 2. the kernel is executing in the same 32MB chunk
       *     as the start of RAM.
       */
      bic        r0, r0, #0x01f00000 >> 18 @ round down
      and        r2, r5, #0xfe000000    @ round down
      add        r3, r8, r2       @ flags + rambase
      str        r3, [r0]
 
      bic        r8, r8, #0x0c       @ turn off cacheable
                                  @ and bufferable bits
代码创建页表目录。首先清空从0xA0004000开始的16K页表项。然后,为了可以访问从0xA0000000开始的内核的1M空间,将该地址对应的页表项赋值。接着映射从TEXTADDR开始的4M的虚拟地址空间,这需要4个页表项。最后,由于SDRAM开始的第一MB的空间存放有启动时的一些参数,所以也需要映射。在这里,该映射和前面的虚拟地址的映射在地址上是相等的。
 
在创建页表目录完成后,代码通过前面主程序的最后一句add pc, r10, #12跳转到实际的CPU的设置子程序__xscale_setup。
__xscale_setup:
   mov        r0, #F_BIT|I_BIT|SVC_MODE
   msr        cpsr_c, r0
   mcr        p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB
   mcr     p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer
   mcr        p15, 0, ip, c8, c7, 0     @ invalidate I, D TLBs
   mcr        p15, 0, r4, c2, c0, 0     @ load page table pointer
   mov        r0,  #0x1f       @ Domains 0, 1 = client
   mcr        p15, 0, r0, c3, c0, 0 @ load domain access register
   mov        r0,  #1          @ Allow user space to access
   mcr        p15, 0, r0, c15, c1, 0    @ ... CP 0 only.
#if CACHE_WRITE_THROUGH
   mov        r0, #0x20
#else
   Mov     r0, #0x00
#endif
   mcr        p15, 0, r0, c1, c1, 0     @ set auxiliary control reg
   mrc        p15, 0, r0, c1, c0, 0     @ get control register
   bic     r0,  r0, #0x0200       @ ......R.........
   bic        r0,  r0, #0x0082       @ ........B.....A.
   orr        r0,  r0, #0x0005       @ .............C.M
   orr        r0,  r0, #0x3900       @ ..VIZ..S........
#ifdef CONFIG_XSCALE_CACHE_ERRATA
   bic        r0,  r0, #0x0004       @ see cpu_xscale_proc_init
#endif
   mov     pc,  lr
主要是操作协处理器,设置页表目录项基地址,对CACHE和BUFFER的控制位进行一些操作。具体大家可以看看介绍ARM编程的书。
 
.type __switch_data, %object
__switch_data: .long __mmap_switched
      .long SYMBOL_NAME(__bss_start)
      .long SYMBOL_NAME(_end)
      .long SYMBOL_NAME(processor_id)
      .long SYMBOL_NAME(__machine_arch_type)
      .long SYMBOL_NAME(cr_alignment)
      .long SYMBOL_NAME(init_task_union)+8192
 
      .type __ret, %function
__ret:   ldr   lr, __switch_data
      mcr   p15, 0, r0, c1, c0
      mov   r0, r0
      mov   r0, r0
      mov   r0, r0
      mov   pc, lr
 
      .align 5
__mmap_switched:
      adr   r3, __switch_data + 4
      ldmia r3, {r4, r5, r6, r7, r8, sp} @ r2 = compat
                                          @ sp = stack pointer
 
      mov   fp, #0                @ Clear BSS (and zero fp)
1:    cmp   r4, r5
      strcc fp, [r4],#4
      bcc   1b
 
      str   r9, [r6]              @ Save processor ID
      str   r1, [r7]              @ Save machine type
#ifdef CONFIG_ALIGNMENT_TRAP
      orr   r0, r0, #2            @ ...........A.
#endif
      bic   r2, r0, #2            @ Clear 'A' bit
      stmia r8, {r0, r2}       @ Save control register values
      b SYMBOL_NAME(start_kernel)
最后这段代码的作用主要是在进入C函数前先做一些变量的初始化和保存工作。首先清空BSS区域,然后保存处理器ID和机器类型到各自变量地址,接着保存cr_alignment,最后跳转到init/main.c中的start_kernel函数运行。
 
以上介绍的是head-armv.S文件的主要内容和功能,它是linux运行的第一个文件,具有非常重要的意义。很好的阅读该文件,对于我们理解ARM处理器的工作方式有很大的帮助。同时,在许多linux系统的移植工作中,往往需要对该文件透彻的理解。
关键字:ARM  Linux  启动分析

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式