• uboot1.1.6 start.s分析


    大多数bootloader都分为stage1stage2两部分,u-boot也不例外。依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在stage1且可以用汇编语言来实现,而stage2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
    1Stage1 start.S代码结构 
    u-bootstage1代码通常放在start.S文件中,他用汇编语言写成,其主要代码部分如下:
    1)定义入口。由于一个可执行的Image必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROMFlash)的0x0地址,因此,必须通知编译器以使其知道这个入口,该工作可通过修改连接器脚本来完成。
    2)设置异常向量(Exception Vector)。
    3)设置CPU的速度、时钟频率及终端控制寄存器。
    4)初始化内存控制器。
    5)将ROM中的程序复制到RAM中。
    6)初始化堆栈。
    7)转到RAM中执行,该工作可使用指令ldr pc来完成。
    2Stage2 C语言代码部分
    lib_arm/board.c中的start arm bootC语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-bootarmboot)的主函数,该函数只要完成如下操作:
    1)调用一系列的初始化函数。
    2)初始化Flash设备。
    3)初始化系统内存分配函数。
    4)如果目标系统拥有NAND设备,则初始化NAND设备。
    5)如果目标系统有显示设备,则初始化该类设备。
    6)初始化相关网络设备,填写IPMAC地址等。
    7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。

    注:

    ARM微处理器支持字节(8位)、半字(16位)、字(32位)3种数据类型
    @向量跳转表,每条占四个字节(一个字),地址范围为0x0000 0000~@0x0000 0020
    @ARM体系结构规定在上电复位后的起始位置,必须有8条连续的跳

    @转指令,通过硬件实现。他们就是异常向量表。ARM在上电复位后,@是从0x00000000开始启动的,其实如果bootloader存在,在执行

    @下面第一条指令后,就无条件跳转到start_code,下面一部分并没@执行。设置异常向量表的作用是识别bootloader。以后系统每当有@异常出现,则CPU会根据异常号,从内存的0x00000000处开始查表@做相应的处理

    /******************************************************

    ;当一个异常出现以后,ARM会自动执行以下几个步骤:
    ;1.把下一条指令的地址放到连接寄存器LR(通常是R14).---保存位置

    ;2.将相应的CPSR(当前程序状态寄存器)复制到SPSR(备份的程序状态寄存器)中---保存CPSR
    ;3.根据异常类型,强制设置CPSR的运行模式位

    ;4.强制PC(程序计数器)从相关异常向量地址取出下一条指令执行,从而跳转到相应的异常处理程序中
    *********************************************************/

    /*
    * armboot - Startup Code for ARM920 CPU-core
    *
    * Copyright (c) 2001 Marius Gr鰃er <mag@sysgo.de>
    * Copyright (c) 2002 Alex Z黳ke <azu@sysgo.de>
    * Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
    *
    * See file CREDITS for list of people who contributed to this
    * project.
    *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License as
    * published by the Free Software Foundation; either version 2 of
    * the License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU General Public License for more details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program; if not, write to the Free Software
    * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
    * MA 02111-1307 USA
    */


    #include <config.h>
    #include <version.h>


    /*
    *************************************************************************
    *
    * 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

    @对于ARM数据从内存到CPU之间的移动只能通过L/S指令,如:ldr r0,0x12345678为把0x12345678内存中的数据写到r0中,还有一个就是ldr伪指令,如:ldr r0,=0x12345678为把0x12345678地址写到r0中,mov只能完成寄存器间数据的移动,而且立即数长度限制在8位

    _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

    @.balignl是.balign的变体

    @ .align伪操作用于表示对齐方式:通过添加填充字节使当前位置

    @满足一定的对齐方式。.balign的作用同.align
    @ .align {alignment} {,fill} {,max}
    @  其中:alignment用于指定对齐方式,可能的取值为2的次

    @幂,缺省为4fill是填充内容,缺省用0填充。max是填充字节@数最大值,如果填充字节数超过max,  就不进行对齐,例如:
    @  .align 4  /* 指定对齐方式为字对齐 */


    /*
    *************************************************************************
    *
    * 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
    *
    *************************************************************************
    */

    _TEXT_BASE:
    .word TEXT_BASE

    .globl _armboot_start
    _armboot_start:
    .word _start

    /*
    * These are defined in the board-specific linker script.
    */
    .globl _bss_start
    _bss_start:
    .word __bss_start

    .globl _bss_end
    _bss_end:
    .word _end

    #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:
    /*
    * set the cpu to SVC32 mode
    */

    @更改处理器模式为管理模式
    @对状态寄存器的修改要按照:读出-修改-写回的顺序来执行
    @
        31 30 29 28 ---   7   6   -   4    3   2   1   0
        N  Z  C  V        I   F       M4  M3  M2 M1 M0
                                       0   0   0  0   0     User26 模式
                                       0   0   0  0   1     FIQ26 模式
                                       0   0   0  1   0     IRQ26 模式
                                       0   0   0  1   1     SVC26 模式
                                       1   0   0  0   0     User 模式
                                       1   0   0  0   1     FIQ 模式
                                       1   0   0  1   0     IRQ 模式
                                       1   0   0  1   1     SVC 模式
                                       1   0   1  1   1     ABT 模式
                                       1   1   0  1   1     UND 模式
                                       1   1   1  1   1     SYS 模式

    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0

    /* turn off the watchdog */
    #if defined(CONFIG_S3C2400)
    # define pWTCON 0x15300000
    # define INTMSK 0x14400008 /* Interupt-Controller base addresses */
    # define CLKDIVN 0x14800014 /* clock divisor register */
    #elif defined(CONFIG_S3C2410)
    # define pWTCON 0x53000000
    # define INTMSK 0x4A000008 /* Interupt-Controller base addresses */
    # define INTSUBMSK 0x4A00001C
    # define CLKDIVN 0x4C000014 /* clock divisor register */
    #endif

    #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
    ldr r0, =pWTCON
    mov r1, #0x0
    str r1, [r0]

    /*
    * mask all IRQs by setting all bits in the INTMR - default
    */
    mov r1, #0xffffffff
    ldr r0, =INTMSK
    str r1, [r0]
    # if defined(CONFIG_S3C2410)
    ldr r1, =0x3ff
    ldr r0, =INTSUBMSK
    str r1, [r0]
    # endif

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */

    @时钟分频设置,FCLK为核心提供时钟,HCLK为AHB(ARM920T,内存@控制器,中断控制器,LCD控制器,DMA和主USB模块)提供时钟,@PCLK为APB(看门狗、IIS、I2C、PWM、MMC、ADC、UART、GPIO、@RTC、SPI)提供时钟。分频数一般选择1:4:8,所以HDIVN=2,PDIVN=1,@CLKDIVN=5,这里仅仅是配置了分频寄存器,关于MPLLCON的配置肯@定写在lowlevel_init.S中了
    @归纳出CLKDIVN的值跟分频的关系:
    @0x0 = 1:1:1  ,  0x1 = 1:1:2 , 0x2 = 1:2:2  ,  0x3 = 1:2:4,  0x4 = 1:4:4,  0x5 = 1:4:8, 0x6 = 1:3:3, 
    0x7 = 1:3:6
    @S3C2440的输出时钟计算式为:Mpll=(2*m*Fin)/(p*2^s)
    S3C2410的输出时钟计算式为:Mpll=(m*Fin)/(p*2^s)
    m=M(the value for divider M)+8;p=P(the value for divider P)+2
    M,P,S的选择根据datasheet中PLL VALUE SELECTION TABLE表格进行。


    ldr r0, =CLKDIVN
    mov r1, #3
    str r1, [r0]
    #endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

    /*
    * we do sys-critical inits only at reboot,
    * not when booting from ram!
    */
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl cpu_init_crit

    @执行CPU初始化,BL完成跳转的同时会把后面紧跟的一条指令地址保存到连接寄存器LR(R14)中。以使子程序执行完后正常返回。
    #endif

    #ifndef CONFIG_SKIP_RELOCATE_UBOOT
    relocate: /* relocate U-Boot to RAM */
    adr r0, _start /* r0 <- current position of code */
    ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
    cmp r0, r1 /* don't reloc during debug */
    beq stack_setup

    ldr r2, _armboot_start
    ldr r3, _bss_start
    sub r2, r3, r2 /* r2 <- size of armboot */
    add r2, r0, r2 /* r2 <- source end address */

    copy_loop:
    ldmia r0!, {r3-r10} /* copy from source address [r0] */

    @从源地址[r0]读取8个字节到寄存器,每读一个就更新一次r0地址
    @ldmia:r0安字节增长

    stmia r1!, {r3-r10} /* copy to target address [r1] */

    @LDM(STM)用于在寄存器所指的一片连续存储器和寄存器列表的寄存@器间进行数据移动,或是进行压栈和出栈操作。
    @格式为:LDM(STM){条件}{类型}基址寄存器{!},寄存器列表{^}
    @对于类型有以下几种情况: IA 每次传送后地址加1,用于移动数

    @据块
        IB 每次传送前地址加1,用于移动数据块
        DA 每次传送后地址减1,用于移动数据块
        DB 每次传送前地址减1,用于移动数据块
        FD 满递减堆栈,用于操作堆栈(即先移动指针再操作数据,相当于DB)
        ED 空递减堆栈,用于操作堆栈(即先操作数据再移动指针,相当于DA)
        FA 满递增堆栈,用于操作堆栈(即先移动指针再操作数据,相当于IB)
        EA 空递增堆栈,用于操作堆栈(即先操作数据再移动指针,相当于IA)


    cmp r0, r2 /* until source end addreee [r2] */
    ble copy_loop
    #endif /* CONFIG_SKIP_RELOCATE_UBOOT */

    /* Set up the stack */
    stack_setup:
    ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
    sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
    sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
    #ifdef CONFIG_USE_IRQ
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
    #endif
    sub sp, r0, #12 /* leave 3 words for abort-stack */

    clear_bss:
    ldr r0, _bss_start /* find start of bss segment */
    ldr r1, _bss_end /* stop here */
    mov r2, #0x00000000 /* clear */

    clbss_l:str r2, [r0] /* clear loop... */
    add r0, r0, #4
    cmp r0, r1
    ble clbss_l

    #if 0
    /* try doing this stuff after the relocation */
    ldr r0, =pWTCON
    mov r1, #0x0
    str r1, [r0]

    /*
    * mask all IRQs by setting all bits in the INTMR - default
    */
    mov r1, #0xffffffff
    ldr r0, =INTMR
    str r1, [r0]

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr r0, =CLKDIVN
    mov r1, #3
    str r1, [r0]
    /* END stuff after relocation */
    #endif

    ldr pc, _start_armboot

    @跳到阶段二C语言中去

    _start_armboot: .word start_armboot


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


    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    cpu_init_crit:
    /*
    * flush v4 I/D caches
    */

    @初始化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 lowlevel_init.S in your board directory.
    */
    mov ip, lr
    bl lowlevel_init

    @在重定向代码之前,必须初始化内存时序,因为重定向时需要将@flash中的代码复制到内存中lowlevel_init@/board/smdk2410/lowlevel_init.S中
    mov lr, ip
    mov pc, lr
    #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

    /*
    *************************************************************************
    *
    * 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
    ldr r2, _armboot_start
    sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub r2, r2, #(CFG_GBL_DATA_SIZE+8) @ set base 2 words into abort stack
    ldmia r2, {r2 - r3} @ get pc, cpsr
    add r0, sp, #S_FRAME_SIZE @ restore sp_SVC

    add r5, sp, #S_SP
    mov r1, lr
    stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr
    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_start @ setup our mode stack
    sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
    sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

    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

  • 相关阅读:
    第六章例6-5
    第六章例6-3
    第六章例6-2
    获取JVM默认编码以及获取其它JVM属性的方法(转)
    Java读取文本文件中文乱码问题
    highcharts highstock API js图形
    swing/swt可视化开发工具windowbuilder免费了
    swt 引入 js 问题
    swt 例子
    经验分享:开发SWT应用两点心得(转)
  • 原文地址:https://www.cnblogs.com/wlzy/p/6047660.html
Copyright © 2020-2023  润新知