zoukankan      html  css  js  c++  java
  • uboot 2013.01 代码简析(3)第二阶段初始化

    u-boot第二阶段初始化内容的入口函数是_main,_main位于arch/arm/lib/crt0.S文件中:

    _main函数中先为调用board_init_f准备初始化环境(设置栈指针sp和并给gd_t结构分配空间):

    .global _main
    
    _main:
    
    /*
     * Set up initial C runtime environment and call board_init_f(0).
     */
    
    #if defined(CONFIG_NAND_SPL)
        /* deprecated, use instead CONFIG_SPL_BUILD */
        ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
    #elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
        ldr    sp, =(CONFIG_SPL_STACK)
    #else
        ldr    sp, =(CONFIG_SYS_INIT_SP_ADDR)
    #endif
        bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
        sub    sp, #GD_SIZE    /* allocate one GD above SP */
        bic    sp, sp, #7    /* 8-byte alignment for ABI compliance */
        mov    r8, sp        /* GD is above SP */

    然后调用board_init_f(0),这是因为r0可以作为输入参数:

    mov r0, #0
    bl  board_init_f

    board_init_f(0)代码如下:

    init_fnc_t *init_sequence[] = {
    arch_cpu_init, /* basic arch cpu dependent setup */
    mark_bootstage,
    #ifdef CONFIG_OF_CONTROL
    fdtdec_check_fdt,
    #endif
    #if defined(CONFIG_BOARD_EARLY_INIT_F)
    board_early_init_f,
    #endif
    timer_init, /* initialize timer */
    #ifdef CONFIG_BOARD_POSTCLK_INIT
    board_postclk_init,
    #endif
    #ifdef CONFIG_FSL_ESDHC
    get_clocks,
    #endif
    env_init, /* initialize environment */
    init_baudrate, /* initialze baudrate settings */
    serial_init, /* serial communications setup */
    console_init_f, /* stage 1 init of console */
    display_banner, /* say that we are here */
    #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, /* configure available RAM banks */
    NULL,
    };
    void board_init_f(ulong bootflag)
    {
        bd_t *bd;
        init_fnc_t **init_fnc_ptr;
        gd_t *id;
        ulong addr, addr_sp;
    #ifdef CONFIG_PRAM
        ulong reg;
    #endif
        void *new_fdt = NULL;
        size_t fdt_size = 0;
    
        memset((void *)gd, 0, sizeof(gd_t));
    
        gd->mon_len = _bss_end_ofs;
    #ifdef CONFIG_OF_EMBED
        /* Get a pointer to the FDT */
        gd->fdt_blob = _binary_dt_dtb_start;
    #elif defined CONFIG_OF_SEPARATE
        /* FDT is at end of image */
        gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE);
    #endif
        /* Allow the early environment to override the fdt address */
        gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
                            (uintptr_t)gd->fdt_blob);
    
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
            if ((*init_fnc_ptr)() != 0) {
                hang ();
            }
        }
    
    #ifdef CONFIG_OF_CONTROL
        /* For now, put this check after the console is ready */
        if (fdtdec_prepare_fdt()) {
            panic("** CONFIG_OF_CONTROL defined but no FDT - please see "
                "doc/README.fdt-control");
        }
    #endif
    
        debug("monitor len: %08lX
    ", gd->mon_len);
        /*
         * Ram is setup, size stored in gd !!
         */
        debug("ramsize: %08lX
    ", gd->ram_size);
    #if defined(CONFIG_SYS_MEM_TOP_HIDE)
        /*
         * Subtract specified amount of memory to hide so that it won't
         * get "touched" at all by U-Boot. By fixing up gd->ram_size
         * the Linux kernel should now get passed the now "corrected"
         * memory size and won't touch it either. This should work
         * for arch/ppc and arch/powerpc. Only Linux board ports in
         * arch/powerpc with bootwrapper support, that recalculate the
         * memory size from the SDRAM controller setup will have to
         * get fixed.
         */
        gd->ram_size -= CONFIG_SYS_MEM_TOP_HIDE;
    #endif
    
        addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;
    
    #ifdef CONFIG_LOGBUFFER
    #ifndef CONFIG_ALT_LB_ADDR
        /* reserve kernel log buffer */
        addr -= (LOGBUFF_RESERVE);
        debug("Reserving %dk for kernel logbuffer at %08lx
    ", LOGBUFF_LEN,
            addr);
    #endif
    #endif
    
    #ifdef CONFIG_PRAM
        /*
         * reserve protected RAM
         */
        reg = getenv_ulong("pram", 10, CONFIG_PRAM);
        addr -= (reg << 10);        /* size is in kB */
        debug("Reserving %ldk for protected RAM at %08lx
    ", reg, addr);
    #endif /* CONFIG_PRAM */
    
    #if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
        /* reserve TLB table */
        gd->tlb_size = 4096 * 4;
        addr -= gd->tlb_size;
    
        /* round down to next 64 kB limit */
        addr &= ~(0x10000 - 1);
    
        gd->tlb_addr = addr;
        debug("TLB table from %08lx to %08lx
    ", addr, addr + gd->tlb_size);
    #endif
    
        /* round down to next 4 kB limit */
        addr &= ~(4096 - 1);
        debug("Top of RAM usable for U-Boot at: %08lx
    ", addr);
    
    #ifdef CONFIG_LCD
    #ifdef CONFIG_FB_ADDR
        gd->fb_base = CONFIG_FB_ADDR;
    #else
        /* reserve memory for LCD display (always full pages) */
        addr = lcd_setmem(addr);
        gd->fb_base = addr;
    #endif /* CONFIG_FB_ADDR */
    #endif /* CONFIG_LCD */
    
        /*
         * reserve memory for U-Boot code, data & bss
         * round down to next 4 kB limit
         */
        addr -= gd->mon_len;
        addr &= ~(4096 - 1);
    
        debug("Reserving %ldk for U-Boot at: %08lx
    ", gd->mon_len >> 10, addr);
    
    #ifndef CONFIG_SPL_BUILD
        /*
         * reserve memory for malloc() arena
         */
        addr_sp = addr - TOTAL_MALLOC_LEN;
        debug("Reserving %dk for malloc() at: %08lx
    ",
                TOTAL_MALLOC_LEN >> 10, addr_sp);
        /*
         * (permanently) allocate a Board Info struct
         * and a permanent copy of the "global" data
         */
        addr_sp -= sizeof (bd_t);
        bd = (bd_t *) addr_sp;
        gd->bd = bd;
        debug("Reserving %zu Bytes for Board Info at: %08lx
    ",
                sizeof (bd_t), addr_sp);
    
    #ifdef CONFIG_MACH_TYPE
        gd->bd->bi_arch_number = CONFIG_MACH_TYPE; /* board id for Linux */
    #endif
    
        addr_sp -= sizeof (gd_t);
        id = (gd_t *) addr_sp;
        debug("Reserving %zu Bytes for Global Data at: %08lx
    ",
                sizeof (gd_t), addr_sp);
    
    #if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL)
        /*
         * If the device tree is sitting immediate above our image then we
         * must relocate it. If it is embedded in the data section, then it
         * will be relocated with other data.
         */
        if (gd->fdt_blob) {
            fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32);
    
            addr_sp -= fdt_size;
            new_fdt = (void *)addr_sp;
            debug("Reserving %zu Bytes for FDT at: %08lx
    ",
                  fdt_size, addr_sp);
        }
    #endif
    
        /* setup stackpointer for exeptions */
        gd->irq_sp = addr_sp;
    #ifdef CONFIG_USE_IRQ
        addr_sp -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ);
        debug("Reserving %zu Bytes for IRQ stack at: %08lx
    ",
            CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
    #endif
        /* leave 3 words for abort-stack    */
        addr_sp -= 12;
    
        /* 8-byte alignment for ABI compliance */
        addr_sp &= ~0x07;
    #else
        addr_sp += 128;    /* leave 32 words for abort-stack   */
        gd->irq_sp = addr_sp;
    #endif
    
        debug("New Stack Pointer is: %08lx
    ", addr_sp);
    
    #ifdef CONFIG_POST
        post_bootmode_init();
        post_run(NULL, POST_ROM | post_bootmode_get(0));
    #endif
    
        gd->bd->bi_baudrate = gd->baudrate;
        /* Ram ist board specific, so move it to board code ... */
        dram_init_banksize();
        display_dram_config();    /* and display it */
    
        gd->relocaddr = addr;
        gd->start_addr_sp = addr_sp;
        gd->reloc_off = addr - _TEXT_BASE;
        debug("relocation Offset is: %08lx
    ", gd->reloc_off);
        if (new_fdt) {
            memcpy(new_fdt, gd->fdt_blob, fdt_size);
            gd->fdt_blob = new_fdt;
        }
        memcpy(id, (void *)gd, sizeof(gd_t));
    }

    从代码中可以看出,board_init_f对gd内容进行初始化并将其拷贝到id变量中。

    此外,代码中还对init_sequence中的所有函数按顺序依次执行,

    从而完成了对MPLL、UPLL、GPIO、Timer、波特率、串口配置以及显示u-boot版本号、显示CPU型号、显示DRAM信息等功能

    接着设置新sp和gd,然后跳转到relocate_code进行重定位,relocate_code的代码如下:

        .globl    relocate_code
    relocate_code:
        mov    r4, r0    /* save addr_sp */
        mov    r5, r1    /* save addr of gd */
        mov    r6, r2    /* save addr of destination */
    
        adr    r0, _start
        cmp    r0, r6
        moveq    r9, #0        /* no relocation. relocation offset(r9) = 0 */
        beq    relocate_done        /* skip relocation */
        mov    r1, r6            /* r1 <- scratch for copy_loop */
        ldr    r3, _bss_start_ofs
        add    r2, r0, r3        /* r2 <- source end address        */
    
    copy_loop:
        ldmia    r0!, {r9-r10}        /* copy from source address [r0]    */
        stmia    r1!, {r9-r10}        /* copy to   target address [r1]    */
        cmp    r0, r2            /* until source end address [r2]    */
        blo    copy_loop
    
    #ifndef CONFIG_SPL_BUILD
        /*
         * fix .rel.dyn relocations
         */
        ldr    r0, _TEXT_BASE        /* r0 <- Text base */
        sub    r9, r6, r0        /* r9 <- relocation offset */
        ldr    r10, _dynsym_start_ofs    /* r10 <- sym table ofs */
        add    r10, r10, r0        /* r10 <- sym table in FLASH */
        ldr    r2, _rel_dyn_start_ofs    /* r2 <- rel dyn start ofs */
        add    r2, r2, r0        /* r2 <- rel dyn start in FLASH */
        ldr    r3, _rel_dyn_end_ofs    /* r3 <- rel dyn end ofs */
        add    r3, r3, r0        /* r3 <- rel dyn end in FLASH */
    fixloop:
        ldr    r0, [r2]        /* r0 <- location to fix up, IN FLASH! */
        add    r0, r0, r9        /* r0 <- location to fix up in RAM */
        ldr    r1, [r2, #4]
        and    r7, r1, #0xff
        cmp    r7, #23            /* relative fixup? */
        beq    fixrel
        cmp    r7, #2            /* absolute fixup? */
        beq    fixabs
        /* ignore unknown type of fixup */
        b    fixnext
    fixabs:
        /* absolute fix: set location to (offset) symbol value */
        mov    r1, r1, LSR #4        /* r1 <- symbol index in .dynsym */
        add    r1, r10, r1        /* r1 <- address of symbol in table */
        ldr    r1, [r1, #4]        /* r1 <- symbol value */
        add    r1, r1, r9        /* r1 <- relocated sym addr */
        b    fixnext
    fixrel:
        /* relative fix: increase location by offset */
        ldr    r1, [r0]
        add    r1, r1, r9
    fixnext:
        str    r1, [r0]
        add    r2, r2, #8        /* each rel.dyn entry is 8 bytes */
        cmp    r2, r3
        blo    fixloop
    #endif
    
    relocate_done:
    
        mov    pc, lr

    relocate_code刚开始执行前先将here的值保存到lr寄存器中,然后执行重定位,执行完毕后跳转到lr寄存器(即here)执行。

    然后对BSS段进行初始化:

    here:
    
    /* Set up final (full) environment */
    
        bl    c_runtime_cpu_setup    /* we still call old routine here */
    
        ldr    r0, =__bss_start    /* this is auto-relocated! */
        ldr    r1, =__bss_end__    /* this is auto-relocated! */
    
        mov    r2, #0x00000000        /* prepare zero to clear BSS */
    
    clbss_l:cmp    r0, r1            /* while not at end of BSS */
        strlo    r2, [r0]        /* clear 32-bit BSS word */
        addlo    r0, r0, #4        /* move to next */
        blo    clbss_l

    接着调用board_init_r()函数:

        bl coloured_LED_init
        bl red_led_on
    
    #if defined(CONFIG_NAND_SPL)
    
        /* call _nand_boot() */
        ldr     pc, =nand_boot
    
    #else
    
        /* call board_init_r(gd_t *id, ulong dest_addr) */
        mov    r0, r8            /* gd_t */
        ldr    r1, [r8, #GD_RELOCADDR]    /* dest_addr */
        /* call board_init_r */
        ldr    pc, =board_init_r    /* this is auto-relocated! */
    
    #endif

    board_init_r函数代码如下:

    void board_init_r(gd_t *id, ulong dest_addr)
    {
        ulong malloc_start;
    #if !defined(CONFIG_SYS_NO_FLASH)
        ulong flash_size;
    #endif
    
        gd->flags |= GD_FLG_RELOC;    /* tell others: relocation done */
        bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");
    
        monitor_flash_len = _end_ofs;
    
        /* Enable caches */
        enable_caches();
    
        debug("monitor flash len: %08lX
    ", monitor_flash_len);
        board_init();    /* Setup chipselects */
        /*
         * TODO: printing of the clock inforamtion of the board is now
         * implemented as part of bdinfo command. Currently only support for
         * davinci SOC's is added. Remove this check once all the board
         * implement this.
         */
    #ifdef CONFIG_CLOCKS
        set_cpu_clk_info(); /* Setup clock information */
    #endif
        serial_initialize();
    
        debug("Now running in RAM - U-Boot at: %08lx
    ", dest_addr);
    
    #ifdef CONFIG_LOGBUFFER
        logbuff_init_ptrs();
    #endif
    #ifdef CONFIG_POST
        post_output_backlog();
    #endif
    
        /* The Malloc area is immediately below the monitor copy in DRAM */
        malloc_start = dest_addr - TOTAL_MALLOC_LEN;
        mem_malloc_init (malloc_start, TOTAL_MALLOC_LEN);
    
    #ifdef CONFIG_ARCH_EARLY_INIT_R
        arch_early_init_r();
    #endif
        power_init_board();
    
    #if !defined(CONFIG_SYS_NO_FLASH)
        puts("Flash: ");
    
        flash_size = flash_init();
        if (flash_size > 0) {
    # ifdef CONFIG_SYS_FLASH_CHECKSUM
            print_size(flash_size, "");
            /*
             * Compute and print flash CRC if flashchecksum is set to 'y'
             *
             * NOTE: Maybe we should add some WATCHDOG_RESET()? XXX
             */
            if (getenv_yesno("flashchecksum") == 1) {
                printf("  CRC: %08X", crc32(0,
                    (const unsigned char *) CONFIG_SYS_FLASH_BASE,
                    flash_size));
            }
            putc('
    ');
    # else    /* !CONFIG_SYS_FLASH_CHECKSUM */
            print_size(flash_size, "
    ");
    # endif /* CONFIG_SYS_FLASH_CHECKSUM */
        } else {
            puts(failed);
            hang();
        }
    #endif
    
    #if defined(CONFIG_CMD_NAND)
        puts("NAND:  ");
        nand_init();        /* go init the NAND */
    #endif
    
    #if defined(CONFIG_CMD_ONENAND)
        onenand_init();
    #endif
    
    #ifdef CONFIG_GENERIC_MMC
        puts("MMC:   ");
        mmc_initialize(gd->bd);
    #endif
    
    #ifdef CONFIG_HAS_DATAFLASH
        AT91F_DataflashInit();
        dataflash_print_info();
    #endif
    
        /* initialize environment */
        if (should_load_env())
            env_relocate();
        else
            set_default_env(NULL);
    
    #if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
        arm_pci_init();
    #endif
    
        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 */
    
    #ifdef CONFIG_DISPLAY_BOARDINFO_LATE
    # ifdef CONFIG_OF_CONTROL
        /* Put this here so it appears on the LCD, now it is ready */
        display_fdt_model(gd->fdt_blob);
    # else
        checkboard();
    # endif
    #endif
    
    #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
    
         /* set up exceptions */
        interrupt_init();
        /* enable exceptions */
        enable_interrupts();
    
        /* Initialize from environment */
        load_addr = getenv_ulong("loadaddr", 16, load_addr);
    
    #ifdef CONFIG_BOARD_LATE_INIT
        board_late_init();
    #endif
    
    #ifdef CONFIG_BITBANGMII
        bb_miiphy_init();
    #endif
    #if defined(CONFIG_CMD_NET)
        puts("Net:   ");
        eth_initialize(gd->bd);
    #if defined(CONFIG_RESET_PHY_R)
        debug("Reset Ethernet PHY
    ");
        reset_phy();
    #endif
    #endif
    
    #ifdef CONFIG_POST
        post_run(NULL, POST_RAM | post_bootmode_get(0));
    #endif
    
    #if defined(CONFIG_PRAM) || defined(CONFIG_LOGBUFFER)
        /*
         * Export available size of memory for Linux,
         * taking into account the protected RAM at top of memory
         */
        {
            ulong pram = 0;
            uchar memsz[32];
    
    #ifdef CONFIG_PRAM
            pram = getenv_ulong("pram", 10, CONFIG_PRAM);
    #endif
    #ifdef CONFIG_LOGBUFFER
    #ifndef CONFIG_ALT_LB_ADDR
            /* Also take the logbuffer into account (pram is in kB) */
            pram += (LOGBUFF_LEN + LOGBUFF_OVERHEAD) / 1024;
    #endif
    #endif
            sprintf((char *)memsz, "%ldk", (gd->ram_size / 1024) - pram);
            setenv("mem", (char *)memsz);
        }
    #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 */
    }

    在board_init_r函数中依次执行使能数据Cache和指令Cache,三个串口初始化,内存分配初始化,flash初始化,nand初始化,mmc设备初始化,stdio初始化,stdout和stderr初始化,开中断,网卡初始化等操作,

    然后反复执行main_loop函数。

    u-boot第二个阶段的执行内容如下:

    (1)为board_init_f准备sp和gd

    (2)执行board_init_f,对MPLL、UPLL、GPIO、Timer、波特率、串口配置,显示u-boot版本号、CPU型号和DRAM信息,并初始化gd内容。

    (3)调用relocate_code进行代码重定位

    (4)初始化BSS

    (5)调用board_init_r,使能数据Cache和指令Cache,三个串口初始化,内存分配初始化,flash初始化,nand初始化,

       mmc设备初始化,stdio初始化,stdout和stderr初始化,开中断,网卡初始化,然后执行main_loop等待用户输入命令或者超时后进入linux内核。

  • 相关阅读:
    ASP.NET MVC下的四种验证编程方式
    tp框架下,数据库和编辑器都是utf-8, 输出中文却还是乱码
    按拼音首字母排序
    PHP 文件导出(Excel, CSV,txt)
    RedisDesktopManager 可视化工具提示:无法加载键:Scan..
    window下redis如何查看版本号
    jQuery 防止相同的事件快速重复触发
    input中加入搜索图标
    JS搜索商品(跟外卖app店内搜索商品一样) ,keyup函数和click函数调用
    JS正则对象 RegExp(有变量的时候使用),用来匹配搜索关键字(标红)
  • 原文地址:https://www.cnblogs.com/qiaoqiao2003/p/3727841.html
Copyright © 2011-2022 走看看