XiaomiRouter自学之路(07-U-boot启动过程)
U-boot的环境编译等都正常,后面需要修改U-boot的具体代码,如上面说的修改波特率等,在修改代码前,有必要了解U-boot的执行过程,这样我们就可以快速的定位到代码执行的大概位置,进行修改验证。
1.系统上电后由uboot的链接文件\board/rt2880/u-boot.lds知程序入口点是ENTRY(_start)。
2._start函数位于/cpu/ralink_soc/start.S中。
.globl _start
.text
_start:
RVECENT(reset,0) /* U-boot entry point */
RVECENT(reset,1) /* software reboot */
3._start函数一直往下执行,会看到以下信息,即CPU频率源的选择,各变量的值即05-U-boot配置编译烧录里面提到的CPU PLL配置参数。
#if defined(CPLL_FROM_480MHZ)
li a0, 1<<11
#elif defined(CPLL_FROM_XTAL)
li a0, 1<<12
#elif defined(CPLL_FROM_CONF)
li a0, CPLL_MULTI_RATIO_CFG
sll a0, a0, 2
ori a0, a0, CPLL_DIV_RATIO_CFG
sll a0, a0, 6
ori a0, a0, CPLL_SSC_CFG
#endif
#if (defined(CPLL_FROM_480MHZ)||defined(CPLL_FROM_XTAL)||defined(CPLL_FROM_CONF))
bal init_cpu_pll
nop
#else
la t0, RALINK_SYSCTL_BASE+0x10
lw t1, 0(t0)
srl t1, t1, 4
andi t1, t1, 0x3
beqz t1, CPLL_DONE
addiu t2, zero, 3
beq t1, t2, CPLL_DONE
li a0, CPLL_DEFAULT_CFG
bal init_cpu_pll
nop
#endif
CPLL_DONE:
4.时钟初始化后接着往下执行,就是DDR的初始化,再往下就可以看到如下语句
la t9, board_init_f
5.board_init_f是一个函数,位于/lib_mips/board.c中,截取部分代码如下:
...
timer_init();
env_init(); /* initialize environment */
init_baudrate(); /* initialze baudrate settings */
serial_init(); /* serial communications setup */
console_init_f();
display_banner(); /* say that we are here */
checkboard();
init_func_ram();
led_init(); /* turn_on_led */
gpio_init();
...
6.直接观察代码函数,可以很清楚其意思,但真正的执行过程等,可能需要后期再深入研究
7.board_init_f执行完,回到_start接着往后,又会看到如下语句
la t9, board_init_r
8.board_init_r也是位于/lib_mips/board.c中的一个函数
...
/* Initialize devices */
devices_init ();
jumptable_init ();
/* Initialize the console (after the relocation and devices init) */
console_init_r ();
...
9.board_init_r函数往下执行可以看到如下信息,有一个DETECT_WPS()的检查,这其实是在开机时长按WPS按键4S以上,使之进入从web更新firware的一个功能,在后面会具体讲解这个功能。
...
printf( "\nPress press WPS button for more than 2 seconds to run web failsafe mode\n\n" );
printf( "WPS button is pressed for: %2d second(s)", counter );
while( DETECT_WPS() ) {
// LED ON and wait 0.2s
LEDON();
udelay( 200000 );
// LED OFF and wait 0.8s
LEDOFF();
udelay( 800000 );
counter++;
// how long the WPS button is pressed?
printf("\b\b\b\b\b\b\b\b\b\b\b\b%2d second(s)", counter);
if ( !DETECT_WPS() ){
break;
}
if ( counter >= 4 ){
break;
}
}
...
10.board_init_r函数往下执行
...
OperationSelect();
while ( timer1 > 0 ) {
--timer1;
/* delay 100 * 10ms */
for ( i=0; i<100; ++i ) {
if ( ( my_tmp = tstc() ) != 0 ) { /* we got a key press */
timer1 = 0; /* no more delay */
BootType = getc();
if ( ( BootType < '0' || BootType > '5' ) && ( BootType != '7' ) && ( BootType != '8' ) && ( BootType != '9' ) )
BootType = '3';
printf( "\n\rYou choosed %c\n\n", BootType );
break;
}
udelay(10000);
}
printf ("\b\b\b%2d ", timer1);
}
...
11.从上面的代码可以看出,该处就是u-boot倒计时的地方,timer1默认为5,倒计时为5s。在倒计时的过程获取键盘的字符,将输入的数值保存在BootType中,默认或输入其他字符则BootType=3。当BootType有值后,就对BootType的值进行判断处理,如下:
switch(BootType) {
case '1':
break;
case '2':
break;
case '4':
printf(" \n%d: System Enter Boot Command Line Interface.\n", SEL_ENTER_CLI);
printf ("\n%s\n", version_string);
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;) {
main_loop ();
}
break;
...
12.对于每个数值的具体功能这边进行概念性介绍,更深入的实现代码将在下一章节进行说明,如下:
- 0: System Load Linux then write to Flash via Serial.
通过串口将系统更新到Flash. - 1: Load system code to SDRAM via TFTP.
通过TFTP将系统更新到SDRAM上. - 2:Load system code then write to Flash via TFTP.
通过TFTP将系统下载到SDRAM上,然后更新到Flash - 3: Boot system code via Flash (default).
从Flash的特定位置读取系统然后启动 - 4: Entr boot command line interface.
进入命令行操作模式 - 7: Load Boot Loader code then write to Flash via Serial.
通过串口将u-boot下载到SDRAM上,然后更新到Flash - 8: System Load UBoot to SDRAM via TFTP.
通过TFTP将u-boot更新到SDRAM上. - 9: Load Boot Loader code then write to Flash via TFTP.
通过TFTP将u-boot下载到SDRAM上,然后更新到Flash
我们从_start开始粗略分析了U-boot的启动流程,这样在后面代码修改的过程中应该能直观些。
U-boot启动过程的分析就到这边,有感悟时会持续会更新。
注:以上内容都是本人在学习过程积累的一些心得,难免会有参考到其他文章的一些知识,如有侵权,请及时通知我,我将及时删除或标注内容出处,如有错误之处也请指出,进行探讨学习。文章只是起一个引导作用,详细的数据解析内容还请查看XiaomiRouter相关教程,感谢您的查阅。