zoukankan      html  css  js  c++  java
  • uboot源码整体框架

    源码解压以后,我们可以看到以下的文件和文件夹:

     cpu

    与处理器相关的文件。每个子目录中都包括cpu.c和interrupt.c、start.S、u-boot.lds。

    cpu.c:初始化CPU、设置指令Cache和数据Cache等

    interrupt.c:设置系统的各种中断和异常

    start.S:是U-boot启动时执行的第一个文件,它主要做最早期的系统初始化,代码重定向和设置系统堆栈,为进入U-boot第二阶段的C程序奠定基础。

    u-boot.lds:链接脚本文件,对于代码的最后组装非常重要。

     board

    已经支持的所有开发板相关文件,其中包含SDRAM初始化代码、Flash底层驱动、板级初始化文件

    其中的config.mk文件定义了TEXT_BASE,也就是代码在内存的实际地址,非常重要。

     common

    与处理器体系结构无关的通用代码,U-boot的命令解析代码/common/command.c、所有命令的上层代码cmd_*.c、U-boot环境变量处理代码env_*.c等都位于该目录下

    drivers

    包含几乎所有外围芯片的驱动,网卡、USB、串口、LCD、Nand Flash等等

    disk

    fs

    net

    支持CPU无关的重要子系统:

    磁盘驱动的分区处理代码

    文件系统:FAT、JFFS2、EXT2等

    网络协议:NFS、TFTP、RARP、DHCP等等

    include

    头文件,包括各CPU的寄存器定义,文件系统、网络等等

    configs子目录下的文件是与目标板相关的配置头文件

    doc

    U-Boot的说明文档,在修改配置文件的时候可能用得上

    lib_arm

    处理器体系相关的初始化文件

    比较重要的是其中的board.c文件,几乎是所有架构的U-boot第二阶段代码入口函数和相关初始化函数存放的地方。

    lib_avr32

    lib_blackfin

    lib_generic

    lib_i386

    lib_m68k

    lib_microblaze

    lib_mips lib_nios

    lib_nios2

    lib_ppc

    lib_sh

    lib_sparc

     api

    examples

    外部扩展应用程序的API和范例

    nand_spl

    onenand_ipl

    post

    一些特殊构架需要的启动代码和上电自检程序代码

    libfdt

    支持平坦设备树(flattened device trees)的库文件

    tools

    编译S-Record或U-Boot映像等相关工具,制作bootm引导的内核映像文件工具mkimage源码就在此

    Makefile

    MAKEALL

    config.mk

    rules.mk

    mkconfig

    控制整个编译过程的主Makefile文件和规则文件

    CHANGELOG

    CHANGELOG-before-U-Boot-1.1.5

    COPYING

    CREDITS

    MAINTAINERS

    README

    一些介绍性的文档、版权说明

    标为红色的是移植时比较重要的文件或文件夹。
    二、U-boot代码的大致执行流程(以S3C24x0为例)

    从链接脚本文件u-boot.lds中可以找到代码的起始:

    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

    OUTPUT_ARCH(arm)

    ENTRY(_start)

    SECTIONS

    {

           . = 0x00000000;

           . = ALIGN(4);

           .text :

           {

                  cpu/arm920t/start.o      (.text)

                  *(.text)

           }

    …..

    从中知道程序的入口点是_start,定位于cpu/arm920t /start.S(即u-boot启动的第一阶段)。
           下面我们来仔细分析一下 start.S。(请对照数据手册阅读源码):

    #include

    #include

    /*

     *************************************************************************

     *

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

     *

     *************************************************************************

     */

    .globl _start

    _start:        b       start_code

             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 (called from the ARM reset exception 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 start code

     */

    start_code:

             /*

              * set the cpu to SVC32 mode

              */

             mrs   r0, cpsr

             bic    r0, r0, #0x1f

             orr    r0, r0, #0xd3

             msr   cpsr, r0

             bl      coloured_LED_init

             bl      red_LED_on

    #if     defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)

             /*

              * relocate exception table

              */

             ldr     r0, =_start

             ldr     r1, =0x0

             mov  r2, #16

    copyex:

             subs r2, r2, #1

             ldr     r3, [r0], #4

             str     r3, [r1], #4

             bne   copyex

    #endif

    #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)

             /* turn off the watchdog */

    # if defined(CONFIG_S3C2400)

    #  define pWTCON    0x15300000

    #  define INTMSK       0x14400008        /* Interupt-Controller base addresses */

    #  define CLKDIVN     0x14800014        /* clock divisor register */

    #else

    #  define pWTCON    0x53000000

    #  define INTMSK       0x4A000008        /* Interupt-Controller base addresses */

    #  define INTSUBMSK         0x4A00001C

    #  define CLKDIVN     0x4C000014       /* clock divisor register */

    # endif

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

             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

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

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

             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, #CONFIG_SYS_MALLOC_LEN   /* malloc area              */

             sub   r0, r0, #CONFIG_SYS_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

             ldr     pc, _start_armboot

    _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

              */

             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

             mov  lr, ip

             mov  pc, lr

    #endif /* CONFIG_SKIP_LOWLEVEL_INIT */

    …...

    //位于include目录下是一个包含其他头文件的头文件

    //位于includelinux目录下

    u-boot的主入口,跳入了后面的start_code

    这些是跳转向量表,和芯片的体系结构有关

     ldr语句的意思是将第二个操作数(如:_undefined_instruction)指向的地址数据传给PC

     .word 为定义一个4字节的空间

    undefined_instruction 为地址, 即后面标号所对的偏移地址数据


    16字节对齐,并以0xdeadbeef填充,它是个Magic number 。





    这些和上面的一样,定义一个4字节的空间存放地址

    代码从这里开始执行!!

    让系统进入SVC(管理员模式)

    这些都是为AT91RM9200写的

    系统时钟的寄存器地址定义

    关闭看门狗



    关闭所有中断

    设置时钟的分频比










    跳入
    cpu_init_crit ,这是一个系统初始化函数,他还会调用board/*/lowlevel_init.S中的lowlevel_init函数。

    主要是对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor FlashSDRAM才可以被系统使用。下面的代码重定向就依赖它。

    代码重定向,它首先检测自己是否已经在内存中:

    如果是直接跳到下面的堆栈初始化代码stack_setup。

    如果不是就将自己从Nor Flash中拷贝到内存中

    自拷贝循环

    请注意看英文注释

    堆栈初始化代码(为第二阶段的C语言做准备)



    BSS段清零(为第二阶段的C语言做准备)

    BSS段(bss segment)通常是用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。在编译时,编译器已经为他们分配好了空间,只不过他们的值为0,为了节省空间,在bin或ELF文件中不占空间。

    编译器会计算出_bss_start和_bss_end的值,不是定义的

    跳入第二阶段的C语言代码入口_start_armboot (已经被重定向到内存)

    前面所说的cpu_init_crit 系统初始化函数

    操作CP15协处理器,

    调用board/*/lowlevel_init.S中的lowlevel_init函数,对系统总线的初始化,初始化了连接存储器的位宽、速度、刷新率等重要参数。经过这个函数的正确初始化,Nor Flash、SDRAM才可以被系统使用。

    后面的代码略,主要是中断相关代码,但是U-boot基本不使用中断所以暂且略过。


    二、 现在我们再来看看lib_arm/board.c中的第二阶段入口函数start_armboot :

    void start_armboot (void)                     

    {

           init_fnc_t **init_fnc_ptr;

           char *s;

    #if defined(CONFIG_VFD) || defined(CONFIG_LCD)

           unsigned long addr;

    #endif

           /* Pointer is writable since we allocated a register for it */

           gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));

           /* compiler optimization barrier needed for GCC >= 3.4 */

           __asm__ __volatile__("": : :"memory");

           memset ((void*)gd, 0, sizeof (gd_t));

           gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));

           memset (gd->bd, 0, sizeof (bd_t));

           gd->flags |= GD_FLG_RELOC;

           monitor_flash_len = _bss_start - _armboot_start;

           for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

                  if ((*init_fnc_ptr)() != 0) {

                         hang ();

                  }

           }

           /* armboot_start is defined in the board-specific linker script */

           mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,

                         CONFIG_SYS_MALLOC_LEN);

    #ifndef CONFIG_SYS_NO_FLASH

           /* configure available FLASH banks */

           display_flash_config (flash_init ());

    #endif /* CONFIG_SYS_NO_FLASH */

    #ifdef CONFIG_VFD

    #     ifndef PAGE_SIZE

    #       define PAGE_SIZE 4096

    #     endif

           /*

            * reserve memory for VFD display (always full pages)

            */

           /* bss_end is defined in the board-specific linker script */

           addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

           vfd_setmem (addr);

           gd->fb_base = addr;

    #endif /* CONFIG_VFD */

    #ifdef CONFIG_LCD

           /* board init may have inited fb_base */

           if (!gd->fb_base) {

    #            ifndef PAGE_SIZE

    #              define PAGE_SIZE 4096

    #            endif

                  /*

                   * reserve memory for LCD display (always full pages)

                   */

                  /* bss_end is defined in the board-specific linker script */

                  addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);

                  lcd_setmem (addr);

                  gd->fb_base = addr;

           }

    #endif /* CONFIG_LCD */

    #if defined(CONFIG_CMD_NAND)

           puts ("NAND:  ");

           nand_init();            /* go init the NAND */

    #endif

    #if defined(CONFIG_CMD_ONENAND)

           onenand_init();

    #endif

    #ifdef CONFIG_HAS_DATAFLASH

           AT91F_DataflashInit();

           dataflash_print_info();

    #endif

           /* initialize environment */

           env_relocate ();

    #ifdef CONFIG_VFD

           /* must do this after the framebuffer is allocated */

           drv_vfd_init();

    #endif /* CONFIG_VFD */

    #ifdef CONFIG_SERIAL_MULTI

           serial_initialize();

    #endif

           /* IP Address */

           gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

           stdio_init ();    /* get the devices list going. */

           jumptable_init ();

    #if defined(CONFIG_API)

           /* Initialize API */

           api_init ();

    #endif

           console_init_r ();    /* fully init console as a device */

    #if defined(CONFIG_ARCH_MISC_INIT)

           /* miscellaneous arch dependent initialisations */

           arch_misc_init ();

    #endif

    #if defined(CONFIG_MISC_INIT_R)

           /* miscellaneous platform dependent initialisations */

           misc_init_r ();

    #endif

           /* enable exceptions */

           enable_interrupts ();

           /* Perform network card initialisation if necessary */

    #ifdef CONFIG_DRIVER_TI_EMAC

           /* XXX: this needs to be moved to board init */

    extern void davinci_eth_set_mac_addr (const u_int8_t *addr);

           if (getenv ("ethaddr")) {

                  uchar enetaddr[6];

                  eth_getenv_enetaddr("ethaddr", enetaddr);

                  davinci_eth_set_mac_addr(enetaddr);

           }

    #endif

    #if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)

           /* XXX: this needs to be moved to board init */

           if (getenv ("ethaddr")) {

                  uchar enetaddr[6];

                  eth_getenv_enetaddr("ethaddr", enetaddr);

                  smc_set_mac_addr(enetaddr);

           }

    #endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

           /* Initialize from environment */

           if ((s = getenv ("loadaddr")) != NULL) {

                  load_addr = simple_strtoul (s, NULL, 16);

           }

    #if defined(CONFIG_CMD_NET)

           if ((s = getenv ("bootfile")) != NULL) {

                  copy_filename (BootFile, s, sizeof (BootFile));

           }

    #endif

    #ifdef BOARD_LATE_INIT

           board_late_init ();

    #endif

    #ifdef CONFIG_GENERIC_MMC

           puts ("MMC:   ");

           mmc_initialize (gd->bd);

    #endif

    #ifdef CONFIG_BITBANGMII

           bb_miiphy_init();

    #endif

    #if defined(CONFIG_CMD_NET)

    #if defined(CONFIG_NET_MULTI)

           puts ("Net:   ");

    #endif

           eth_initialize(gd->bd);

    #if defined(CONFIG_RESET_PHY_R)

           debug ("Reset Ethernet PHY ");

           reset_phy();

    #endif

    #endif

           /* main_loop() can return to retry autoboot, if so just run it again. */

           for (;;) {

                  main_loop ();

           }

           /* NOTREACHED - no way out of command loop except booting */

    }

     

    gd_t bd_t这两个数据结构比较重要,建议大家看。

    分配一个存储全局数据的区域,地址给指针 gd

    全局数据的区清零

    给 gd->bd(指针)赋值(在gd的前面)并清零


    gd->flags 赋值,表示已经重定向(在内存中)

    monitor_flash_len为u-boot代码长度。

    初始化循环

    init_sequence 是一个初始化函数集的函数指针数组(后面讲解)

    如果有任何一个函数失败就进入死循环。

    这个始化函数集比较重要,建议大家认真跟踪一下。

    初始化堆空间,清零。

    初始化Nor Flash相关参数,并显示其大小。

    初始化VFD存储区(LCD显示相关)

    初始化LCD显存

      

    初始化Nand Flash控制器,并显示其容量大小

    初始化OneNand

    初始化 DataFlash

    初始化环境变量,如果认为没有找到存储其中的,就用默认值并打印:“*** Warning - bad CRC, using default environment”。这是我们常看到的。

    初始化 VFD(LCD显示相关)

    初始化串口。

    从环境变量里获取IP地址

    初始化标准输入输出设备。比如:串口、LCD、键盘等等 

    初始化全局数据表中的跳转表gd->jt。

    跳转表是一个函数指针数组,定义了u-boot中基本的常用的函数库,gd->jt是这个函数指针数组的首指针。

    初始化API,用于为U-boot编写的“应用程序”

    初始化 console,平台无关,不一定是串口哦,如果把标准输出设为vga,字符会显示在LCD上。

    平台相关的其他初始化,有的平台有

    中断使能(一般不使用,很多平台此函数是空的)

    TI芯片中的内置MAC初始化(平台相关)

    一种网卡芯片初始化(平台相关)

      

    获取 bootfile参数



    一些板级初始化(有的板子有)

      

    SD/MMC控制器初始化

    MII相关初始化

      

    网卡初始化

    进入主循环,其中会读取bootdelay和bootcmd

    在bootdelay时间内按下键进入命令行,否则执行bootcmd的命令。

    标有红色的是比较重要的地方。

    大致的U-boot启动流程就简单介绍到这。

  • 相关阅读:
    tyvj 1031 热浪 最短路
    【bzoj2005】 [Noi2010]能量采集 数学结论(gcd)
    hdu 1394 Minimum Inversion Number 逆序数/树状数组
    HDU 1698 just a hook 线段树,区间定值,求和
    ZeptoLab Code Rush 2015 C. Om Nom and Candies 暴力
    ZeptoLab Code Rush 2015 B. Om Nom and Dark Park DFS
    ZeptoLab Code Rush 2015 A. King of Thieves 暴力
    hdoj 5199 Gunner map
    hdoj 5198 Strange Class 水题
    vijos 1659 河蟹王国 线段树区间加、区间查询最大值
  • 原文地址:https://www.cnblogs.com/Ph-one/p/4809316.html
Copyright © 2011-2022 走看看