处理器              ATSAMA5D3x

硬件平台          SAMA5D3x-EK

u-boot 版本     u-boot-2012.10

先阅读链接脚本 arch/arm/cpu/u-boot.lds 文件:

OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm") ; 指定输出可执行文件是elf格式,32位ARM指令,小端模式
OUTPUT_ARCH(arm)                      ; 定义输出的架构为 arm 体系结构 
ENTRY(_start)                                    ; u-boot 的入口地址为 _start ,定义在 arch/arm/cpu/armv7/start.S
SECTIONS
{
     . = 0x00000000                   ; 起始地址为 0X00000000 
 
     . = ALIGN(4)                         ; 四字节对齐 
     .text :
     {   
        ;映像文件复制起始地址 
         __image_copy_start = .       ; __image_copy_start 的值为当前地址,即 0X00000000 
         CPUDIR/start.o (.text)           ; 对应 arch/arm/cpu/armv7/start.S 
         *(.text)                                      ; 其它代码依次存放 
     }
 
     . = ALIGN(4)                     
     .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } ; 指定只读数据段
 
     . = ALIGN(4); 
     .data : {                        ; 数据段 
         *(.data) 
     }
 
     . = ALIGN(4); 
 
     . = .; 
     __u_boot_cmd_start = .                   ; __u_boot_cmd_start 的起始地址为命令存放区域的首地址 
     .u_boot_cmd : { *(.u_boot_cmd) }  ; 命令存放区 
     __u_boot_cmd_end = .                    ; 命令存放区末地址
 
     . = ALIGN(4); 
 
     __image_copy_end = .             ; 映像文件复制结束地址 
 
    .rel.dyn : {                      ; 用于动态连接的重定位信息  
         __rel_dyn_start = .; 
         *(.rel*) 
         __rel_dyn_end = .  ; 
     }
    
     .dynsym : {            ; .dynsym 动态符号表,这个表只保存了与动态链接相关的符号 
         __dynsym_start = . ; 这是动态连接符号表的数据结构部分,须与 .dynstr 联用。
         *(.dynsym) 
     }
 
     _end = .; 
 
     . = ALIGN(4096); 
     .mmutable : { 
         *(.mmutable) 
     }
     .bss __rel_dyn_start (OVERLAY) : { 
         __bss_start = .; 
         *(.bss)
 
          . = ALIGN(4); 
         __bss_end__ = .; 
     }
 
     /DISCARD/ : { *(.dynstr*) }    ; 动态连接符号表的字符串部分,与 .dynsym 联用
     /DISCARD/ : { *(.dynamic*) } 
     /DISCARD/ : { *(.plt*) }       ; 过程连接表(Procedure Linking Table)
     /DISCARD/ : { *(.interp*) } 
     /DISCARD/ : { *(.gnu*) }
}
 
入口文件 arch/arm/cpu/armv7/start.S :
.globl _start
_start: b reset /* 0x0,正常情况下,系统 reset 后的入口 */
/* 异常向量表 */
ldr pc, _undefined_instruction  /* 0x4,未定义指令异常 */
ldr pc, _software_interrupt        /* 0x8,软件中断异常 */
ldr pc, _prefetch_abort              /* 0xc,未定义指令异常 */
ldr pc, _data_abort                    /* 0x10,数据终止异常 */
ldr pc, _not_used/* 0x14,保留 */
ldr pc, _irq/* 0x18,中断 */
ldr pc, _fiq/* 0x1c,快中断 */
reset: /* 
* 通过设置 CPSR 寄存器,让 CPU 运行在操作系统保护模式,禁止 IRQ 和 FIQ ,
* 以防止代码正在执行时,产生外部中断,导致程序跳转到异常向量表而无法正常按顺序执行。
* 为后面进行其它操作作好准备。
*/

/* 读状态寄存器 cpsr 到 r0 */
mrs r0, cpsr 
/* 将 r0 的低 5 位清零,对应 cpsr 的 M[4:0] ,用于控制处理器模式 */
bic r0, r0, #0x1f 
/* 对应 cpsr 的 I=1,F=1, M[4:0]=10011 ,禁止中断、快中断,设置为管理模式*/
orr r0, r0, #0xd3 
/* 将 r0 的值写回到 状态寄存器 cpsr */
msr cpsr,r0 #if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD)) /* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0@ Read CP15 SCTRL Register
bic r0, #CR_V@ CR_V : 1<< 13, V(bit[13]) = 0
mcr p15, 0, r0, c1, c0, 0@ Write CP15 SCTRL Register
/* Set vector address in CP15 VBAR register */ ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0@Set VBAR
#endif

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
/* CONFIG_SKIP_LOWLEVEL_INIT 在 include/configs/sama5d3xek.h 中定义,本段代码不执行。 
* 设置 cp15 ,禁用指令 (I)cache 和数据 (D)cache ,禁止 MMU 和 cache,设置重要的寄存器和 memory 等功能,
* 这些硬件平台的初始化工作在 AT91Bootstrap 中已经做好了。
*/
bl cpu_init_cp15
bl cpu_init_crit
#endif /* 设置堆栈指针,为执行 c 程序做准备 */ call_board_init_f:
/* 设置堆栈指针 SP */
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
/* 传给 board_init_f 函数的参数为 0x00000000 */
ldr r0,=0x00000000
/* 跳转到 board_init_f 函数 */
bl board_init_f

board_init_f 定义在 arch/arm/lib/board.c 文件中:
这里涉及两个重要的结构体: hd_t 和 gd_t ,在初始化操作很多都要靠这两个数据结构来保存或传递。
bd_t : board info 数据结构定义,主要是用来保存板子的信息。
定义在 arch/arm/include/asm/u-boot.h 文件中:
typedef struct bd_info {
    // 串口波特率
    int bi_baudrate; 
    // 板子的唯一标识ID,该值将传递给内核,在内核 arch/arm/tools/mach-types 文件中有定义,二者需一致。 
    ulong bi_arch_number; 
    // u-boot传递给内核的参数的保存地址
    ulong bi_boot_params; 
    // arm 频率 
    unsigned long bi_arm_freq;
    // dsp core 频率 
    unsigned long bi_dsp_freq;
    // ddr 频率 
    unsigned long bi_ddr_freq;
    
    // 配置 RAM 的起始地址及大小
    struct 
    {
ulong start;
ulong size;
}bi_dram[CONFIG_NR_DRAM_BANKS];
}bd_t;

gd_t : global data 数据结构定义,存放一些全局的系统初始化参数。
定义在 arch/arm/include/asm/global_data.h 文件中:
typedef structglobal_data {
// 板子相关的信息
bd_t *bd;
// 指示标志
unsigned long flags;
// 波特率
unsigned long baudrate;
// 串口是否已经初始化
unsigned long have_console;
// 环境变量参数地址
unsigned long env_addr;
// 校验环境变量是否有效
unsigned long env_valid;
// frame buffer 基地址
unsigned long fb_base;

#ifdef CONFIG_AT91FAMILY
/* "static data" needed by at91's clock.c */
unsigned long cpu_clk_rate_hz;
unsigned long main_clk_rate_hz;
unsigned long mck_rate_hz;
unsigned long plla_rate_hz;
unsigned long pllb_rate_hz;
unsigned long at91_pllb_usb_init;
#endif
#ifdef CONFIG_ARM
/* "static data" needed by most of timer.c on ARM platforms */
unsigned long timer_rate_hz;
unsigned long tbl;
unsigned long tbu;
unsigned long longtimer_reset_value;
unsigned long lastinc;
#endif
#ifdef CONFIG_IXP425
unsigned long timestamp;
#endif
// u-boot 在 RAM 中的起始地址
unsigned long relocaddr;
phys_size_t ram_size; /* RAM size */
unsigned long mon_len; /* monitor len */
unsigned long irq_sp; /* irq stack pointer */
unsigned long start_addr_sp; /* start_addr_stackpointer */
unsigned long reloc_off;
#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
unsigned long tlb_addr;
#endif
const void *fdt_blob; /* Our device tree, NULL if none */
void **jt;/* jump table */
char env_buf[32];/* buffer for getenv() before reloc. */
#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER)
unsigned long post_log_word; /* Record POST activities */
unsigned long post_log_res; /* success of POST test */
unsigned long post_init_f_time; /* When post_init_f started */
#endif
} gd_t;
 
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
bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f"); /* Pointer is writable since we allocated a register for it */
gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");

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);

/* 通过循环,调用 init_sequence 数组中的一系列初始化函数对开发板初始化 */
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\n", gd->mon_len); /*
* Ram is setup, size stored in gd !!
*/
debug("ramsize: %08lX\n", 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\n", 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\n", reg, addr);
#endif /* CONFIG_PRAM */

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
/* reserve TLB table */
addr -= (4096 * 4);

/* round down to next 64 kB limit */
addr &= ~(0x10000 - 1); gd->tlb_addr = addr; debug("TLB table at: %08lx\n", addr);
#endif
/* round down to next 4 kB limit */ addr &= ~(4096 - 1);
debug("Top of RAM usable for U-Boot at: %08lx\n", 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\n", 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\n",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\n",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\n",sizeof (gd_t), addr_sp); /* 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\n",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\n", 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 的起始地址和 size */

dram_init_banksize();
/* 打印 DRAM 的配置信息 */
display_dram_config();/* and display it */

/* u-boot 重定位后的起始地址 */
gd->relocaddr = addr;
/* 堆栈指针 */
gd->start_addr_sp = addr_sp;
/* 偏移量 = u-boot 重定位后的起始地址 - _TEXT_BASE(u-boot下载地址)*/
gd->reloc_off = addr - _TEXT_BASE;
debug("relocation Offset is: %08lx\n", gd->reloc_off);
memcpy(id, (void *)gd, sizeof(gd_t));

/* 代码重定位函数 relocate_code 有三个参数:
* 用户栈地址 - addr_sp
* 全局数据结构体地址 - id
* 代码重定位的起始地址 - addr
* 分别保存在寄存器 R0,R1,R2 中
*/
relocate_code(addr_sp, id, addr);

/* NOTREACHED - relocate_code() does not return */
}

回到 arch/arm/cpu/armv7/start.S 
ENTRY(relocate_code)
/* 保存参数 */
mov r4, r0/* save addr_sp */
mov r5, r1/* save addr of gd */
mov r6, r2/* save addr of destination */

/* 设置栈 */
stack_setup:
/* sp = addr_sp */
mov sp, r4 /* r0 = u-boot 的链接地址,r6 = u-boot 重定位后的地址 */ adr r0, _start

/* 判断 u-boot 是否已经搬运到目的地址 */
cmp r0, r6

/* r0 = r6 ,不需要重定位,偏移地址 r9 = 0 */
moveq r9, #0/* no relocation. relocation offset(r9) = 0 */
/* r0 = r6 ,跳到 clear_bss 执行 */
beq clear_bss/* skip relocation */

/* r1 = r6 = 重定位后的地址 */
mov r1, r6/* r1 <- scratch for copy_loop */
/* r3 = _image_copy_end_ofs = 需要拷贝的文件大小 */
ldr r3, _image_copy_end_ofs
/* r2 = r0 + r3 = 需要拷贝源码的结束地址 */
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]    */
/* r0 < r2 ,则跳转到 copy_loop 继续搬移 */
blo copy_loop

/* 在链接文件 /arch/arm/cpu/u-boot.lds 中有两个段:
* .dynsym 动态符号表,.rel.dyn 动态重定位表。
     * 下面程序的主要工作就是将 .dynsym 和 .rel.dyn 重定位,
* 并遍历 .rel.dyn,根据重定位表中的信息将符号表中的函数地址等进行重定位 
*/
/*
* 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
b clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start /* 清 BSS 段 */ clear_bss:
/* bss段的开始偏移地址 */
ldr r0, _bss_start_ofs
/* bss段的结束偏移地址 */
ldr r1, _bss_end_ofs
mov r4, r6/* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000/* clear   */

/* 通过一个循环将 BSS 清零 */
clbss_l:cmp r0, r1/* clear loop... */
bhs clbss_e/* if reached end of bss, exit */
str r2, [r0]
add r0, r0, #4
b clbss_l
clbss_e: /* * We are done. Do not return, instead branch to second part of board
 * initialization, now running from RAM.
 */
jump_2_ram:
/* 禁用 I-cache */ #ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0@ invalidate icache
mcr     p15, 0, r0, c7, c10, 4@ DSB
mcr     p15, 0, r0, c7, c5, 4@ ISB
#endif
/* 移动向量表 */ #if !defined(CONFIG_TEGRA20)
/* Set vector address in CP15 VBAR register */
ldr     r0, =_start
add     r0, r0, r9
mcr     p15, 0, r0, c12, c0, 0  @Set VBAR
#endif /* !Tegra20 */
ldr r0, _board_init_r_ofs adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* 设置传递给函数 board_init_r 的参数,全局结构 gd 在 SDRAM 中的起始地址和 U-Boot 在 SDRAM 中的起始地址 */
mov r0, r5/* gd_t */
mov r1, r6/* dest_addr */
/* 跳转到 board_init_r 函数 */
mov pc, lr
_board_init_r_ofs: .word board_init_r - _start
ENDPROC(relocate_code)

函数 board_init_r 定义在 arch/arm/lib/board.c 文件中:
void board_init_r(gd_t *id, ulong dest_addr)
{
ulong malloc_start;
#if !defined(CONFIG_SYS_NO_FLASH)
ulong flash_size;
#endif

gd = id;

gd->flags |= GD_FLG_RELOC;/* tell others: relocation done */
bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_R, "board_init_r");

/* u-boot 的长度 */
monitor_flash_len = _end_ofs;

/* 使能 caches */
enable_caches();

debug("monitor flash len: %08lX\n", 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
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); #ifdef CONFIG_LOGBUFFER
logbuff_init_ptrs();
#endif
#ifdef CONFIG_POST
post_output_backlog();
#endif

/* 对 SDRAM 中的 malloc 空间进行清零初始化 */
/* 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

#if !defined(CONFIG_SYS_NO_FLASH)
puts("Flash: ");

/* 计算 FLASH 的大小,并通过串口显示 */
flash_size = flash_init();
if (flash_size > 0) {
# ifdef CONFIG_SYS_FLASH_CHECKSUM
char *s = getenv("flashchecksum");

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 (s && (*s == 'y')) {
printf("  CRC: %08X", crc32(0,(const unsigned char *) CONFIG_SYS_FLASH_BASE,flash_size));
}
putc('\n');
# else /* !CONFIG_SYS_FLASH_CHECKSUM */
print_size(flash_size, "\n");
# endif /* CONFIG_SYS_FLASH_CHECKSUM */
} else {
puts(failed);
hang();
}
#endif

/* 初始化 NandFlash ,定义在 drivers/mtd/nand/nand.c */
#if defined(CONFIG_CMD_NAND)
puts("NAND:  ");
nand_init(); /* go init the NAND */
#endif

#if defined(CONFIG_CMD_ONENAND)
onenand_init();
#endif

/* 初始化 mmc */
#ifdef CONFIG_GENERIC_MMC
puts("MMC:   ");
mmc_initialize(gd->bd);
#endif

#ifdef CONFIG_HAS_DATAFLASH
AT91F_DataflashInit();
dataflash_print_info();
#endif

/* 初始化环境 ,定义在 common/env_common.c */
env_relocate();

#if defined(CONFIG_CMD_PCI) || defined(CONFIG_PCI)
arm_pci_init();
#endif

/* 初始化各类外设,如 LCD、USB 等,定义在 common/stdio.c */
stdio_init(); /* get the devices list going. */

/* 初始化跳转表,定义在 common/exports.c */
jumptable_init();

#if defined(CONFIG_API)
/* Initialize API */
api_init();
#endif

/* 初始化控制台,即标准输入、标准输出和标准错误,在这里都是串口。函数定义在 common/console.c */
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

/* 初始化中断 */
interrupt_init();
/* 使能中断 */
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 */

/* 从环境变量中获取 loadaddr 参数,得到需要加载的地址 */
/* 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\n");
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

/* 这个函数主要是判断是进入自启动模式还是交互模式。
* 如果设置了 bootcmd 和 bootdelay 参数,默认进入自启动模式;
* 若其中任一参数没有设置,就进入交互模式。
* main_loop() 定义在 common/main.c 
*/
/* 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 */
} 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_PREBOOT
char *p;
#endif
#ifdef CONFIG_BOOTCOUNT_LIMIT
unsigned long bootcount = 0;
unsigned long bootlimit = 0;
char *bcs;
char bcs_set[16];
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_BOOTCOUNT_LIMIT
bootcount = bootcount_load();
bootcount++;
bootcount_store (bootcount);
sprintf (bcs_set, "%lu", bootcount);
setenv ("bootcount", bcs_set);
bcs = getenv ("bootlimit");
bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0;
#endif /* CONFIG_BOOTCOUNT_LIMIT */

#ifdef CONFIG_MODEM_SUPPORT
debug ("DEBUG: main_loop:   do_mdm_init=%d\n", do_mdm_init);
if (do_mdm_init) {
char *str = strdup(getenv("mdm_cmd"));
setenv ("preboot", str);  /* set or delete definition */
if (str != NULL)
free (str);
mdm_init(); /* wait for modem connection */
}
#endif  /* CONFIG_MODEM_SUPPORT */ #ifdef CONFIG_VERSION_VARIABLE {
setenv ("ver", version_string);  /* set version variable */
}
#endif /* CONFIG_VERSION_VARIABLE */
#ifdef CONFIG_SYS_HUSH_PARSER u_boot_hush_start ();
#endif
#if defined(CONFIG_HUSH_INIT_VAR) hush_init_var ();
#endif

#ifdef CONFIG_PREBOOT
if ((p = getenv ("preboot")) != NULL) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1);/* disable Control C checking */
# endif run_command_list(p, -1, 0); # ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev);/* restore Control C checking */
# endif
}
#endif /* CONFIG_PREBOOT */
#if defined(CONFIG_UPDATE_TFTP) update_tftp (0UL);
#endif /* CONFIG_UPDATE_TFTP */

#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s = getenv ("bootdelay");
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;

debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);

#if defined(CONFIG_MENU_SHOW)
bootdelay = menu_show(bootdelay);
#endif
# ifdef CONFIG_BOOT_RETRY_TIME
init_cmd_timeout ();
# endif /* CONFIG_BOOT_RETRY_TIME */

#ifdef CONFIG_POST
if (gd->flags & GD_FLG_POSTFAIL) {
s = getenv("failbootcmd");
}
else
#endif /* CONFIG_POST */
#ifdef CONFIG_BOOTCOUNT_LIMIT
if (bootlimit && (bootcount > bootlimit)) {
printf ("Warning: Bootlimit (%u) exceeded. Using altbootcmd.\n",(unsigned)bootlimit);
s = getenv ("altbootcmd");
}
    else
#endif /* CONFIG_BOOTCOUNT_LIMIT */
/* 从命令行获得 bootcmd 参数 */
s = getenv ("bootcmd");

debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");

if (bootdelay != -1 && s && !abortboot(bootdelay)) {
# ifdef CONFIG_AUTOBOOT_KEYED
int prev = disable_ctrlc(1);/* disable Control C checking */
# endif

/* 解析 bootcmd 命令,并执行 */
run_command_list(s, -1, 0);

# ifdef CONFIG_AUTOBOOT_KEYED
disable_ctrlc(prev);/* restore Control C checking */
# endif
}

# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd");
if (s)
run_command_list(s, -1, 0);
}
#endif /* CONFIG_MENUKEY */
#endif /* CONFIG_BOOTDELAY */

/*
* Main Loop for Monitor Command Processing
*/
#ifdef CONFIG_SYS_HUSH_PARSER
parse_file_outer();
/* This point is never reached */
for (;;);
#else
for (;;) {
#ifdef CONFIG_BOOT_RETRY_TIME
if (rc >= 0) {
/* Saw enough of a valid command to
* restart the timeout.
*/
reset_cmd_timeout();
}
#endif
len = readline (CONFIG_SYS_PROMPT);

flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag |= CMD_FLAG_REPEAT;
#ifdef CONFIG_BOOT_RETRY_TIME
else if (len == -2) {
/* -2 means timed out, retry autoboot
*/
puts ("\nTimed out waiting for command\n");
# ifdef CONFIG_RESET_TO_RETRY
/* Reinit board to run initialization code again */
do_reset (NULL, 0, 0, NULL);
# else
return; /* retry autoboot */
# endif
}
#endif if (len == -1) puts ("<INTERRUPT>\n");
else
rc = run_command(lastcommand, flag);

if (rc <= 0) {
/* invalid command or not repeatable, forget it */
lastcommand[0] = 0;
}
}
#endif /*CONFIG_SYS_HUSH_PARSER*/
}

Atmel SAMA5D3 U-Boot 启动流程简单分析相关推荐

  1. Spring Boot————Spring Boot启动流程分析

    一.引言 Spring Boot 的启动虽然仅仅是执行了一个main方法,但实际上,运行流程还是比较复杂的,其中包含几个非常重要的事件回调机制.在实际生产开发中,有时候也会利用这些启动流程中的回调机制 ...

  2. 【鸿蒙OS开发入门】06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 启动init进程

    [鸿蒙OS开发入门]06 - 启动流程代码分析之KernelOS:之启动Linux-4.19 Kernel内核 一.head.S 启动start_kernel() 1.1 start_kernel() ...

  3. ZYNQ启动流程之分析BootRoM

    ZYNQ启动流程之分析BootRoM 一.fsbl由谁来启动 1.背景 2.需要做的事 3.这些事由谁来做----BootRoM 二.何为BootRoM 三.SD卡启动方式 一.fsbl由谁来启动 1 ...

  4. busybox启动流程简单解析:从init到shell login

    https://www.cnblogs.com/arnoldlu/p/10868354.html busybox启动流程简单解析:从init到shell login 关键词:kernel_init() ...

  5. 【鸿蒙OS开发入门】13 - 启动流程代码分析之第一个用户态进程:init 进程 之 init 任务详解

    [鸿蒙OS开发入门]13 - 启动流程代码分析之第一个用户态进程:init 进程 之 init 任务详解 一. /etc/init.cfg 系统默认cfg:启动lo回环网卡 1.1 init.Hi35 ...

  6. spring boot 启动流程分析

    spring boot 框架凭借极简配置,一键运行和强大的第三方框架集成等特点,受到广大开发者的青睐,基本成为java开发中必不可少的基础的框架.spirng boot带给我们这么多便利的背后,它都做 ...

  7. lk启动流程详细分析

    转载请注明来源:cuixiaolei的技术博客 这篇文章是lk启动流程分析(以高通为例),将会详细介绍下面的内容: 1).正常开机引导流程 2).recovery引导流程 3).fastboot引导流 ...

  8. 海思uboot启动流程详细分析(二)

    1. 第二个start.S 从start_armboot开始,在startup.c中有包含#include <config.h> 在config.h中: /* Automatically ...

  9. uboot启动流程详细分析(基于i.m6ull)

    uboot介绍 uboot就是一段引导程序,在加载系统内核之前,完成硬件初始化,内存映射,为后续内核的引导提供一个良好的环境.uboot是bootloader的一种,全称为universal boot ...

最新文章

  1. python自定义配置文件读取_python读取和自定义配置文件的方法
  2. 苏宁推出物联网应用“云居”
  3. 三星智能电视将用户语音隐私泄露给第三方?
  4. 大数据存在的安全隐患该如何防患
  5. SEO知识分享一,选择关键词
  6. C++ std::multiset 删除 查找 重复元素中的特定元素
  7. 关于继承的理解,自带有白话文,更适合编程小白新手,简单易理解
  8. java springboot android 安卓点餐外卖源码
  9. 什么是竞品分析?竞品分析全流程解析
  10. vscode 使用pem文件免密连接服务器
  11. 聚合数据API接口调用方法
  12. 你们以为洗白了张柏芝,自己就不是婊子
  13. CodeForces 416C Booking System
  14. 使用idea快速生成项目树结构
  15. 深入理解Linux进程描述符task_struct结构体
  16. Fiddler与iPhone配合拦截首都图书馆微信小程序请求并多线程模拟请求刷预约 Java HttpGet HttpPost
  17. C语言中“->”的意义
  18. (六十四)朴素贝叶斯算法
  19. H3CTE讲师分享H3C广域网接口和线缆实验
  20. keras实现手写数字识别

热门文章

  1. 解决mysql特殊字符或者Emoji表情插入报错问题
  2. HC15产品设计初衷
  3. 【经验分享】我为什么不建议你读一年制的研究生
  4. eml企业通讯录管理系统经典版V5.4.14适配phpstudy8修改版
  5. DSGV1DS中国制造已经在互联网时代更加的符合用户需求
  6. dedec教程:修改织梦Dedecms跳转提示信息的方法
  7. SLC、MLC、TLC三者的区别
  8. TBSS和dpabifiber
  9. 全民享益源码开发中的系统
  10. oracle-rdbms,Oracle数据库管理脚本介绍 (RDBMS目录下)