Bootloader学习笔记

来源:互联网 发布:淘宝实名认证可以改吗 编辑:程序博客网 时间:2024/06/08 05:00

1、“Boot parameters”分区中存放一些可设置的参数,比如IP地址、串口波特率、要传递给内核的命令行参数等。
这里写图片描述

2、正常启动时,Bootloader首先运行,然后它将内核复制到内存中,并且在内存某个固定地址设置好要传递给内核的参数,最后运行内核。内核启动后,它就挂接根文件系统,启动文件系统中的应用程序。

3、Bootloader一般分两个阶段,第一个阶段使用汇编实现,第二阶段使用C语言来实现。
(1)Bootloader第一阶段功能:

  • 硬件设备初始化。(关闭看门狗、关中断、RAM初始化)
  • 为加载Bootloader的第二阶段代码准备RAM空间。
  • 复制Bootloader的第二阶段代码到RAM空间中。
  • 设置好栈。
  • 跳转到第二阶段代码的C入口点。

(2)Bootloader第二阶段功能:

  • 初始化本阶段要使用到的硬件设备。
  • 检测系统内存映射。
  • 将内核映像和根文件系统映像从Flash上读到RAM空间中。
  • 为内核设置启动参数。
  • 调用内核。

4、make smdk2410_config执行后创建include/config.mk文件,内容如下:

ARCH = armCPU = arm920tBOARD = smdk2410SOC = s3c24x0

5、include/configs/.h文件用来裁剪和设置U-Boot,该头文件有两类宏:

(1)前缀为“CONFIG_” : 用来选择CPU、SOC、开发板类型、设置系统时钟、选择设备驱动

#define CONFIG_ARM920T      1   /* This is an ARM920T Core  */#define CONFIG_S3C2410      1   /* in a SAMSUNG S3C2410 SoC     */#define CONFIG_SMDK2410     1   /* on a SAMSUNG SMDK2410 Board  */

(2)前缀为“CFG” : 设置malloc缓冲池的大小、U-Boot的提示符、U-Boot下载文件是默认的
加载地址、Flash的起始地址等。

#define CFG_MALLOC_LEN      (CFG_ENV_SIZE + 128*1024)#define CFG_GBL_DATA_SIZE   128#define CFG_LONGHELP                /* undef to save memory     */#define CFG_PROMPT      "SMDK2410 # "   /* Monitor Command Prompt   */#define CFG_CBSIZE      256     /* Console I/O Buffer Size  */#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */#define CFG_MAXARGS     16      /* max number of command args   */#define CFG_BARGSIZE        CFG_CBSIZE  /* Boot Argument Buffer Size    */#define CFG_MEMTEST_START   0x30000000  /* memtest works on */#define CFG_MEMTEST_END     0x33F00000  /* 63 MB in DRAM    */

6、U-Boot属于两阶段Bootloader, 第一阶段文件为cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S,
前者是平台相关的,后者是开发板相关的。

7、跳转到第二阶段代码前要清除bss段数据(初始值为0、无初始值的全局变量、静态变量放在BSS段)。

8、U-Boot顶层目录说明
这里写图片描述

9、U-Boot第二阶段流程图
这里写图片描述

10、U-Boot中主要文件之间的相互调用过程
这里写图片描述

11、start.S的分析

#include <config.h>#include <version.h>/*****************************************变量定义******************************************************************///global 声明一个符号可被其他文件引用,.globl.global相同.globl _start              //u-boot的启动入口_start: b       reset     //复位向量并且跳转到reset    ldr pc, _undefined_instruction  //7种中断 ,ldr:把中断向量的地址赋给pc寄存器    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   // .word :分配一段字内存单元_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     //指定对齐方式为字对齐//TEXT_BASE在开发板相关目录下的config.mk中定义,它定义了代码在运行时所在的地址//_TEXT_BASE保存着该地址_TEXT_BASE:    .word   TEXT_BASE//声明_armboot_start并用_start进行初始化,在board/u-boot.lds中定义.globl _armboot_start_armboot_start:    .word _start//__bss_start定义在board/u-boot.lds.globl _bss_start_bss_start:    .word __bss_start//_end定义在board/u-boot.lds.globl _bss_end_bss_end:    .word _end#ifdef CONFIG_USE_IRQ/* IRQ stack memory (calculated at run-time) */.globl IRQ_STACK_STARTIRQ_STACK_START:    .word   0x0badc0de/* IRQ stack memory (calculated at run-time) */.globl FIQ_STACK_STARTFIQ_STACK_START:    .word 0x0badc0de#endif/***********************************************************************************************************//********************************************主功能***********************************************************//* * reset代码 */reset:    /*     * 设置CPU进入SVC32模式     */    mrs r0,cpsr         //将CPRS状态寄存器读取保存到r0中    bic r0,r0,#0x1f     //清除r0的bit[4:0]位    orr r0,r0,#0xd3     //将r0与0xd3做或运算,结果返回给r0    msr cpsr,r0         //将r0写入状态寄存器中/* 关闭看门狗 */#if defined(CONFIG_S3C2400)     //S3C2400看门狗对应的寄存器地址定义# define pWTCON     0x15300000# define INTMSK     0x14400008  # define CLKDIVN    0x14800014  #elif defined(CONFIG_S3C2410)   //S3C2410看门狗对应的寄存器地址定义# define pWTCON     0x53000000# define INTMSK     0x4A000008  # define INTSUBMSK  0x4A00001C  //2410才有的寄存器# define CLKDIVN    0x4C000014  #endif#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)    ldr     r0, =pWTCON     //r0赋值为看门狗寄存器的地址    mov     r1, #0x0        //r1 = 0    str     r1, [r0]        //设置看门狗寄存器的值为0(关闭看门狗)   str:将r1寄存器的值赋给r0对应的寄存器    /*     * 关闭所有中断     */    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 ! */    ldr r0, =CLKDIVN    mov r1, #3    str r1, [r0]#endif  /* CONFIG_S3C2400 || CONFIG_S3C2410 */    /*     * b : 跳转到指定的目的地址     * bl: 跳转到指定的目的地址,并将转移后面紧接的一条指令地址保存到LR(R14)寄存器,以此来完成子程序的调用     *     * 调用cpu_init_crit对CPU进行初始化     */#ifndef CONFIG_SKIP_LOWLEVEL_INIT    bl  cpu_init_crit#endif#ifndef CONFIG_SKIP_RELOCATE_UBOOTrelocate:               /* 重定向U-Boot到RAM(拷贝U-Boot到RAM)*/    adr r0, _start      /* 获取当前代码的开始位置 */    ldr r1, _TEXT_BASE      /*代码段的连接地址*/    cmp     r0, r1          /* 检测U-Boot是从FLASH还是RAM启动,如果是在debug,就不拷贝 */     beq     stack_setup    //重定向代码    ldr r2, _armboot_start  //_armboot_start在前面定义,是第一条指令的运行地址    ldr r3, _bss_start      //在连接脚本U-Boot.lds中定义,是代码段的结束地址    sub r2, r3, r2      /* r2 = 代码段长度 */    add r2, r0, r2      /* r2 = NOR Flash上代码段的结束地址*/    //拷贝到RAMcopy_loop:    ldmia   r0!, {r3-r10}       /* 从地址[r0]处获取数据*/    stmia   r1!, {r3-r10}       /* 复制到地址[r1]处 */    cmp r0, r2                  /*判断是否复制结束*/    ble copy_loop               //没复制完,则继续#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */    /* 初始化堆栈*/stack_setup:    ldr r0, _TEXT_BASE              //_TEXT_BASE为代码段的起始地址,值为0x33F80000    sub r0, r0, #CFG_MALLOC_LEN     //代码段下面留出一段内存以实现malloc    sub r0, r0, #CFG_GBL_DATA_SIZE //再留出一段内存,存一些全局参数#ifdef CONFIG_USE_IRQ    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  //IRQ、FIQ模式的栈#endif    sub sp, r0, #12     /* 最后留出12字节的内存给abort异常,往下的内存就都是栈了*/    //清除bss段clear_bss:    ldr r0, _bss_start      //在连接脚本U-Boot.lds中定义,是代码段的结束地址,bss段的开始地址    ldr r1, _bss_end        //bss段的结束地址    mov     r2, #0x00000000     //bss段清为0clbss_l:str r2, [r0]        //清除bss段为0    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    //跳转到start_armboot函数入口,start_armboot函数在lib_arm/board.c中实现    ldr pc, _start_armboot_start_armboot: .word start_armboot/* ************************************************************************* * * CPU_init_critical registers * * setup important registers * setup memory timing * ************************************************************************* */#ifndef CONFIG_SKIP_LOWLEVEL_INITcpu_init_crit:    /*     * 初始化CACHE     */    mov r0, #0    mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */    mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */    /*     * 关闭MMU和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    mov ip, lr    bl  lowlevel_init   //lowlevel_init函数在board/smdk2410/lowlevel_init.s中定义    mov lr, ip    mov pc, lr#endif /* CONFIG_SKIP_LOWLEVEL_INIT *//*******************************************************************************************************************//****************************************************中断处理********************************************************//* ************************************************************************* * * 中断处理 * ************************************************************************* */@@ 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    .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/* * 中断处理,具体实现在lib_arm/interrupts.c */    .align  5undefined_instruction:    get_bad_stack    bad_save_user_regs    bl  do_undefined_instruction    .align  5software_interrupt:    get_bad_stack    bad_save_user_regs    bl  do_software_interrupt    .align  5prefetch_abort:    get_bad_stack    bad_save_user_regs    bl  do_prefetch_abort    .align  5data_abort:    get_bad_stack    bad_save_user_regs    bl  do_data_abort    .align  5not_used:    get_bad_stack    bad_save_user_regs    bl  do_not_used#ifdef CONFIG_USE_IRQ    .align  5irq:    get_irq_stack    irq_save_user_regs    bl  do_irq    irq_restore_user_regs    .align  5fiq:    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  5irq:    get_bad_stack    bad_save_user_regs    bl  do_irq    .align  5fiq:    get_bad_stack    bad_save_user_regs    bl  do_fiq#endif/*************************************************************************************************************/
0 0
原创粉丝点击