u-boot2013.01 smdk2410 启动第二阶段分析

时间:2022-02-12 16:31:55
2016/7/16
u-boot 第二阶段的代码就进入了一个C语言的环境。
进入这个阶段你的函数的board_init_r
void board_init_r(gd_t *id, ulong dest_addr) 
1. board_init_r 函数分析
    
  gd->flags |= GD_FLG_RELOC;    /* tell others: relocation done */

         //此时的gd到底是指向什么位置呢? 在代码中,并没有发现对gd位置的重定向。只能说gd目前还处于sdram 的低端内存区域。而不是高端内存区域
       //可以知道的是代码运行到这里,重定位已经完成。
       
        /* Setup chipselects */
        board_init();    //板级相关的初始化
              
     /* arch number of SMDK2410-Board */
                    gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

                    /* adress of boot parameters */
                    gd->bd->bi_boot_params = 0x30000100;

                    icache_enable();
                    dcache_enable();

                    //在 board_init 中对bi_arch_number和 bi_boot_params 两个重要的参数进行了赋值。这是的board 是2410。
                    //在移植2440的时候,需要适当的进行修改。 另外一个参数 启动的参数。这两个参数是需要传递给内核的。非常重要
                    //除此之外,还使能了cache
        
     serial_initialize();
        //串口的初始化
        
        /* 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);
        //初始第一阶段的malloc空间
    
     
     /* arch number of SMDK2410-Board */
                    gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

                    /* adress of boot parameters */
                    gd->bd->bi_boot_params = 0x30000100;

                    icache_enable();
                    dcache_enable();
           
      
 #ifdef CONFIG_GENERIC_MMC  //如果单板支持mmc。只需要在单板文件中定义 CONFIG_GENERIC_MMC 即可
        puts("MMC:   ");
        mmc_initialize(gd->bd);
        #endif

        /* initialize environment */
        if (should_load_env())
            env_relocate();


      //初始化环境变量   环境变量有两种。一种是默认的,另一种是flash保存的环境变量(优先执行)
      
      stdio_init();    /* get the devices list going. */  //得到设备清单
  /* Initialize the list */
      INIT_LIST_HEAD(&(devs.list));   
      drv_system_init ();
       serial_stdio_init ();  
                     //主要是串口信息的初始化
    jumptable_init(); //跳转表的出初始化,暂时不明白干嘛用的
      console_init_r();    /* fully init console as a device */
      
      /* set up exceptions */
        interrupt_init();
        /* enable exceptions */
        enable_interrupts();
        //设置中断和使能中断
       /* Initialize from environment */
        load_addr = getenv_ulong("loadaddr", 16, load_addr);   (原值    0x30800000)
        
            eth_initialize(gd->bd) 

            //网卡的初始化
                  
     
   /* main_loop() can return to retry autoboot, if so just run it again. */
        for (;;) {
            main_loop();
        }


        //进入一个主循环
2.main_loop 分析
    在main_loop中有两种实现方式:一种是使用HUSH的这种主循环的方式,另一种是裸机代码形式的主循环 (参考连接 http://blog.csdn.net/andy_wsj/article/details/8614905)
    
    逻辑代码的形式
    
 
   char *s;
    int bootdelay;


    //定义两个变量
    
  
  s = getenv ("bootdelay");
    bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
            int strict_strtol


            功能:将一个字符串转换sigend long型。
        //将环境变量的字符串转换为一个数字
        
    s = getenv ("bootcmd");
    //获得boot命令
    
    if (bootdelay != -1 && s && !abortboot(bootdelay)) {
        run_command_list(s, -1, 0);
        }


    //在倒计时计数前,没有空格,则执行run_command_list
    //此时的s 表示的是bootcmd  是一个自启动命令
    //bootcmd  nand read.jffs 0x300007fc0  kernel
  //bootm 0x300007fc0   //内核启动
 
  /如果输入了空格
 
for(;;)
      len = readline (CONFIG_SYS_PROMPT);
       strcpy (lastcommand, console_buffer);
         rc = run_command(lastcommand, flag);
 
 3. int run_command(const char *cmd, int flag) 分析
            //builtin_run_command can return 0 or 1 for success, so clean up its result.
             builtin_run_command(cmd, flag)   //  readline 大于零的情况 flag = 0;    /* assume no special flags for now */      flag |= CMD_FLAG_REPEAT;
                         char cmdbuf[CONFIG_SYS_CBSIZE];    /* working copy of cmd        */  //存储每一个cmd CONFIG_SYS_CBSIZE 256 命令的长度限制在256字节
                        char *token;            /* start of token in cmdbuf    */            
                        char *sep;            /* end of token (separator) in cmdbuf */
                        char finaltoken[CONFIG_SYS_CBSIZE];
                        char *str = cmdbuf;                                                                                   //为后续的while 解析做准备
                        char *argv[CONFIG_SYS_MAXARGS + 1];    /* NULL terminated    */
                        int argc, inquotes;
                        int repeatable = 1;                                                                                   //命令的可重复性。在中断输入回车是否执行上一条命令
                        int rc = 0;
                                         
                        clear_ctrlc();        /* forget any previous Control C */  //清楚CTRL+C 中止的命令
                            
                        if (strlen(cmd) >= CONFIG_SYS_CBSIZE) {
                        puts ("## Command too long!\n");
                        return -1;
                        }


                         //限制长度
                         
                         strcpy (cmdbuf, cmd);
                         //将形参传入的cmd 拷贝到cmdbuf中  
                         
                      
            while (*str) {
                              /*
                          * Find separator, or string end
                         * Allow simple escape of ';' by writing "\;"
                          */
                           for (inquotes = 0, sep = str; *sep; sep++) {
                                  if ((*sep=='\'') &&
                                    (*(sep-1) != '\\'))
                                   inquotes=!inquotes;

                                     if (!inquotes &&
                                       (*sep == ';') &&    /* separator        */
                                      ( sep != str) &&    /* past string start    */
                                         (*(sep-1) != '\\'))    /* and NOT escaped    */
                                       break;
                                        }


                                        //解析命令, 一个个提取出来。 命令的分割是以 \;作为标识的
                                
        
                               token = str;
                              
                                /* find macros in this token and replace them */
                               process_macros (token, finaltoken);                


                                        //解析宏
                                        
                         
                   /* Extract arguments */
                      if ((argc = parse_line (finaltoken, argv)) == 0) {
                                rc = -1;    /* no command at all */
                                 continue;
                             }


                                         //提取参数
                                                             int parse_line (char *line, char *argv[])
                                                             例如 md.w  0
                                                             ==> argv[0] = md.w   //命令
                                                                     argv[1] = 0            //参数
                                                                     返回值 argc = 2
                                                                     
                          
               if (cmd_process(flag, argc, argv, &repeatable))


                                         //执行命令


4.  (cmd_process(flag, argc, argv, &repeatable))     的执行过程
  
      
            enum command_ret_t rc = CMD_RET_SUCCESS; //一个枚举变量。执行运行状态
                enum command_ret_t {
                CMD_RET_SUCCESS,    /* 0 = Success */
                CMD_RET_FAILURE,    /* 1 = Failure */
                CMD_RET_USAGE = -1,    /* Failure, please report 'usage' error */
            };
                cmd_tbl_t *cmdtp;
                //一个命令的结构体 这个结构体非常的重要-->命令的回调函数就是在这个结构体cmd_tbl_t 的函数指针中
                        typedef struct cmd_tbl_s    cmd_tbl_t;
               
         
                         struct cmd_tbl_s {
                        char        *name;        /* Command Name            */                          // 命令的查找 find_name 中有(strncmp (cmd, cmdtp->name, len) == 0)
                        int        maxargs;    /* maximum number of arguments    */  
                        int        repeatable;    /* autorepeat allowed?        */                //命令的可重复性
                                        /* Implementation function    */
                        int        (*cmd)(struct cmd_tbl_s *, int, int, char * const []);        //函数指针。命令的具体执行 cmd_call 中 result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
                        char        *usage;        /* Usage message    (short)    */                 //命令的短 帮助信息 例如:输入help 在命令后边提示的
                        char        *help;        /* Help  message    (long)    */                //命令的长帮助信息  例如 bootcmd     -help
                        }
                       
                            /* Look up command in command table */
                            cmdtp = find_cmd(argv[0]);
                            //在命令表中 查找命令 。
                            //命令表具体又在哪里呢?在u-boot.lds链接脚本中有关于段的分配。其中就有u-boot cmd 段
                            //同时。每一个u-boot 的命令。都使用U_BOOT_CMD 进行修饰。这个宏就是将这些cmd 分配到对应的段中
            
                                 . = ALIGN(4);
                         .u_boot_list : {
                        _u_boot_list__start = .;
                        _u_boot_list_cmd__start = .;
                        *(SORT(.u_boot_list.cmd.*));
                        _u_boot_list_cmd__end = .;
                        _u_boot_list_env_clbk__start = .;
                        *(SORT(.u_boot_list.env_clbk.*));
                        _u_boot_list_env_clbk__end = .;
                        *(SORT(.u_boot_list.*));
                        _u_boot_list__end = .;
                         } 


                        #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)        \
                        U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)  Command.h (\include)    
                        ..... //省略一些
                
        #define ll_entry_declare(_type, _name, _section_u, _section_d)        \
                        _type _u_boot_list_##_section_u##_##_name __attribute__((    \
                        unused,    aligned(4),                \
                        section(".u_boot_list."#_section_d"."#_name)))
                        //find_cmd 函数的具体分析。后续在分析
                
         
       if (cmdtp == NULL) {
                printf("Unknown command '%s' - try 'help'\n", argv[0]);
                return 1;
                }
                //如果没有相应的命令则打印提示 Unknown command '%s' - try 'help'\n
                
                if (argc > cmdtp->maxargs)
                rc = CMD_RET_USAGE;
                //判断参数的格式。是否大于参数的最大值 //这个maxargs 应当是从find_cmd 中查找到的参数,返回而得到的
                //如果大于。则标记为 CMD_RET_USAGE
                
          
         /* If OK so far, then do the command */
                if (!rc) {
                    rc = cmd_call(cmdtp, flag, argc, argv);
                    *repeatable &= cmdtp->repeatable;
                }
                //如果rc 等于 CMD_RET_SUCCESS  。则执行cmd对应的函数
                if (rc ==  CMD_RET_USAGE )
                    rc = cmd_usage(cmdtp);
                return rc;
                //如果rc == CMD_RET_USAGE ,则打印usage 信息
            


5.cmd_call(cmdtp, flag, argc, argv);  函数分析
    Call a command function.
    static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

      
     result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
            //执行回调函数
  int        (*cmd)(struct cmd_tbl_s *, int, int, char * const []);    
            //cmd 函数的原型     
        
         下边以bootm为例分析
         int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
         //bootm 的函数原型
6.bootm 分析
        6.1  命令模块的框架
        文件的命名cmd_xxx.c
        框架:
        #include <common.h>
        #include <command.h>
        int do_xxx (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
        {
            ....
            return 0;
        }
        
        U_BOOT_CMD(
        xxx,    1,    0,    do_xxx,
        "short usage message",
        " long usage message"
    );


    6.2 bootm 实现的分析
        文件 cmd_bootm.c
        
        6.2.1 分析U_BOOT_CMD这个宏
         # define _CMD_HELP(x) x,  //首先这里的宏定义 # 后边有个空格,这样的语法,还需要了解
                    # define _CMD_COMPLETE(x)
                    
                        #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,        \
                            _usage, _help, _comp)            \
                    { #_name, _maxargs, _rep, _cmd, _usage,            \
                        _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
                ==>        
                #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,    _usage, _help, _comp)            \
                    { #_name, _maxargs, _rep, _cmd, _usage,    _help,}
                    
                    
                    
                        #define ll_entry_declare(_type, _name, _section_u, _section_d)        \
                    _type _u_boot_list_##_section_u##_##_name __attribute__((    \
                            unused,    aligned(4),                \
                        section(".u_boot_list."#_section_d"."#_name)))
            ==>整理一下形式
                    #define ll_entry_declare(_type, _name, _section_u, _section_d)        \
                    _type _u_boot_list_##_section_u##_##_name __attribute__((    unused,    aligned(4),section(".u_boot_list."#_section_d"."#_name)))
                            
                                    
                        #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
                    ll_entry_declare(cmd_tbl_t, _name, cmd, cmd) =            \
                        U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,    \
                                        _usage, _help, _comp);                    
            ==》
                #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
                    cmd_tbl_t _u_boot_list_##cmd##_##cmd_tbl_t __attribute__((    unused,    aligned(4),section(".u_boot_list."#cmd"."#_name)))   \
                    { #_name, _maxargs, _rep, _cmd, _usage,    _help,}                            
                                        
                                                                
                    #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)        \
                        U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
                        
                ==》
                    #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)        \
                        cmd_tbl_t _u_boot_list_##cmd##_##cmd_tbl_t __attribute__((    unused,    aligned(4),section(".u_boot_list."cmd"."_name)))   \
                    { #_name, _maxargs, _rep, _cmd, _usage,    _help,}        
                    
                    
                    U_BOOT_CMD(
                bootm,    CONFIG_SYS_MAXARGS,    1,    do_bootm,
                "boot application image from memory", bootm_help_text
                );    
            ==>_name:bootm
                  _maxargs: CONFIG_SYS_MAXARGS(16)
                    _rep:    1
                    _cmd:do_bootm
                    _usage:     "boot application image from memory"  //字符串
                    _help :    bootm_help_text                 //字符串  ==>字符数组的首地址  
                        
                        
                bootm_help_text:
                    static char bootm_help_text[] =
                "[addr [arg ...]]\n    - boot application image stored in memory\n"
                "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
                "\t'arg' can be the address of an initrd image\n"
                "\nSub-commands to do part of the bootm sequence.  The sub-commands "
                "must be\n"
                "issued in the order below (it's ok to not issue all sub-commands):\n"
                "\tstart [addr [arg ...]]\n"
                "\tloados  - load OS image\n"
                    "\tcmdline - OS specific command line processing/setup\n"
                "\tbdt     - OS specific bd_t processing\n"
                "\tprep    - OS specific prep before relocation or go\n"
                "\tgo      - start OS";
            }

                    cmd_tbl_t _u_boot_list_do_bootm_cmd_tbl_t __attribute__((    unused,    aligned(4),section(".u_boot_list."do_bootm"."bootm)))   \
                    { bootm, 16, 1, do_bootm, "boot application image from memory",    
                "[addr [arg ...]]\n    - boot application image stored in memory\n"
                "\tpassing arguments 'arg ...'; when booting a Linux kernel,\n"
                "\t'arg' can be the address of an initrd image\n"
                "\nSub-commands to do part of the bootm sequence.  The sub-commands "
                "must be\n"
                "issued in the order below (it's ok to not issue all sub-commands):\n"
                "\tstart [addr [arg ...]]\n"
                "\tloados  - load OS image\n"
                    "\tcmdline - OS specific command line processing/setup\n"
                "\tbdt     - OS specific bd_t processing\n"
                "\tprep    - OS specific prep before relocation or go\n"
                "\tgo      - start OS";,}    ;
                //观察这个存储在u_boot_list段中的这个  _u_boot_list_do_bootm_cmd_tbl_t可以知道。这是在定义一个 cmd_tbl_t类型的变量,同时对它进行初始化操作
                                    c语言中的#号和##号的作用    http://blog.chinaunix.net/uid-27666459-id-3772549.html