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().
*/ #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, # /* -byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, # /* -byte alignment for ABI compliance */
mov r8, sp /* GD is above SP */
然后调用board_init_f(0),这是因为r0可以作为输入参数:
mov r0, #
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 = ; memset((void *)gd, , 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", ,
(uintptr_t)gd->fdt_blob); for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != ) {
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", , CONFIG_PRAM);
addr -= (reg << ); /* 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 */
gd->tlb_size = * ;
addr -= gd->tlb_size; /* round down to next 64 kB limit */
addr &= ~(0x10000 - ); gd->tlb_addr = addr;
debug("TLB table from %08lx to %08lx\n", addr, addr + gd->tlb_size);
#endif /* round down to next 4 kB limit */
addr &= ~( - );
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 &= ~( - ); debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> , 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 >> , 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); #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, ); addr_sp -= fdt_size;
new_fdt = (void *)addr_sp;
debug("Reserving %zu Bytes for FDT at: %08lx\n",
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\n",
CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ, addr_sp);
#endif
/* leave 3 words for abort-stack */
addr_sp -= ; /* 8-byte alignment for ABI compliance */
addr_sp &= ~0x07;
#else
addr_sp += ; /* 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());
#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\n", 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, # /* no relocation. relocation offset(r9) = */
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, #]
and r7, r1, #0xff
cmp r7, # /* relative fixup? */
beq fixrel
cmp r7, # /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR # /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #] /* 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, # /* each rel.dyn entry is 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 -bit BSS word */
addlo r0, r0, # /* 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\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
serial_initialize(); 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 /* 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 > ) {
# 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") == ) {
printf(" CRC: %08X", crc32(,
(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 #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", , 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());
#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 = ;
uchar memsz[]; #ifdef CONFIG_PRAM
pram = getenv_ulong("pram", , 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) / ;
#endif
#endif
sprintf((char *)memsz, "%ldk", (gd->ram_size / ) - 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内核。
uboot 2013.01 代码简析(3)第二阶段初始化的更多相关文章
- uboot 2013.01 代码简析(2)第一阶段初始化
uboot执行"make smdk2410_config"之后就可以进行编译了,可以执行make命令进行编译, 因为整个输出太长,我仅仅列出部分最关键的输出(部分我不关心的内容直接 ...
- uboot 2013.01 代码简析(1)开发板配置
u-boot下载地址:ftp://ftp.denx.de/pub/u-boot/u-boot-2013.01.01.tar.bz2 下载之后对该文件进行解压. 我试着分析smdk2410_config ...
- uboot 2013.01 s3c6400编译失败
通常我们对s3c6410平台开发u-boot是在s3c6400的基础上修改而成的,但是从uboot 2013.01这个版本之后的版本都把smdk6400对应的配置给删除了. 这是因为该版本smdk64 ...
- OpenStack之虚机冷迁移代码简析
OpenStack之虚机冷迁移代码简析 前不久我们看了openstack的热迁移代码,并进行了简单的分析.真的,很简单的分析.现在天气凉了,为了应时令,再简析下虚机冷迁移的代码. 还是老样子,前端的H ...
- WinForm 自动完成控件实例代码简析
在Web的应用方面有js的插件实现自动完成(或叫智能提示)功能,但在WinForm窗体应用方面就没那么好了. TextBox控件本身是提供了一个自动提示功能,只要用上这三个属性: AutoComple ...
- Log4js 工作原理及代码简析
本文地址 http://www.cnblogs.com/jasonxuli/p/6518650.html log4js 版本 0.6.16, 最新版1.1.1 大体类似. 使用 log4j ...
- Hive Metastore 代码简析
1. hive metastore 内部结构 1.1 包结构 从package结构来看,主要的5个package,让我们来看看这几个package的内容 (1) metastorepackage是m ...
- GPXReader工具代码简析
完整的文件在TerraExplorer Pro的默认安装目录下C:\Program Files (x86)\Skyline\TerraExplorer Pro\Tools\GPXReader: 如果你 ...
- ortp代码简析
ortp初始化 /** * Initialize the oRTP library. You should call this function first before using * ...
随机推荐
- windows小游戏之扫雷技巧
通过单击即可挖开方块.如果挖开的是地雷,则您输掉游戏. 如果方块上出现数字,则表示在其周围的八个方块中共有多少颗地雷.
- WordPress系列之钩子hook的作用及基本用法
WordPress 的插件机制实际上只的就是这个 Hook 了,它中文被翻译成钩子,允许你参与 WordPress 核心的运行,是一个非常棒的东西,下面我们来详细了解一下它.钩子分类 钩子分为两种,一 ...
- 闪屏(Splash)
好久没弄ReactNative了, 写个怎样实现闪屏(Splash)的文章吧. 注意: (1) 怎样切换页面. (2) 怎样使用计时器TimerMixin. (3) 怎样使用动画效果. (4) 怎样载 ...
- Lua学习十一----------Lua迭代器
© 版权声明:本文为博主原创文章,转载请注明出处 Lua迭代器 - 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址 - Lu ...
- 在Ubuntu 16.04下安装 virtualbox 5.2
sudo sh -c 'echo "deb http://download.virtualbox.org/virtualbox/debian xenial contrib" ...
- DDD架构Sample
http://dddsamplenet.codeplex.com/SourceControl/latest#DDDSample-Vanilla/Application/IBookingService. ...
- 【问题记录】mysql设置任意ip访问
# 给username用户授予可以用任意IP带密码password访问数据库 GRANT ALL PRIVILEGES ON *.* TO 'username'@'%'IDENTIFIED BY 'p ...
- Apatar 学习文档
1. Apatar数据集成简介 Apatar是一个开源跨平台数据集成工具,可以安装和运行在任何机器这有一些类型的用户界面.该工具用于启用批处理数据集成和提供简单的用户界面,这样任何人,不仅仅是技术 ...
- Gradle 的配置和引用
我们的Android studio工程有时会存在很多共同的构建包 这里我会新建一个gradle 文件 config.gradle ext{ android = [ applicationId : &q ...
- QT应用程序 安装路径中文异常问题
[1]QT 安装中文路径启动异常问题 最近在搞一个很简单的QT应用程序,开发环境VS2017 + QT5.9,线上异常报错:安装中文路径下启动崩溃~~~~ 最后,本地调试Debug版本,发现安装中文路 ...