XiaomiRouter自学之路(07-U-boot启动过程)

题图:gratisography

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相关教程,感谢您的查阅。

推荐阅读更多精彩内容