boot整体结构、移植步骤以及启动代码分析

本篇文章首先介绍u-boot的整体代码结构,移植的基本步骤,然后分析启动的代码(start.S)中
其中代码结构和移植步骤是参考了下面两个连接的文章,作者是 焦玉全 黄乡生 鲍玉军,题目是
第7540篇:U-Boot在S3C2410上的移植(具体URL忘了,我文章是下载的,知道的朋友告诉一声)
一、整体结构
首先下载u-boot的源代码(),解压缩,你可以看到下面的目录:
- board 目标板相关文件,主要包含SDRAM、FLASH驱动;
- common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;
- cpu 与处理器相关的文件。如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
- driver 通用设备驱动,如CFI FLASH驱动(目前对INTEL FLASH支持较好)
- doc U-Boot的说明文档;
- examples可在U-Boot下运行的示例程序;如hello_world.c,timer.c;
- include U-Boot头文件;尤其configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
- lib_xxx 处理器体系相关的文件,如lib_ppc, lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
- net 与网络功能相关的文件目录,如bootp,nfs,tftp;
- post 上电自检文件目录。尚有待于进一步完善;
- rtc RTC驱动程序;
- tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具;

二、移植步骤

为了使U-Boot支持新的开发板,一种简便的做法是在U-Boot已经支持的开发板中选择一种和目标板接近的,并在其基础上进行修改。代码修改的步骤如下:
1)在board目录下创建smdk2410目录,添加smdk2410.c、flash.c、memsetup.s、u-boot.lds和config.mk等;
2)在cpu目录下创建arm920t目录,主要包含start.s、interrupts.c、cpu.c、serial.c和speed.c等文件;
3)在include/configs目录下添加smdk2410.h,它定义了全局的宏定义等;
4)修改u-boot根目录下的Makefile文件:
smdk2410_config : unconfig@./mkconfig $(@:_config=) arm arm920t smdk2410
5)运行make smdk2410_config,如果没有错误,就可以开始进行与硬件相关的代码移植工作。由于这部分代码与硬件紧密相关,所以要熟悉开发板的硬件配置,可参考各芯片的用户手册。

    当然,这个是一般步骤,后面我们做的可能具体文件名还和这个不一样,等到那时候在交待,这里先介绍的目的是在开始的时候给个大概的思路,要不直接分析源代码,有点在原始森林的感觉,耐心的看吧:)

三、start.S分析
首先介绍start.S中的代码的具体作用,由于该代码是系统最开始执行的,这时,u-boot对系统一无所知,必须要初始化一些东西,比如设置异常的入口地址和异常处理函数;配置PLLCON寄存器,确定系统的主频;屏蔽看门狗和中断;初始化I/O寄存器;关闭MMU功能;调用 /board/smdk2410中的memsetup.s,初始化存储器空间,设置刷新频率;将U-Boot的内容复制到SDRAM中;设置堆栈的大小, 然后ldr pc, _start_armboot,跳到C函数

代码来自华恒的板子上面的资料

/* CPU clcok */
/* 50.00 MHz */
#define MDIV_50                 0x5c
#define PDIV_50                 0x4
#define SDIV_50                 0x2

/* 100.00 MHz */
#define MDIV_100        0xa1
#define PDIV_100        0x3
#define SDIV_100        0x1

/* 200.00 MHz */
/*CPU clock = 202.800000 Mhz, HCLK = 101.400000 Mhz, PCLK = 50.700000 Mhz*/
/*0xa1  3  1*/
/*180Mhz 90Mhz 45Mhz  0x52  1  1*/
/*152MHZ              0x44 1   1*/
#define MDIV_200                0xa1
#define PDIV_200                0x3
#define SDIV_200                0x1


#define vMPLLCON_50             ((MDIV_50 << 12) | (PDIV_50 << 4) | (SDIV_50))
#define vMPLLCON_100        ((MDIV_100 << 12) | (PDIV_100 << 4) | (SDIV_100))
#define vMPLLCON_200        ((MDIV_200 << 12) | (PDIV_200 << 4) | (SDIV_200))

/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */


.globl _start
_start:    b       reset======================================〉程序从这里开始
    ldr    pc, _undefined_instruction
    ldr    pc, _software_interrupt
    ldr    pc, _prefetch_abort
    ldr    pc, _data_abort
    ldr    pc, _not_used
    ldr    pc, _irq
    ldr    pc, _fiq

_undefined_instruction:    .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:        .word not_used
_irq:            .word irq
_fiq:            .word fiq

    .balignl 16,0xdeadbeef


/*
 *************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

/*
 * CFG_MEM_END is in the board dependent config-file (configs/config_BOARD.h)
 */
_TEXT_BASE:
    .word    TEXT_BASE

.globl _armboot_start
_armboot_start:
    .word _start

/*
 * Note: _armboot_end_data and _armboot_end are defined
 * by the (board-dependent) linker script.
 * _armboot_end_data is the first usable FLASH address after armboot
 */
.globl _armboot_end_data
_armboot_end_data:
    .word armboot_end_data
.globl _armboot_end
_armboot_end:
    .word armboot_end

/*
 * _armboot_real_end is the first usable RAM address behind armboot
 * and the various stacks
 */
.globl _armboot_real_end
_armboot_real_end:
    .word 0x0badc0de

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
    .word    0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
    .word 0x0badc0de
#endif


/*
 * the actual reset code
 */

reset:=============================================〉程序开始的时候跳转到这里

    ldr     r0, =pWTCON
    mov     r1, #0x0
    str     r1, [r0];0x0写到0x53000000地址上,其实该地址是看门狗的控制寄存器,该指令就是关闭看门狗,具体对应位请看2410的用户手册。

    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov    r1, #0xffffffff
    ldr    r0, =INTMSK
    str    r1, [r0];将0xffffffff写到INTMSK代表的地址上,屏蔽中断
#if defined(CONFIG_S3C2410)
    ldr    r1, =0x7ff
    ldr    r0, =INTSUBMSK
    str    r1, [r0];对于2410还要设置此寄存器
#endif

        @ initialise system clocks;下面没什么要讲的,具体参看2410的用户手册
        mov     r1, #CLK_CTL_BASE
        mvn     r2, #0xff000000
        str     r2, [r1, #0x0]  /*oLOCKTIME*/

        @ldr    r2, mpll_50mhz
        @str    r2, [r1, #0x4]  /*oMPLLCON*/

        mov     r1, #CLK_CTL_BASE
/*        mov     r2, #0x3*/
        mov     r2, #0x3
        str     r2, [r1, #0x14]            /*oCLKDIVN*/

        mrc     p15, 0, r1, c1, c0, 0           @ read ctrl register
        orr     r1, r1, #0xc0000000             @ Asynchronous
        mcr     p15, 0, r1, c1, c0, 0           @ write ctrl register


        @ now, CPU clock is 200 Mhz
        mov     r1, #CLK_CTL_BASE
        ldr     r2, mpll_200mhz
        str     r2, [r1, #0x4]               /*oMPLLCON*/

    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
#ifdef CONFIG_INIT_CRITICAL
    bl    cpu_init_crit ;跳到下面的子过程
#endif

relocate:;下面代码的��用是把u-boot的后续代码搬运到内存中
    /*
     * relocate armboot to RAM
     */
    adr    r0, _start        /* r0 <- current position of code */
    ldr    r2, _armboot_start
    ldr    r3, _armboot_end
    sub    r2, r3, r2        /* r2 <- size of armboot */
    ldr    r1, _TEXT_BASE        \board\smdk2410\config.mk中定义了_TEXT_BASE,表示把u-boot搬到内存中的相应位置,在这里是0x33F00000,相对于0x30000000来说是63MB的地方,朋友们可能要疑惑了,前面的文章不是介绍了我们用的板子是32M内存吗?那怎么是63M的地方呢,其实2410支持地址循环,这里其实就是31M的地方,哈哈,那u-boot不是把自己放在SDRAM中的最高的地方吗?的确是这样的。

    add    r2, r0, r2        /* r2 <- source end address */

    /*
     * r0 = source address
     * r1 = target address
     * r2 = source end address
     */
copy_loop:;开始拷贝
    ldmia    r0!, {r3-r10}
    stmia    r1!, {r3-r10}
    cmp    r0, r2
    ble    copy_loop

    /* set up the stack */;最后我们在u-boot之后建立堆栈,为C语言的执行创建环境,否则是不允许执行C程序的,大小为128*1024
    ldr    r0, _armboot_end
    add    r0, r0, #CONFIG_STACKSIZE 该宏在\include\configs\smdk2410.h中定义
    sub    sp, r0, #12        /* leave 3 words for abort-stack */

    ldr    pc, _start_armboot

_start_armboot:    .word start_armboot;跳转到/lib_arm/board.c中的start_armboot()函数中运行了,到此我们完成了第一阶段,初始汇编代码的运行


/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */


cpu_init_crit:
    /*
     * flush v4 I/D caches ;意思很明白不是?
     */
    mov    r0, #0
    mcr    p15, 0, r0, c7, c7, 0    // flush v3/v4 cache
    mcr    p15, 0, r0, c8, c7, 0    // flush v4 TLB

    /*
     * disable MMU stuff and caches
     */
    mrc    p15, 0, r0, c1, c0, 0
    bic    r0, r0, #0x00002300    @ clear bits 13, 9:8 (--V- --RS)
    bic    r0, r0, #0x00000087    @ clear bits 7, 2:0 (B--- -CAM)
    orr    r0, r0, #0x00000002    @ set bit 2 (A) Align
    orr    r0, r0, #0x00001000    @ set bit 12 (I) I-Cache
    mcr    p15, 0, r0, c1, c0, 0


    /*
     * before relocating, we have to setup RAM timing
     * because memory timing is board-dependend, you will
     * find a memsetup.S in your board directory.
     */
    mov    ip, lr
    bl    memsetup ==〉上面英文注释就是,在重新定位之前,要初始化RAM,以及设置刷新频率
我们在本文的最后插上memsetup.S的代码。
    mov    lr, ip

    mov    pc, lr返回,并且回到上面,进行重定位




/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE    72

#define S_OLD_R0    68
#define S_PSR        64
#define S_PC        60
#define S_LR        56
#define S_SP        52

#define S_IP        48
#define S_FP        44
#define S_R10        40
#define S_R9        36
#define S_R8        32
#define S_R7        28
#define S_R6        24
#define S_R5        20
#define S_R4        16
#define S_R3        12
#define S_R2        8
#define S_R1        4
#define S_R0        0

#define MODE_SVC 0x13
#define I_BIT     0x80

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */

    .macro    bad_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0-r12
    add     r8, sp, #S_PC

    ldr    r2, _armboot_end
    add    r2, r2, #CONFIG_STACKSIZE
    sub    r2, r2, #8
    ldmia    r2, {r2 - r4}                   @ get pc, cpsr, old_r0
    add    r0, sp, #S_FRAME_SIZE        @ restore sp_SVC

    add    r5, sp, #S_SP
    mov    r1, lr
    stmia    r5, {r0 - r4}                   @ save sp_SVC, lr_SVC, pc, cpsr, old_r
    mov    r0, sp
    .endm

    .macro    irq_save_user_regs
    sub    sp, sp, #S_FRAME_SIZE
    stmia    sp, {r0 - r12}            @ Calling r0-r12
    add     r8, sp, #S_PC
    stmdb   r8, {sp, lr}^                   @ Calling SP, LR
    str     lr, [r8, #0]                    @ Save calling PC
    mrs     r6, spsr
    str     r6, [r8, #4]                    @ Save CPSR
    str     r0, [r8, #8]                    @ Save OLD_R0
    mov    r0, sp
    .endm

    .macro    irq_restore_user_regs
    ldmia    sp, {r0 - lr}^            @ Calling r0 - lr
    mov    r0, r0
    ldr    lr, [sp, #S_PC]            @ Get PC
    add    sp, sp, #S_FRAME_SIZE
    subs    pc, lr, #4            @ return & move spsr_svc into cpsr
    .endm

    .macro get_bad_stack
    ldr    r13, _armboot_end        @ setup our mode stack
    add    r13, r13, #CONFIG_STACKSIZE    @ resides at top of normal stack
    sub    r13, r13, #8

    str    lr, [r13]            @ save caller lr / spsr
    mrs    lr, spsr
    str     lr, [r13, #4]

    mov    r13, #MODE_SVC            @ prepare SVC-Mode
    @ msr    spsr_c, r13
    msr    spsr, r13
    mov    lr, pc
    movs    pc, lr
    .endm

    .macro get_irq_stack            @ setup IRQ stack
    ldr    sp, IRQ_STACK_START
    .endm

    .macro get_fiq_stack            @ setup FIQ stack
    ldr    sp, FIQ_STACK_START
    .endm

/*
 * exception handlers
 */
    .align  5
undefined_instruction:
    get_bad_stack
    bad_save_user_regs
    bl     do_undefined_instruction

    .align    5
software_interrupt:
    get_bad_stack
    bad_save_user_regs
    bl     do_software_interrupt

    .align    5
prefetch_abort:
    get_bad_stack
    bad_save_user_regs
    bl     do_prefetch_abort

    .align    5
data_abort:
    get_bad_stack
    bad_save_user_regs
    bl     do_data_abort

    .align    5
not_used:
    get_bad_stack
    bad_save_user_regs
    bl     do_not_used

#ifdef CONFIG_USE_IRQ

    .align    5
irq:
    get_irq_stack
    irq_save_user_regs
    bl     do_irq
    irq_restore_user_regs

    .align    5
fiq:
    get_fiq_stack
    /* someone ought to write a more effiction fiq_save_user_regs */
    irq_save_user_regs
    bl     do_fiq
    irq_restore_user_regs

#else

    .align    5
irq:
    get_bad_stack
    bad_save_user_regs
    bl     do_irq

    .align    5
fiq:
    get_bad_stack
    bad_save_user_regs
    bl     do_fiq

#endif
@ Processor clock values
.align 4
mpll_50mhz:
        .long   vMPLLCON_50
mpll_100mhz:
        .long   vMPLLCON_100
mpll_200mhz:
        .long   vMPLLCON_200

    .align    5
.globl reset_cpu
reset_cpu:
#ifdef CONFIG_S3C2400
    bl    disable_interrupts
    ldr    r1, _rWTCON
    ldr    r2, _rWTCNT
    /* Disable watchdog */
    mov    r3, #0x0000
    str    r3, [r1]
    /* Initialize watchdog timer count register */
    mov    r3, #0x0001
    str    r3, [r2]
    /* Enable watchdog timer; assert reset at timer timeout */
    mov    r3, #0x0021
    str    r3, [r1]
_loop_forever:
    b    _loop_forever
_rWTCON:
    .word    0x15300000
_rWTCNT:
    .word    0x15300008
#else /* ! CONFIG_S3C2400 */
    mov     ip, #0
    mcr     p15, 0, ip, c7, c7, 0           @ invalidate cache
    mcr     p15, 0, ip, c8, c7, 0           @ flush TLB (v4)
    mrc     p15, 0, ip, c1, c0, 0           @ get ctrl register
    bic     ip, ip, #0x000f                 @ ............wcam
    bic     ip, ip, #0x2100                 @ ..v....s........
    mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
    mov     pc, r0
#endif /* CONFIG_S3C2400 */
/////////////////////////////////////////////////////////////////////
start.S到此结束


//下面就是初始化内存的代码
/board/smdk2410/memsetup.S
memsetup:
    /* memory control configuration */
    /* make r0 relative the current location so that it */
    /* reads SMRDATA out of FLASH rather than memory ! */
    ldr     r0, =SMRDATA
    ldr    r1, _TEXT_BASE
    sub    r0, r0, r1
    ldr    r1, =BWSCON    /* Bus Width Status Controller */
    add     r2, r0, #13*4
0:
    ldr     r3, [r0], #4
    str     r3, [r1], #4
    cmp     r2, r0
    bne     0b

    /* everything is fine now */
    mov    pc, lr

    .ltorg
/* the literal pools origin */

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x31
    .word 0x30
    .word 0x30


下篇文章, 我们主要分析start_armboot()函数的主要作用,其实该函数就是进行一系列的硬件初始化,然后进入main_loop,等待用户的命令,或者直接默认加载Linux内核,启动Linux,好了今天就到这吧,该休息了:)

linux

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

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