S3C2410下WinCE6.0的启动过程详解(2)

OAL的启动代码和EBOOT的启动代码经常复用,但为了代码的简洁,最好还是分开实现,而且在EBOOT中如果已经初始化了相关硬件,那么OAL的启动代码就可以省去那部分工作,可以很简练,如上面的代码所示。

可以看出,OAL的启动代码又调用了函数KernelStart(),而这个函数是在文件C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\armstart.s中实现的,代码如下:

Code
LEAF_ENTRY KernelStart

        mov     r11, r0                         ; (r11) = &OEMAddressTable (save pointer)

        ; figure out the virtual address of OEMAddressTable
        mov     r1, r11                         ; (r1) = &OEMAddressTable (2nd argument to VaFromPa)
        bl      VaFromPa
        mov     r6, r0                          ; (r6) = VA of OEMAddressTable

        ; convert base of PTs to Physical address
        ldr     r4, =PTs                        ; (r4) = virtual address of FirstPT
        mov     r0, r4                          ; (r0) = virtual address of FirstPT
        mov     r1, r11                         ; (r1) = &OEMAddressTable (2nd argument to PaFromVa)
        bl      PaFromVa

        mov     r10, r0                         ; (r10) = ptr to FirstPT (physical)

;       Zero out page tables & kernel data page

        mov     r0, #0                          ; (r0-r3) = 0's to store
        mov     r1, #0
        mov     r2, #0
        mov     r3, #0
        mov     r4, r10                         ; (r4) = first address to clear
        add     r5, r10, #KDEnd-PTs             ; (r5) = last address + 1
18      stmia   r4!, {r0-r3}
        stmia   r4!, {r0-r3}
        cmp     r4, r5
        blo     %B18

        ; read the architecture information
        bl      GetCpuId
        mov     r5, r0 LSR #16                  ; r5 >>= 16
        and     r5, r5, #0x0000000f             ; r5 &= 0x0000000f == architecture id
       
;       Setup 2nd level page table to map the high memory area which contains the
; first level page table, 2nd level page tables, kernel data page, etc.
;       (r5) = architecture id

        add     r4, r10, #HighPT-PTs            ; (r4) = ptr to high page table

        cmp     r5, #ARMv6                      ; v6 or later?
; ARMV6_MMU
        orrge   r0, r10, #PTL2_KRW + PTL2_SMALL_PAGE + ARMV6_MMU_PTL2_SMALL_XN
                                                ; (r0) = PTE for 4K, kr/w u-/- page, uncached unbuffered, nonexecutable
; PRE ARMV6_MMU
        orrlt   r0, r10, #PTL2_KRW + (PTL2_KRW << 2) + (PTL2_KRW << 4) + (PTL2_KRW << 6)
                                                ; Need to replicate AP bits into all 4 fields
        orrlt   r0, r0,  #PTL2_SMALL_PAGE + PREARMV6_MMU_PTL2_SMALL_XN
                                                ; (r0) = PTE for 4K, kr/w u-/- page, uncached unbuffered, nonexecutable
        str     r0, [r4, #0xD0*4]               ; store the entry into 4 slots to map 16K of primary page table
        add     r0, r0, #0x1000                 ; step on the physical address
        str     r0, [r4, #0xD1*4]
        add     r0, r0, #0x1000                 ; step on the physical address
        str     r0, [r4, #0xD2*4]
        add     r0, r0, #0x1000                 ; step on the physical address
        str     r0, [r4, #0xD3*4]

        add     r8, r10, #ExceptionVectors-PTs  ; (r8) = ptr to vector page
        orr     r0, r8, #PTL2_SMALL_PAGE        ; construct the PTE (C=B=0)

;; The exception stacks and the vectors are mapped as a single kr/w page.
;; Any alternative will use more physical memory.
;; Multiple mappings don't provide any real protection: if the vectors were in a r/o page,
;; they could still be corrupted via the kr/w setting required for the stacks.
        cmp     r5, #ARMv6                      ; v6 or later?
; ARMV6_MMU 
        orrge   r0, r0, #PTL2_KRW
; PRE ARMV6_MMU
        orrlt   r0, r0, #PTL2_KRW + (PTL2_KRW << 2) + (PTL2_KRW << 4) + (PTL2_KRW << 6)
                                                ; Need to replicate AP bits into all 4 fields for pre-V6 MMU

        str     r0, [r4, #0xF0*4]               ; store entry for exception stacks and vectors
                                                ; other 3 entries now unused

        add     r9, r10, #KPage-PTs             ; (r9) = ptr to kdata page
        orr     r0, r9, #PTL2_SMALL_PAGE        ; (r0)=PTE for 4K (C=B=0)
       
; ARMV6_MMU (condition codes still set)
        orrge   r0, r0, #PTL2_KRW_URO           ; No subpage access control, so we must set this all to kr/w+ur/o
; PRE ARMV6_MMU
        orrlt   r0, r0, #(PTL2_KRW << 0) + (PTL2_KRW << 2) + (PTL2_KRW_URO << 4)
                                                ; (r0) = set perms kr/w kr/w kr/w+ur/o r/o
        str     r0, [r4, #0xFC*4]               ; store entry for kernel data page
        orr     r0, r4, #PTL1_2Y_TABLE          ; (r0) = 1st level PTE for high memory section
        add     r1, r10, #0x4000
        str     r0, [r1, #-4]                   ; store PTE in last slot of 1st level table

;       Fill in first level page table entries to create "statically mapped" regions
; from the contents of the OEMAddressTable array.
;
;       (r5) = architecture id
;       (r9) = ptr to KData page
;       (r10) = ptr to 1st level page table
;       (r11) = ptr to OEMAddressTable array

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

        mov     r0, #PTL1_SECTION
        orr     r0, r0, #PTL1_KRW               ; (r0)=PTE for 0: 1MB (C=B=0, kernel r/w)
20      mov     r1, r11                         ; (r1) = ptr to OEMAddressTable array (physical)


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     r12, =0x1FF00000
        and     r2, r2, r12                      ; VA needs 512MB, 1MB aligned.

        ldr     r12, =0xFFF00000
        and     r3, r3, r12                      ; 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
        sub     r10, r10, #0x2000               ; (r10) = restore address of 1st level page table

        ; The minimal page mappings are setup. Initialize the MMU and turn it on.

        ; there are some CPUs with pipeline issues that requires identity mapping before turning on MMU.
        ; We'll create an identity mapping for the address we'll jump to when turning on MMU on and remove
        ; the mapping after we turn on MMU and running on Virtual address.
       

        ldr     r12, =0xFFF00000                ; (r12) = mask for section bits
        and     r1, pc, r12                     ; physical address of where we are 
                                                ; NOTE: we assume that the KernelStart function never spam across 1M boundary.
        orr     r0, r1, #PTL1_SECTION
        orr     r0, r0, #PTL1_KRW               ; (r0) = PTE for 1M for current physical address, C=B=0, kernel r/w
        add     r7, r10, r1, LSR #18            ; (r7) = 1st level PT entry for the identity map
        ldr     r8, [r7]                        ; (r8) = saved content of the 1st-level PT
        str     r0, [r7]                        ; create the identity map

        mov     r1, #1
        mtc15   r1, c3                          ; Setup access to domain 0 and clear other
        mtc15   r10, c2                         ; setup translation base (physical of 1st level PT)

        mov     r0, #0
        mcr     p15, 0, r0, c8, c7, 0           ; Flush the I&D TLBs

        mfc15   r1, c1
        orr     r1, r1, #0x007F                 ; changed to read-mod-write for ARM920 Enable: MMU, Align, DCache, WriteBuffer

        cmp     r5, #ARMv6                      ; r5 still set       
; ARMV6_MMU
        orrge   r1, r1, #0x3000                 ; vector adjust, ICache
        orrge   r1, r1, #1<<23                  ; V6-format page tables
        orrge   r1, r1, #ARMV6_U_BIT            ; V6-set U bit, let A bit control unalignment support
; PRE ARMV6_MMU
        orrlt   r1, r1, #0x3200                 ; vector adjust, ICache, ROM protection

        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
;       (r7)  = entry in 1st level PT for identity map
;       (r8)  = saved 1st level PT save at (r7)
VStart  ldr     r2, =FirstPT                    ; (r2) = VA of 1st level PT
        sub     r7, r7, r10                     ; (r7) = offset into 1st-level PT
        str     r8, [r2, r7]                    ; restore the temporary identity map
        mcr     p15, 0, r0, c8, c7, 0           ; Flush the I&D TLBs

;
; setup stack for each modes: current mode = supervisor mode
;
        ldr     sp, =KStack
        add     r4, sp, #KData-KStack           ; (r4) = ptr to KDataStruct

        ; setup ABORT stack
        mov     r1, #ABORT_MODE:OR:0xC0
        msr     cpsr_c, r1                      ; switch to Abort Mode w/IRQs disabled
        add     sp, r4, #AbortStack-KData

        ; setup IRQ stack
        mov     r2, #IRQ_MODE:OR:0xC0
        msr     cpsr_c, r2                      ; switch to IRQ Mode w/IRQs disabled
        add     sp, r4, #IntStack-KData

        ; setup FIQ stack
        mov     r3, #FIQ_MODE:OR:0xC0
        msr     cpsr_c, r3                      ; switch to FIQ Mode w/IRQs disabled
        add     sp, r4, #FIQStack-KData

        ; setup UNDEF stack
        mov     r3,  #UNDEF_MODE:OR:0xC0
        msr     cpsr_c, r3                      ; switch to Undefined Mode w/IRQs disabled
        mov     sp, r4                          ; (sp_undef) = &KData

        ; switch back to Supervisor mode
        mov     r0, #SVC_MODE:OR:0xC0
        msr     cpsr_c, r0                      ; switch to Supervisor Mode w/IRQs disabled
        ldr     sp, =KStack

        ; continue initialization in C
        add     r0, sp, #KData-KStack           ; (r0) = ptr to KDataStruct
        str     r6, [r0, #pAddrMap]             ; store VA of OEMAddressTable in KData
        bl      ARMInit          ; call C function to perform the rest of initializations
        ; upon return, (r0) = entry point of kernel.dll

        mov     r12, r0
        ldr     r0, =KData
        mov     pc, r12     ; jump to entry of kernel.dll

从上面的代码可以看出,KernelStart()通过OEMAddressTable初始化了MMU,然后通过调用函数ARMInit()获得kernel.dll的入口点,最后跳转到kernel.dll的入口点处。

为了找到Kernel.dll的入口点,用IDA反汇编kernel.dll文件,可以看到,Kernel.dll的入口点为NKStartup。

NKStartup()的实现在文件C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\ mdarm.c中,代码如下: 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/392d14ee7c46bd4a232f80e3976d6e8b.html