bootload启动流程(一)----硬件的初始化和基本配置

来源:互联网 发布:程序员职业规划 知乎 编辑:程序博客网 时间:2024/06/05 00:48

  EBOOT经过NBOOT引导后,一般会跳转到0x30038000开始执行第一条指令。在我这EBOOT中是先执行目录下2440/Kernel/hal/arm/fw.s。这个在有些系统能够中是setup.s,总之就是从系统ResetHandle开始执行了。下面开始分析这段汇编代码,并且讲述它都做了一些什么工作:

     ldr     r0, = INTMSK

         ldr              r1, = ~BIT_BAT_FLT  ; all interrupt disable, nBATT_FLT =enabled

         str     r1, [r0]

 

         ldr              r0, = INTSUBMSK

         ldr              r1, = 0x7ff           ;all sub interrupt disable

         str              r1, [r0]

 

         ldr     r0, = INTMOD

         ldr              r1, = BIT_BAT_FLT   ; set all interrupt as IRQ, BAT_FLT = FIQ

         str     r1, [r0]

 

         ldr    r1, =MISCCR                            ; MISCCR's Bit [22:20] -> 100

         ldr              r0, [r1]

         bic              r0, r0, #(7 << 20)

         bic              r0, r0, #(1 << 3)

         bic              r0, r0, #(1 << 13)

         orr              r0, r0, #(4 << 20)

         str              r0, [r1]

 

         bl      ARMClearUTLB

         bl      ARMFlushICache

         ldr     r0, = (DCACHE_LINES_PER_SET - 1)    

         ldr     r1, = (DCACHE_NUM_SETS - 1)   

         ldr     r2, = DCACHE_SET_INDEX_BIT   

         ldr     r3, = DCACHE_LINE_SIZE    

         bl      ARMFlushDCache   

         nop

         nop

         nop

        

         ldr     r0, = GPFCON

         ldr     r1, = 0x55aa     

         str     r1, [r0]

 

         ldr     r0, = WTCON                  ; watch dog disable

         ldr     r1, = 0x0        

         str     r1, [r0]

//以上代码比较简单,但是很关键,关闭所有中断,刷新cache和快表。后面是点亮LED,禁止看门狗。

[ {TRUE}

         ldr     r0, = CLKDIVN

         ldr     r1, = CLKDIVVAL ; 0x0 = 1:1:1  ,  0x1 = 1:1:2, use CLKDIVVAL instead of 7

                                                                 ; 0x2 = 1:2:2  ,  0x3 = 1:2:4,  0x4 = 1:4:4,  0x5 = 1:4:8, 0x6 = 1:3:3, 0x7 = 1:3:6

         str     r1, [r0]

 

         ands    r1, r1, #0xe             ; Make AsyncBusMode

         beq     %F1

 

         mrc             p15, 0, r0, c1, c0, 0

         orr              r0, r0, #R1_nF:OR:R1_iA

         mcr             p15, 0, r0, c1, c0, 0

1

         ldr              r0, = LOCKTIME                 ; To reduce PLL lock time, adjust the LOCKTIME register.

         ldr              r1, = 0xffffff

         str              r1, [r0]

 

         ldr     r0, = UPLLCON              ; Fin=12MHz, Fout=48MHz

         [ FIN = 12

         ldr     r1, = ((0x38 << 12) + (0x2 << 4) + 0x2) 

         |

         ldr     r1, = ((60 << 12) + (4 << 4) + 0x2) 

         ] 

         str     r1, [r0]

        

         nop   ; Caution: After UPLL setting, at least 7-clocks delay must be inserted for setting hardware be completed.

         nop

         nop

         nop

         nop

         nop

         nop

 

         ldr              r0, = CAMDIVN

         ldr              r1, = 0

         str              r1, [r0]

 

         ldr     r0, = MPLLCON                  ; Configure MPLL ; Fin=12MHz, Fout=50MHz

         ldr     r1, = PLLVAL

         str     r1, [r0]

 

         ]

 

         mov     r0, #0x2000

1      

         subs    r0, r0, #1

         bne     %B1

//以上的也同样简单但是很重要,主要是设置总线时钟比,启动PLLUPLL然后等待有效。

下面的代码也是一些电源管理,检测启动模式(电源启动、睡眠启动还是看门狗启动),最后初始化内存一直到下面的代码:

; :::::::::::::::::::::::::::::::::::::::::::::

;           Add for Power Management

; - - - - - - - - - - - - - - - - - - - - - - -

         tst              r10, #0x2                                                  ; Power-Off reset check

         beq             BringUpWinCE                    ; Normal Mode Booting

如果检测到是正常启动,则跳到BringUpWinCE

BringUpWinCE

 

         ldr              r0, = GPFDAT

         mov            r1, #0x60

         str              r1, [r0]

        

         add             r0, pc, #OEMAddressTable - (. + 8)

 

         bl                KernelStart

到这之后点亮指示灯后将map的头指针给r0后进入内核启动,实际这段代码是nkBoot公用的。这里只讨论boot,所以代码进去了mmu.s:

这个代码在2440/eboot /arm/mmu.s下面:

;   (r10) = 1st level page table

;   (r11) = ptr to MemoryMap array

 

    add r10, r10, #0x2000   ; (r10) = ptr to 1st PTE for "unmapped space"

 

    mov r0, #0x0E       ; (r0) = PTE for 0: 1MB cachable bufferable

    orr r0, r0, #0x400      ; set kernel r/w permission

20  mov r1, r11         ; (r1) = ptr to MemoryMap array

 

       

25  ldr r2, [r1], #4        ; (r2) = virtual address to map Bank at

    ldr r3, [r1], #4        ; (r3) = physical address to map from

    ldr r4, [r1], #4        ; (r4) = num MB to map

 

    cmp r4, #0                  ; End of table?

    beq %F29

 

    ldr r5, =0x1FF00000

    and r2, r2, r5              ; VA needs 512MB, 1MB aligned.               

 

    ldr r5, =0xFFF00000

    and r3, r3, r5              ; PA needs 4GB, 1MB aligned.

 

    add r2, r10, r2, LSR #18

    add r0, r0, r3              ; (r0) = PTE for next physical page

 

28  str r0, [r2], #4

    add r0, r0, #0x00100000     ; (r0) = PTE for next physical page

    sub r4, r4, #1              ; Decrement number of MB left

    cmp r4, #0

    bne %B28                    ; Map next MB

 

    bic r0, r0, #0xF0000000     ; Clear Section Base Address Field

    bic r0, r0, #0x0FF00000     ; Clear Section Base Address Field

    b   %B25                    ; Get next element

       

29  tst r0, #8

    bic r0, r0, #0x0C       ; clear cachable & bufferable bits in PTE

    add r10, r10, #0x0800   ; (r10) = ptr to 1st PTE for "unmapped uncached space"

    bne %B20            ; go setup PTEs for uncached space

    sub r10, r10, #0x3000   ; (r10) = restore address of 1st level page table

 

 

; setup mmu to map (VA == 0) to (PA == 0x30000000)

 

    ldr r0, =PTs        ; PTE entry for VA = 0

    ldr r1, =0x3000040E     ; uncache/unbuffer/rw, PA base == 0x30000000

    str r1, [r0]

 

; uncached area

 

    add r0, r0, #0x0800     ; PTE entry for VA = 0x0200.0000 , uncached

    ldr r1, =0x30000402     ; uncache/unbuffer/rw, base == 0x30000000

    str r1, [r0]

   

; Comment:

; The following loop is to direct map RAM VA == PA. i.e.

;   VA == 0x30XXXXXX => PA == 0x30XXXXXX for S3C2400

; Fill in 8 entries to have a direct mapping for DRAM

 

    ldr r10, =PTs       ; restore address of 1st level page table

    ldr r0,  =PHYBASE

 

    add r10, r10, #(0x3000 / 4) ; (r10) = ptr to 1st PTE for 0x30000000

 

    add r0, r0, #0x1E       ; 1MB cachable bufferable

    orr r0, r0, #0x400      ; set kernel r/w permission

    mov r1, #0

    mov r3, #64

35  mov r2, r1          ; (r2) = virtual address to map Bank at

    cmp r2, #0x20000000:SHR:BANK_SHIFT

    add r2, r10, r2, LSL #BANK_SHIFT-18

    strlo   r0, [r2]

    add r0, r0, #0x00100000 ; (r0) = PTE for next physical page

    subs    r3, r3, #1

    add r1, r1, #1

    bgt %B35

 

    ldr r10, =PTs       ; (r10) = restore address of 1st level page table

 

;

; The page tables and exception vectors are setup. Initialize the MMU and turn

; it on.

 

    mov     r1, #1

    MTC15   r1, c3                  ; setup access to domain 0

    MTC15   r10, c2

    mcr     p15, 0, r0, c8, c7, 0   ; flush I+D TLBs

    mov     r1, #0x0071             ; Enable: MMU

    orr     r1, r1, #0x0004     ; Enable the cache

   

 

    ldr     r0, =VirtualStart

 

    cmp     r0, #0                  ; make sure no stall on "mov pc,r0" below

    MTC15   r1, c1                  ; enable the MMU & Caches

    mov     pc, r0                  ;  & jump to new virtual address

    nop

 

; MMU & caches now enabled.

;

;   (r10) = physcial address of 1st level page table

 

VirtualStart

 

 

    mov sp, #0x8C000000

    add sp, sp, #0x30000    ; arbitrary initial super-page stack pointer

    b   main

 

END

上面的代码实际也很简单,主要工作是初始化页表,这里因为是Boot,所以只初始化了一级页表和开启了mmu。关于这段代码的详细分析我写了一片关于mmu的文章,有兴趣的朋友可以查阅。最后跳转到main(),这里就进入了真正的c代码。(待续。。)