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上,然后更新到Flash3: 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上,然后更新到Flash8: 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启动过程的分析就到这边,有感悟时会持续会更新。