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

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

时间: 2024-08-04 19:27:00

u-boot2013.01 smdk2410 启动第二阶段分析的相关文章

12.u-boot2013.01 smdk2410 启动第一阶段分析.txt

u-boot2013.01 smdk2410  -->2440 启动分析 1.u-boot启动第一阶段 start.S (arch\arm\cpu\arm920t) _start: b start_code 1.1 set the cpu to SVC32 mode mrs r0, cpsr bic r0, r0, #0x1f orr r0, r0, #0xd3 msr cpsr, r0 1.2 关闭看门狗 # define pWTCON 0x53000000 ldr r0, =pWTCON m

启动第二个Activity

启动第二个Activity activity_main.xml文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height

uboot启动第一阶段分析

u-boot第一阶段分析: 第一阶段主要是在start.S中 .globl _start  //声明_start是全局变量,和c语言中的extern相似,声明此变量,并且告诉链 接器此变量是全局的,外部可以访问.由board\100ask24x0\u-boot.lds中 ENTRY(_start)可知,_start是程序入口地址,一开始从nor_flash启动,_start 为0,当执行后面的地址重载后,_start就变为TEXT_BASE = 0x33F80000了 _start: b    

修改端口号还是无法启动第二个tomcat的原因

问题:我的服务器是Tomcat7.0.20,修改完所有端口之后(shutdown端口.http端口.https端口.ajp端口),启动一个就不能启动另一个. 两 个startup.bat最前面加上一句set CATALINA_HOME=当前TOMCAT路径就可以了 当第一个tomcat启动后,后面tomcat的server.xml中的端口不管怎么改,仍然会报端口冲突.后来在dos下运行才发现所有的 tomcat都会去找CATALINA_HOME和CATALINA_BASE这两个环境变量,因此步骤

启动第二个Acitivity和intent传递数据

先定义一个Activity package com.example.work; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener;

uboot第二阶段分析

uboot的第二阶段主要是start_armboot函数 gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t)); 在uboot代码和堆空间下面开辟一个全局变量gd的空间,大小就是gd_t的大小 gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));//gd结构体中bd结构体开辟空间,紧挨着gd typedefstructglobal_data { bd_t*bd;//板子的相关信息 unsigne

01.项目管理——启动过程组表格

项目章程 项目名称 项目发起人 准备日期 项目经理 项目客户 项目目的或批准项目的原因 高层级项目描述 高层级需求 高层级风险 项目目标 成功标准 批准人员 范围 时间 成本 其他 总体里程碑 到期日 预算 干系人 角色 项目经理职权层级 人员配备决策 预算管理和偏差 技术决策 冲突解决 批准 项目经理签名 发起人或委托人签字 日期 日期 干系人登记册 项目名称 准备日期 姓名 职位 角色 联系信息 需求 期望 影响力 分类 干系人分析矩阵 项目名称 准备日期 权利 利益 原文地址:https:

rac 11g_第二个节点重启后无法启动实例:磁盘组dismount问题

原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/41480075 rac第二个节点重启后无法启动实例:磁盘组dismount问题 实验案例: 实验环境:CentOS 6.4.Oracle 11.2.0.1 现象重演:1. 重启第二节点服务器2. 手工启动第二节点实例,报错[[email protected] ~]# s

rac_第二个节点重启后无法启动实例:磁盘组dismount问题

原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong/article/details/41480075 rac第二个节点重启后无法启动实例:磁盘组dismount问题 实验案例: 实验环境:CentOS 6.4.Oracle 11.2.0.1 现象重演: 1. 重启第二节点服务器 2. 手工启动第二节点实例,报错 [[email protected] ~]