zoukankan      html  css  js  c++  java
  • Uboot流程分析

    1. uboot的配置分析

    1).配置入口分析

    首先分析配置:

    从make mx6dl_sabresd_android_config可知配置项,搜索Makefile:

    mx6solo_sabresd_android_config             
    mx6dl_sabresd_config                
    mx6dl_sabresd_mfg_config         
    mx6dl_sabresd_android_config                    
    mx6q_sabresd_config                 
    mx6q_sabresd_android_config             
    mx6q_sabresd_mfg_config                
    mx6q_sabresd_iram_config  : unconfig
           @[ -z "$(findstring iram_,$@)" ] || 
                  {echo "TEXT_BASE = 0x00907000" > $(obj)board/freescale/mx6q_sabresd/config.tmp ; 
                    echo "... with iram configuration" ; 
                  }
           @$(MKCONFIG) $(@:_config=) arm arm_cortexa8 mx6q_sabresd freescale mx6

    其中MKCONFIG就是mkconfig

    展开后结果为:mkconfig mx6dl_sabresd_android  arm arm_cortexa8 mx6q_sabresd freescale mx6

    2). mkconfig

    然后打开mkconfig查看:

    APPEND=no   # Default: Create new config file
    
    BOARD_NAME=""   # Name to print in make output
    
    
    #循环查看参数并处理
    
    while [ $# -gt 0 ] ; do
    
        case "$1" in
    
        --) shift ; break ;;
    
        -a) shift ; APPEND=yes ;;
    
        -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
    
        *)  break ;;
    
        esac
    
    done
    
    [ "${BOARD_NAME}" ] || BOARD_NAME="$1"
    
    #当参数数量小于4或者大于6个的时候退出
    
    [ $# -lt 4 ] && exit 1
    
    [ $# -gt 6 ] && exit 1
    
    #这里就是配置时窗口显示的Configuring for mx6dl_sabresd_android board...
    
    echo "Configuring for ${BOARD_NAME} board..."
    
    
    
    # Create link to architecture specific headers
    
    # 根据不同的架构,将不同的文件进行软连接
    
    if [ "$SRCTREE" != "$OBJTREE" ] ; then
    
        mkdir -p ${OBJTREE}/include
    
        mkdir -p ${OBJTREE}/include2
    
        cd ${OBJTREE}/include2
    
        rm -f asm
    
        ln -s ${SRCTREE}/include/asm-$2 asm
    
        LNPREFIX="../../include2/asm/"
    
        cd ../include
    
        rm -rf asm-$2
    
        rm -f asm
    
        mkdir asm-$2
    
        ln -s asm-$2 asm
    
    else
    
        cd ./include
    
        rm -f asm
    
        ln -s asm-$2 asm
    
    fi
    
     
    rm -f asm-$2/arch
    
    
    if [ -z "$6" -o "$6" = "NULL" ] ; then
    
        ln -s ${LNPREFIX}arch-$3 asm-$2/arch
    
    else
    
        ln -s ${LNPREFIX}arch-$6 asm-$2/arch
    
    fi
    
    if [ "$2" = "arm" ] ; then
    
        rm -f asm-$2/proc
    
        ln -s ${LNPREFIX}proc-armv asm-$2/proc
    
    fi
    
    
    #创建一个/include/config.mk,并将传进来的参数放入里面
    
    echo "ARCH   = $2" >  config.mk
    
    echo "CPU    = $3" >> config.mk
    
    echo "BOARD  = $4" >> config.mk
    
     
    
    [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
    
     
    
    [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk
    
     
    
    #创建/include/config.h并将两个架构相关的头文件放入其中
    
    if [ "$APPEND" = "yes" ]    # Append to existing config file
    
    then
    
        echo >> config.h
    
    else
    
        > config.h      # Create new config file
    
    fi
    
    echo "/* Automatically generated - do not edit */" >>config.h
    
    echo "#include <configs/$1.h>" >>config.h
    
    echo "#include <asm/config.h>" >>config.h
    
     
    
    exit 0

    查看MKCONFIG可知,最后这五个会生成include/config.mk中

    ARCH   = arm

    CPU    = arm_cortexa8

    BOARD  = mx6q_sabresd

    VENDOR = freescale

    SOC    = mx6

    由此可以推出./board/freescale/mx6q_sabresd/u-boot.lds

    由此可知入口为flash_header.S

    3).编译过程分析

    通过之前分析查看/include/config.mk

    ARCH   = arm

    CPU    = arm_cortexa8

    BOARD  = mx6q_sabresd

    VENDOR = freescale

    SOC    = mx6

    通过全局搜索可以找到/board/freescale/mx6q_sabresd/u-boot.lds为链接脚本文件

    OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
    
    OUTPUT_ARCH(arm)
    
    ENTRY(_start)
    
    SECTIONS
    
    {
    
        . = 0x00000000;
    
     
    
        . = ALIGN(4);
    
        .text      :
    
        {
    
          /* WARNING - the following is hand-optimized to fit within    */
    
          /* the sector layout of our flash chips!  XXX FIXME XXX   */
    
          board/freescale/mx6q_sabresd/flash_header.o   (.text.flasheader)
    
          cpu/arm_cortexa8/start.o
    
          board/freescale/mx6q_sabresd/libmx6q_sabresd.a    (.text)
    
          lib_arm/libarm.a      (.text)
    
          net/libnet.a          (.text)
    
          drivers/mtd/libmtd.a      (.text)
    
          drivers/mmc/libmmc.a      (.text)
    
     
    
          . = DEFINED(env_offset) ? env_offset : .;
    
          common/env_embedded.o(.text)
    
     
    
          *(.text)
    
        }
    
     
    
        . = ALIGN(4);
    
        .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
    
     
    
        . = ALIGN(4);
    
        .data : { *(.data) }
    
     
    
        . = ALIGN(4);
    
        .got : { *(.got) }
    
     
    
        . = .;
    
        __u_boot_cmd_start = .;
    
        .u_boot_cmd : { *(.u_boot_cmd) }
    
        __u_boot_cmd_end = .;
    
     
    
        . = ALIGN(4);
    
        _end_of_copy = .; /* end_of ROM copy code here */
    
     
    
        /* Extend to align to 0x1000, then put the Hab Data */
    
        . = ALIGN(0x1000);
    
        __hab_data = .;
    
        . = . + 0x2000;
    
        __data_enc_key = .;
    
        /* actually, only 64bytes are needed, but this generates
    
            a size multiple of 512bytes, which is optimal for SD boot */
    
        . = . + 0x200;
    
        __hab_data_end = .;
    
        /* End of Hab Data, Place it before BSS section */
    
     
    
        __bss_start = .;
    
        .bss : { *(.bss) }
    
        _end = .;
    
    }

    从这个文件可知,代码的入口为_start

    text为代码段,rodata为只读数据段,u_boot_cmd为命令的存放空间。

    发现第一个文件为board/freescale/mx6q_sabresd/flash_header.S,他是保存在(.text.flasheader)段中

    2. uboot的第一阶段

    从flash_header.S中可知

    .section ".text.flasheader", "x"
    
           b     _start
    

      

    这个时候跳入了_start中了,其在cpu/arm_cortexa8/start.S当中

     

    /*第一步:首先进行复位*/
    
    .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
    
    _pad:           .word 0x12345678 /* now 16*4=64 */
    
    .global _end_vect
    
    _end_vect:
    
     
    
    .balignl 16,0xdeadbeef
    
     
    
    。。。省略。。。
    
     
    
    /*复位,设置CPSR寄存器*/
    
    reset:
    
        /*
    
         * set the cpu to SVC32 mode
    
         */
    
        mrs r0, cpsr
    
        bic r0, r0, #0x1f
    
        orr r0, r0, #0xd3
    
        msr cpsr,r0
    
       
    
        /*没有定义CONFIG_SKIP_LOWLEVEL_INIT ,所以进入cpu_init_crit */
    
    #ifndef CONFIG_SKIP_LOWLEVEL_INIT
    
        bl  cpu_init_crit
    
    #endif
    
    。。。省略。。。
    
     
    
    cpu_init_crit:
    
        /*
    
         * Invalidate L1 I/D
    
         */
    
        mov r0, #0          @ set up for MCR
    
        mcr p15, 0, r0, c8, c7, 0   @ invalidate TLBs
    
        mcr p15, 0, r0, c7, c5, 0   @ invalidate icache
    
     
    
        /*关闭mmu和catch*/
    
        mrc p15, 0, r0, c1, c0, 0
    
        bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
    
        bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
    
        orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
    
        orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
    
        mcr p15, 0, r0, c1, c0, 0
    
     
    
        mov ip, lr          @ persevere link reg across call
    
        bl  lowlevel_init  @这里是跳转到lowlevel_init去初始化一些基本的板级信息。
    
        mov lr, ip          @ restore link
    
        mov pc, lr          @ back to my caller

    通过全局搜索可知lowlevel_init在boardfreescalemx6q_sabresd目录中的lowlevel_init.S中,打开lowlevel_init.S

    .globl lowlevel_init
    
    lowlevel_init:
    
           /* 禁止D-CACHE */
    
           inv_dcache
    
           /*禁止L2Cache */
    
           init_l2cc
    
           init_aips
    
           /*初始化时钟*/
    
           init_clock
    
           /*跳回去*/
    
           mov pc, lr

    返回到start.S中,如下代码可知,返回到了cpu_init_crit调用之后的代码

    #ifndef CONFIG_SKIP_RELOCATE_UBOOT
    
    /*比较_start 的值和_TEXT_BASE的值是否一致,如果不一致的话则进行拷贝,
    
     *在uboot的第一阶段是不一致的,因为_start为nor flash的地址值,而
    
     *_TEST_BASE为RAM中确定的运行地址值 */
    
    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:              @ copy 32 bytes at a time
    
        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 */
    
     
    
    /*重定位之后,设置堆栈,,初始化C语言环境 */
    
    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
    
        and sp, sp, #~7     @ 8 byte alinged for (ldr/str)d
    
     
    
        /* Clear BSS (if any). Is below tx (watch load addr - need space) */
    
    clear_bss:
    
        ldr r0, _bss_start      @ find start of bss segment
    
        ldr r1, _bss_end        @ stop here
    
        mov r2, #0x00000000     @ clear value
    
    clbss_l:
    
        str r2, [r0]        @ clear BSS location
    
        cmp r0, r1          @ are we at the end yet
    
        add r0, r0, #4      @ increment clear index pointer
    
        bne clbss_l         @ keep clearing till at end
    
     
    
    #ifdef CONFIG_ARCH_MMU
    
        bl board_mmu_init
    
    #endif
    
        ldr pc, _start_armboot  @ jump to C code
    
     /*从这里跳入uboot的第二阶段*/
    
    _start_armboot: .word start_armboot
    

      

     

    第一阶段流程总结:

    flash_header.S     b   _start     

    start.S            _start: b reset       //复位        

    start.S            cpu_init_crit        //关闭mmu和catch             

    lowlevel_init.S     lowlevel_init        //关闭D-CACHE和L2Cache,初始化时钟

    start.S            relocate           //查看是否需要代码进行重定位

    start.S            copy_loop         //代码进行重定位

    start.S            stack_setup        //设置堆栈,清BSS等初始化C语言环境

    start.S            start_armboot      //跳入第二阶段

    3. uboot的第二阶段

    通过搜索可知第二阶段代码在: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;
    
        /*这里的init_sequence是一个函数指针数组,他将分别对硬件进行初始化*/
    
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
    
            if ((*init_fnc_ptr)() != 0) {
    
                hang ();
    
            }
    
        }

    在lib_arm/board.c中查看所初始化的函数:

    init_fnc_t *init_sequence[] = {
    
    #if defined(CONFIG_ARCH_CPU_INIT)
    
        arch_cpu_init,      /* CPU基本的初始化:打开icache,dcache,清看门狗,和一些外设掉电 */
    
    #endif
    
        board_init,     /* 板子的基本信息:机器码=3980,LCD基本信息 */
    
    #if defined(CONFIG_USE_IRQ)
    
        interrupt_init,     /* set up exceptions */
    
    #endif
    
        timer_init,     /*初始化定时器*/
    
        env_init,       /* 初始化环境变量,所在文件为common/env_sf.c */
    
        init_baudrate,      /* 设置波特率 */
    
        serial_init,        /* 设置串口 */
    
        console_init_f,     /* 设置是否有无控制台 */
    
        display_banner,     /*打印一些基本信息给控制台*/
    
    #if defined(CONFIG_DISPLAY_CPUINFO)
    
        print_cpuinfo,      /* display cpu info (and speed) */
    
    #endif
    
    #if defined(CONFIG_DISPLAY_BOARDINFO)
    
        checkboard,     /* display board info */
    
    #endif
    
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
    
        init_func_i2c,
    
    #endif
    
        dram_init,      /* 设置DRAM的大小和地址 */
    
    #if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
    
        arm_pci_init,
    
    #endif
    
        display_dram_config,  /*打印配置的DRAM的基本信息*/
    
        NULL,
    
    };
    
     
    

      

    其中env_init为环境变量的初始化,所在文件为common/env_sf.c

    int env_init(void)
    
    {
    
        /* SPI flash isn't usable before relocation */
    
        gd->env_addr = (ulong)&default_environment[0];
    
        gd->env_valid = 1;
    
     
    
        return 0;
    
    }

    default_environment则为默认环境变量在/common/env_common.c中

    uchar default_environment[] = {
    
    #ifdef  CONFIG_BOOTARGS
    
        "bootargs=" CONFIG_BOOTARGS         ""
    
    #endif
    
    #ifdef  CONFIG_BOOTCOMMAND
    
        "bootcmd="  CONFIG_BOOTCOMMAND      ""
    
    #endif
    
    #ifdef  CONFIG_RAMBOOTCOMMAND
    
        "ramboot="  CONFIG_RAMBOOTCOMMAND       ""
    
    #endif
    
    #ifdef  CONFIG_NFSBOOTCOMMAND
    
        "nfsboot="  CONFIG_NFSBOOTCOMMAND       ""
    
    #endif
    
    #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    
        "bootdelay="    MK_STR(CONFIG_BOOTDELAY)    ""
    
    #endif
    
    #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
    
        "baudrate=" MK_STR(CONFIG_BAUDRATE)     ""
    
    #endif
    
    #ifdef  CONFIG_LOADS_ECHO
    
        "loads_echo="   MK_STR(CONFIG_LOADS_ECHO)   ""
    
    #endif
    
    #ifdef  CONFIG_ETHADDR
    
        "ethaddr="  MK_STR(CONFIG_ETHADDR)      ""
    
    #endif
    
    #ifdef  CONFIG_ETH1ADDR
    
        "eth1addr=" MK_STR(CONFIG_ETH1ADDR)     ""
    
    #endif
    
    #ifdef  CONFIG_ETH2ADDR
    
        "eth2addr=" MK_STR(CONFIG_ETH2ADDR)     ""
    
    #endif
    
    #ifdef  CONFIG_ETH3ADDR
    
        "eth3addr=" MK_STR(CONFIG_ETH3ADDR)     ""
    
    #endif
    
    #ifdef  CONFIG_ETH4ADDR
    
        "eth4addr=" MK_STR(CONFIG_ETH4ADDR)     ""
    
    #endif
    
    #ifdef  CONFIG_ETH5ADDR
    
        "eth5addr=" MK_STR(CONFIG_ETH5ADDR)     ""
    
    #endif
    
    #ifdef  CONFIG_IPADDR
    
        "ipaddr="   MK_STR(CONFIG_IPADDR)       ""
    
    #endif
    
    #ifdef  CONFIG_SERVERIP
    
        "serverip=" MK_STR(CONFIG_SERVERIP)     ""
    
    #endif
    
    #ifdef  CONFIG_SYS_AUTOLOAD
    
        "autoload=" CONFIG_SYS_AUTOLOAD         ""
    
    #endif
    
    #ifdef  CONFIG_PREBOOT
    
        "preboot="  CONFIG_PREBOOT          ""
    
    #endif
    
    #ifdef  CONFIG_ROOTPATH
    
        "rootpath=" MK_STR(CONFIG_ROOTPATH)     ""
    
    #endif
    
    #ifdef  CONFIG_GATEWAYIP
    
        "gatewayip="    MK_STR(CONFIG_GATEWAYIP)    ""
    
    #endif
    
    #ifdef  CONFIG_NETMASK
    
        "netmask="  MK_STR(CONFIG_NETMASK)      ""
    
    #endif
    
    #ifdef  CONFIG_HOSTNAME
    
        "hostname=" MK_STR(CONFIG_HOSTNAME)     ""
    
    #endif
    
    #ifdef  CONFIG_BOOTFILE
    
        "bootfile=" MK_STR(CONFIG_BOOTFILE)     ""
    
    #endif
    
    #ifdef  CONFIG_LOADADDR
    
        "loadaddr=" MK_STR(CONFIG_LOADADDR)     ""
    
    #endif
    
    #ifdef CONFIG_RD_LOADADDR
    
        "rd_loadaddr="  MK_STR(CONFIG_RD_LOADADDR)  ""
    
    #endif
    
    #ifdef  CONFIG_CLOCKS_IN_MHZ
    
        "clocks_in_mhz=1"
    
    #endif
    
    #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
    
        "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY)    ""
    
    #endif
    
    #ifdef  CONFIG_EXTRA_ENV_SETTINGS
    
        CONFIG_EXTRA_ENV_SETTINGS
    
    #endif
    
        ""
    
    };

    返回到lib_arm/board.c中的start_armboot接着往下看

     

      /* armboot_start is defined in the board-specific linker script */
    
        mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN);
    
     
    
    #ifndef CONFIG_SYS_NO_FLASH
    
        /* 初始化Flash */
    
        display_flash_config (flash_init ());
    
    #endif /* CONFIG_SYS_NO_FLASH */
    
     
    
    。。。省略。。。
    
     
    
    #ifdef CONFIG_LCD
    
        /* 在之前arch_cpu_init进行过设置gd->fb_base = CONFIG_FB_BASE=(TEXT_BASE + 0x300000)
    
           所以这里就不进入了*/
    
        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 */
    
     
    
    。。。省略。。。
    
     
    
    #ifdef CONFIG_GENERIC_MMC
    
        /*初始化MMC设备*/
    
        puts ("MMC:   ");
    
        mmc_initialize (gd->bd);
    
    #endif
    
     
    
        /* 加载环境变量,如果没有则使用默认的 */
    
        env_relocate ();
    
     
    
    。。。省略。。。
    
     
    
        /* IP Address */
    
        gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
    
     
    
    #if defined CONFIG_SPLASH_SCREEN && defined CONFIG_VIDEO_MX5
    
        setup_splash_image();
    
    #endif
    
        /*对设备进行初始化,并将其加入链表进行统一的管理*/
    
    stdio_init ();  /* get the devices list going. */
    
     

    在stdio_init中,采用了uboot的设备管理模型对设备进行了管理,对于设备的具体操作方式统一了接口,并将它们放在了链表上进行统一的管理。如下:

    int stdio_init (void)
    
    {
    
    #ifndef CONFIG_ARM  /* already relocated for current ARM implementation */
    
        ulong relocation_offset = gd->reloc_off;
    
        int i;
    
     
    
        /* relocate device name pointers */
    
        for (i = 0; i < (sizeof (stdio_names) / sizeof (char *)); ++i) {
    
            stdio_names[i] = (char *) (((ulong) stdio_names[i]) +
    
                            relocation_offset);
    
        }
    
    #endif
    
     
    
        /* 初始化设备链表 */
    
        INIT_LIST_HEAD(&(devs.list));
    
     
    
    #ifdef CONFIG_ARM_DCC_MULTI
    
        drv_arm_dcc_init ();
    
    #endif
    
    #if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
    
        /*初始化I2C设备*/
    
        i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE);
    
    #endif
    
    #ifdef CONFIG_LCD
    
        /*初始化LCD设备*/
    
        drv_lcd_init ();
    
    #endif
    
    #if defined(CONFIG_VIDEO) || defined(CONFIG_CFB_CONSOLE)
    
        /*初始化视频设备*/
    
        drv_video_init ();     
    
    #endif
    
    #ifdef CONFIG_KEYBOARD
    
        /*初始化按键设备*/
    
        drv_keyboard_init ();  
    
    #endif
    
    #ifdef CONFIG_LOGBUFFER
    
        drv_logbuff_init ();
    
    #endif
    
        /*初始化系统设备*/
    
        drv_system_init ();
    
    #ifdef CONFIG_SERIAL_MULTI
    
        serial_stdio_init ();
    
    #endif
    
    #ifdef CONFIG_USB_TTY
    
        /*初始化usbtty设备*/
    
        drv_usbtty_init ();
    
    #endif
    
    #ifdef CONFIG_NETCONSOLE
    
        drv_nc_init ();
    
    #endif
    
    #ifdef CONFIG_JTAG_CONSOLE
    
        drv_jtag_console_init ();
    
    #endif
    
     
    
        return (0);
    
    }

     

    继续接下来start_armboot中的代码。

        /*将一些常用的函数统一放入gd->jt当中*/
    
        jumptable_init ();
    
     
    
    。。。省略。。。
    
        /*控制台*/
    
        console_init_r ();  /* fully init console as a device */
    
     
    
    。。。省略。。。
    
     
    
        /* enable exceptions */
    
        enable_interrupts ();
    
     
    
        /* Perform network card initialisation if necessary */
    
    。。。省略。。。
    
     
    
    #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 */
    
     
    
    #if defined(CONFIG_ENC28J60_ETH) && !defined(CONFIG_ETHADDR)
    
        extern void enc_set_mac_addr (void);
    
        enc_set_mac_addr ();
    
    #endif /* CONFIG_ENC28J60_ETH && !CONFIG_ETHADDR*/
    
     
    
        /* 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_ANDROID_RECOVERY
    
        check_recovery_mode();
    
    #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
    
    #ifdef CONFIG_FASTBOOT
    
        check_fastboot_mode();
    
    #endif
    
        /* main_loop() can return to retry autoboot, if so just run it again. */
    
        for (;;) {
    
            main_loop ();
    
        }
    
    }

     

    在main_loop后就进入了死循环,不停的接收命令,执行命令,其代码在/common/main.c当中

    void main_loop (void)
    
    {
    
    #ifndef CONFIG_SYS_HUSH_PARSER
    
        static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, };
    
        int len;
    
        int rc = 1;
    
        int flag;
    
    #endif
    
     
    
    #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    
        char *s;
    
        int bootdelay;
    
    #endif
    
     
    
    。。。省略。。。
    
     
    
    #ifdef CONFIG_SYS_HUSH_PARSER
    
        u_boot_hush_start ();
    
    #endif
    
     
    
    #ifdef CONFIG_AUTO_COMPLETE      
    
        install_auto_complete();
    
    #endif
    
     
    
    #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
    
        /*从环境变量中获取到bootdelay的值*/
    
        s = getenv ("bootdelay");
    
       
    
        bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
    
     
    
        debug ("### main_loop entered: bootdelay=%d
    
    ", bootdelay);
    
       
    
    。。。省略。。。   
    
     
    
        /*从环境变量中获取到bootcmd的值*/
    
        s = getenv ("bootcmd");
    
     
    
        debug ("### main_loop: bootcmd="%s"
    ", s ? s : "<UNDEFINED>");
    
        /*等待bootdelay秒并且没有按下确认键则进入if*/
    
        if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
    
     
    
    。。。省略。。。
    
       
    
    # ifndef CONFIG_SYS_HUSH_PARSER
    
            run_command (s, 0);
    
    # else
    
            /*在这里执行bootcmd,正常流程就是进入到启动内核程序中了*/
    
            parse_string_outer(s, FLAG_PARSE_SEMICOLON |
    
                        FLAG_EXIT_FROM_LOOP);
    
    # endif
    
     
    
    。。。省略。。。
    
     
    
        }
    
       
    
    #endif  /* CONFIG_BOOTDELAY */
    
     
    
    #ifdef CONFIG_SYS_HUSH_PARSER
    
        /*这里进入循环的命令解析执行*/
    
        parse_file_outer();   
    
        /* 不会到这里 */
    
        for (;;);
    
    #else
    
    。。。省略。。。
    
    #endif /*CONFIG_SYS_HUSH_PARSER*/
    
    }

    4. uboot启动kernel

    首先注意比较重要的结构体cmd_tbl_s

    struct cmd_tbl_s {
    
        char    *name;      /* 命令的名字 */
    
        int     maxargs;    /* 最大参数个数  */
    
        int     repeatable; /* 是否可以重复,也就是按确认键,是否会支持  */
    
        int     (*cmd)(struct cmd_tbl_s *, int, int, char *[]);/*执行函数*/
    
        char        *usage;     /* 用户帮助信息  (简略的) */
    
    #ifdef  CONFIG_SYS_LONGHELP
    
        char        *help;      /* 用户帮助信息   (详细的)  */
    
    #endif
    
    #ifdef CONFIG_AUTO_COMPLETE
    
        /* do auto completion on the arguments */
    
        int     (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
    
    #endif
    
    };

     

    Bootm的宏为:

    U_BOOT_CMD(
    
        bootm,  CONFIG_SYS_MAXARGS, 1,  do_bootm,
    
        。。。省略。。。
    
    );

     

    宏展开后可以推出:

    cmd_tbl_t __u_boot_cmd_bootm = {"bootm", CONFIG_SYS_MAXARGS, 1, do_bootm, 。。。}

    启动流程:

    lib_arm/bootm.c

    int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    
    {
    
        ulong       iflag;
    
        ulong       load_end = 0;
    
        int     ret;
    
        boot_os_fn  *boot_fn;
    
     
    
        /* relocate boot function table */
    
        if (!relocated) {
    
            int i;
    
            for (i = 0; i < ARRAY_SIZE(boot_os); i++)
    
                if (boot_os[i] != NULL)
    
                    boot_os[i] += gd->reloc_off;
    
            relocated = 1;
    
        }
    
    。。。省略。。。
    
        /*取得镜像信息*/
    
        if (bootm_start(cmdtp, flag, argc, argv))
    
            return 1;
    
        /*关中断*/
    
        iflag = disable_interrupts();
    
     
    
    #if defined(CONFIG_CMD_USB)
    
        usb_stop();
    
    #endif
    
     
    
    #ifdef CONFIG_AMIGAONEG3SE
    
        icache_disable();
    
        dcache_disable();
    
    #endif
    
        /*加载内核,在这里面首先会判断内核镜像是否需要解压缩。我们把解压缩放在了kernel的开头进行,所以在这里并不需要,然后再把内核加载到指定的地址*/
    
        ret = bootm_load_os(images.os, &load_end, 1);
    
     
    
        if (ret < 0) {
    
            if (ret == BOOTM_ERR_RESET)
    
                do_reset (cmdtp, flag, argc, argv);
    
            if (ret == BOOTM_ERR_OVERLAP) {
    
                if (images.legacy_hdr_valid) {
    
                    if (image_get_type (&images.legacy_hdr_os_copy) == IH_TYPE_MULTI)
    
                        puts ("WARNING: legacy format multi component "
    
                            "image overwritten
    ");
    
                } else {
    
                    puts ("ERROR: new format image overwritten - "
    
                        "must RESET the board to recover
    ");
    
                    show_boot_progress (-113);
    
                    do_reset (cmdtp, flag, argc, argv);
    
                }
    
            }
    
            if (ret == BOOTM_ERR_UNIMPLEMENTED) {
    
                if (iflag)
    
                    enable_interrupts();
    
                show_boot_progress (-7);
    
                return 1;
    
            }
    
        }
    
     
    
        lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load));
    
     
    
    。。。省略。。。
    
     
    
        show_boot_progress (8);
    
     
    
    #ifdef CONFIG_SILENT_CONSOLE
    
        if (images.os.os == IH_OS_LINUX)
    
            fixup_silent_linux();
    
    #endif
    
        /*获取到启动函数的函数指针,在这里为do_bootm_linux*/
    
        boot_fn = boot_os[images.os.os];
    
     
    
        /*跳转至do_bootm_linux*/
    
        boot_fn(0, argc, argv, &images);
    
        /*不会运行到这里*/
    
        show_boot_progress (-9);
    
    #ifdef DEBUG
    
        puts ("
    ## Control returned to monitor - resetting...
    ");
    
    #endif
    
        do_reset (cmdtp, flag, argc, argv);
    
     
    
        return 1;
    
    }

     

    其中比较关键的函数为bootm_start(获取镜像信息)和bootm_load_os(加载内核)还有在bootm.c当中的do_bootm_linux,下面我们来看一下bootm_start实现的功能:

    static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    
    {
    
        ulong       mem_start;
    
        phys_size_t mem_size;
    
        void        *os_hdr;
    
        int     ret;
    
        /*先将信息清零,然后再填充*/
    
        memset ((void *)&images, 0, sizeof (images));
    
        images.verify = getenv_yesno ("verify");
    
     
    
        lmb_init(&images.lmb);
    
        /*获取到dram的起始地址*/
    
    mem_start = getenv_bootm_low();
    
    /*获取到dram的大小*/
    
        mem_size = getenv_bootm_size();
    
        /*应该是对dram进行某些管理*/
    
        lmb_add(&images.lmb, (phys_addr_t)mem_start, mem_size);
    
     
    
        arch_lmb_reserve(&images.lmb);
    
        board_lmb_reserve(&images.lmb);
    
     
    
       
    
    /* 得到内核镜像的头,启动地址和长度 ,在我们这里是由自己固定的,从0x10800000处取出,在得到内核后,接下来会调用image_get_kernel对内核镜像进行检测:包括对魔数、头的CRC、内核架构,image_start和image_len为函数在去掉内核镜像头部信息以后的地址和长度,如果正确,则返回内核地址,错误返回NULL*/
    
        os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,
    
                &images, &images.os.image_start, &images.os.image_len);
    
        if (images.os.image_len == 0) {
    
            puts ("ERROR: can't get kernel image!
    ");
    
            return 1;
    
        }
    
     
    
        /* 得到镜像的一些参数 */
    
        switch (genimg_get_format (os_hdr)) {
    
        case IMAGE_FORMAT_LEGACY:
    
            images.os.type = image_get_type (os_hdr);
    
            images.os.comp = image_get_comp (os_hdr);
    
            images.os.os = image_get_os (os_hdr);
    
     
    
            images.os.end = image_get_image_end (os_hdr);
    
            images.os.load = image_get_load (os_hdr);
    
            break;
    
           。。。省略。。。
    
        default:
    
            puts ("ERROR: unknown image format type!
    ");
    
            return 1;
    
        }
    
     
    
        /* find kernel entry point */
    
        if (images.legacy_hdr_valid) {
    
            images.ep = image_get_ep (&images.legacy_hdr_os_copy);
    
    #if defined(CONFIG_FIT)
    
        } else if (images.fit_uname_os) {
    
            ret = fit_image_get_entry (images.fit_hdr_os,
    
                    images.fit_noffset_os, &images.ep);
    
            if (ret) {
    
                puts ("Can't get entry point property!
    ");
    
                return 1;
    
            }
    
    #endif
    
        } else {
    
            puts ("Could not find kernel entry point!
    ");
    
            return 1;
    
        }
    
     
    
        if (images.os.os == IH_OS_LINUX) {
    
            /* find ramdisk */
    
            ret = boot_get_ramdisk (argc, argv, &images, IH_INITRD_ARCH,
    
                    &images.rd_start, &images.rd_end);
    
            if (ret) {
    
                puts ("Ramdisk image is corrupt or invalid
    ");
    
                return 1;
    
            }
    
     
    
    #if defined(CONFIG_OF_LIBFDT)
    
    #if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_SPARC)
    
            /* find flattened device tree */
    
            ret = boot_get_fdt (flag, argc, argv, &images,
    
                        &images.ft_addr, &images.ft_len);
    
            if (ret) {
    
                puts ("Could not find a valid device tree
    ");
    
                return 1;
    
            }
    
     
    
            set_working_fdt_addr(images.ft_addr);
    
    #endif
    
    #endif
    
        }
    
     
    
        images.os.start = (ulong)os_hdr;
    
        images.state = BOOTM_STATE_START;
    
     
    
        return 0;
    
    }
    
     

    从do_bootm可知,最后会跳转至lib_arm/bootm.c中的do_bootm_linux

    int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
    
    {
    
        bd_t    *bd = gd->bd;
    
        char    *s;
    
        int machid = bd->bi_arch_number;
    
        void    (*theKernel)(int zero, int arch, uint params);
    
     
    
    #ifdef CONFIG_CMDLINE_TAG
    
        char *commandline = getenv ("bootargs");
    
    #endif
    
     
    
        if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
    
            return 1;
    
        /*得到函数的地址*/
    
        theKernel = (void (*)(int, int, uint))images->ep;
    
        /*获取到机器码*/
    
        s = getenv ("machid");
    
        if (s) {
    
            machid = simple_strtoul (s, NULL, 16);
    
            printf ("Using machid 0x%x from environment
    ", machid);
    
        }
    
     
    
        show_boot_progress (15);
    
     
    
        debug ("## Transferring control to Linux (at address %08lx) ...
    ",
    
               (ulong) theKernel);
    
     
    
    #if defined (CONFIG_SETUP_MEMORY_TAGS) || 
    
        defined (CONFIG_CMDLINE_TAG) || 
    
        defined (CONFIG_INITRD_TAG) || 
    
        defined (CONFIG_SERIAL_TAG) || 
    
        defined (CONFIG_REVISION_TAG) || 
    
        defined (CONFIG_LCD) || 
    
        defined (CONFIG_VFD)
    
        setup_start_tag (bd);
    
    #ifdef CONFIG_SERIAL_TAG
    
        setup_serial_tag (&params);
    
    #endif
    
    #ifdef CONFIG_REVISION_TAG
    
        setup_revision_tag (&params);
    
    #endif
    
    #ifdef CONFIG_SETUP_MEMORY_TAGS
    
        setup_memory_tags (bd);
    
    #endif
    
    #ifdef CONFIG_CMDLINE_TAG
    
        setup_commandline_tag (bd, commandline);
    
    #endif
    
    #ifdef CONFIG_INITRD_TAG
    
        if (images->rd_start && images->rd_end)
    
            setup_initrd_tag (bd, images->rd_start, images->rd_end);
    
    #endif
    
    #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
    
        setup_videolfb_tag ((gd_t *) gd);
    
    #endif
    
        setup_end_tag (bd);
    
    #endif
    
     
    
        /* we assume that the kernel is in place */
    
        printf ("
    Starting kernel ...
    
    ");
    
     
    
    #ifdef CONFIG_USB_DEVICE
    
        {
    
            extern void udc_disconnect (void);
    
            udc_disconnect ();
    
        }
    
    #endif
    
        /*在启动kernel之前进行一些清理工作*/
    
        cleanup_before_linux ();
    
        /*从这个地方就正式跳入了kernel,并将机器码和参数传入kernel,机器码用于kernel的比对,参数用于指导kernel的启动。到此,uboot的所有功能就结束了*/
    
        theKernel (0, machid, bd->bi_boot_params);
    
        /* does not return */
    
     
    
        return 1;
    
    }

     

  • 相关阅读:
    动态添加LInk的分析
    ASP.NET内置对象-网页转向的4中方法
    网页生命周期-动态添加控件
    网页生命周期-控件事件执行顺序
    网页生命周期-PageLoad事件
    HyperLink 控件
    ListBox控件
    OptionMenu选项菜单
    Menubutton按钮弹出菜单
    Menu-右键弹出菜单
  • 原文地址:https://www.cnblogs.com/maogefff/p/7639566.html
Copyright © 2011-2022 走看看