liang's profile阿斯提亚神殿——梦幻天子's skyPhotosBlogLists Tools Help
    June 13

    UBOOT添加命令(转载)

    这个应该对我有帮助,使我能够更好的了解uboot命令的执行流程。

    具体内容如下:

    U-Boot的命令为用户提供了交互功能,并且已经实现了几十个常用的命令。如果开发板需要很特殊的操作,可以添加新的U-Boot命令。
    U-Boot的每一个命令都是通过U_Boot_CMD宏定义的。这个宏在include/command.h头文件中定义,每一个命令定义一个cmd_tbl_t结构体。
     
    #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
    cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
     
    这样每一个U-Boot命令有一个结构体来描述。结构体包含的成员变量:命令名称、最大参数个数、重复数、命令执行函数、用法、帮助。
    从控制台输入的命令是由common/command.c中的程序解释执行的。(这就是我要找的)find_cmd()负责匹配输入的命令,从列表中找出对应的命令结构体。
    基于U-Boot命令的基本框架,来分析一下简单的icache操作命令,就可以知道添加新命令的方法。
    (1)定义CACHE命令。在include/cmd_confdefs.h中定义了所有U-Boot命令的标志位。
     
    #define CFG_CMD_CACHE       0x00000010ULL   /* icache, dcache       */
     
    如果有更多的命令,也要在这里添加定义。
    (2)实现CACHE命令的操作函数。下面是common/cmd_cache.c文件中icache命令部分的代码。
     
    #if (CONFIG_COMMANDS & CFG_CMD_CACHE)
    static int on_off (const char *s)
    {       //这个函数解析参数,判断是打开cache,还是关闭cache
            if (strcmp(s, "on") == 0) {  //参数为“on”
                   return (1);
            } else if (strcmp(s, "off") == 0) {  //参数为“off”
                   return (0);
        }
        return (-1);
    }
     
    int do_icache ( cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {     //对指令cache的操作函数
          switch (argc) {
          case 2:               /* 参数个数为1,则执行打开或者关闭指令cache操作 */
                 switch (on_off(argv[1])) {
                 case 0:     icache_disable();        //打开指令cache
                       break;
                 case 1:     icache_enable ();        //关闭指令cache
                       break;
                 }
                /* FALL TROUGH */
          case 1:           /* 参数个数为0,则获取指令cache状态*/ 
                printf ("Instruction Cache is %s\n",
                        icache_status() ? "ON" : "OFF");
                return 0;
          default:  //其他缺省情况下,打印命令使用说明
                printf ("Usage:\n%s\n", cmdtp->usage);
                return 1;
          }
          return 0;
    }
    ……
    U_Boot_CMD( //通过宏定义命令
        icache,   2,   1,     do_icache,  //命令为icache,命令执行函数为do_icache()
        "icache  - enable or disable instruction cache\n",   //帮助信息
        "[on, off]\n"
        "    - enable or disable instruction cache\n"
    );
    ……
    #endif
     
    U-Boot的命令都是通过结构体__U_Boot_cmd_##name来描述的。根据U_Boot_CMD在include/command.h中的两行定义可以明白。
     
    #define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
    cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}
     
    还有,不要忘了在common/Makefile中添加编译的目标文件。
    (3)打开CONFIG_COMMANDS选项的命令标志位。这个程序文件开头有#if语句需要预处理是否包含这个命令函数。CONFIG_COMMANDS选项在开发板的配置文件中定义。例如:SMDK2410平台在include/configs/smdk2410.h中有如下定义。
     
    /***********************************************************
     * Command definition
     ***********************************************************/
    #define CONFIG_COMMANDS \
                     (CONFIG_CMD_DFL  | \
                     CFG_CMD_CACHE     | \
                     CFG_CMD_REGINFO    | \
                     CFG_CMD_DATE      | \
                     CFG_CMD_ELF)
     
    按照这3步,就可以添加新的U-Boot命令。

    一篇uboot的移植文档(转载)

    1     uboot的介绍及体系结构... 2
    1.1 uboot的介绍... 2
    1.2 uboot的体系结构... 2
    2     uboot的运行过程分析... 3
    2.1 启动模式介绍... 3
    2.2 运行过程... 3
    2.3      本开发板的地址分布(leopard2a)... 5
    2.4      运行代码分析... 5
    2.4.1 stage 1. 5
    2.4.2 stage 2. 5
    2.4.2.1 调用一系列初始化函数... 5
    2.4.2.2 初始化网络设备... 7
    2.4.2.3 进入主UBOOT 命令行... 7
    3     uboot的移植和测试... 7
    3.1 移植的过程... 7
    3.2 移植主要修改的文件... 8
    3.3 uboot网络下载功能的添加和RAM调试... 8
     
     
    1          uboot的介绍及体系结构
     
    1.1 uboot的介绍
     
    Uboot是德国DENX小组的开发用于多种嵌入式CPU的bootloader程序, UBoot不仅仅支持嵌入式Linux系统的引导,当前,它还支持NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS嵌入式操作系统。UBoot除了支持PowerPC系列的处理器外,还能支持MIPS、 x86、ARM、NIOS、XScale等诸多常用系列的处理器。
     
    1.2 uboot的体系结构
     
    目录树
     
    |--board
    |--common
    |--cpu
    |--disk
    |--doc
    |--drivers
    |--dtt
    |--examples
    |--fs
    |--include
    |--lib_arm
    |--lib_generic
    |--net
    |--post
    |--rtc
    |--tools
     
     
     
    2. board:和一些已有开发板有关的文件. 每一个开发板都以一个子目录出现在当前目录中,比如说: leopard2a子目录中存放与我们开发板相关的配置文件.
    3. common:实现uboot命令行下支持的命令,每一条命令都对应一个文件。例如bootm命令对应就是cmd_bootm.c。
    4. cpu:与特定CPU架构相关目录,每一款Uboot下支持的CPU在该目录下对应一个子目录,比如有子目录arm926ejs就是我们开发板上使用的cpu架构目录。
    5. disk:对磁盘的支持。
    5. doc:文档目录。Uboot有非常完善的文档,推荐大家参考阅读。
    6. drivers:Uboot支持的设备驱动程序都放在该目录,比如各种网卡、支持CFI的Flash、串口和USB等。
    7. fs: 支持的文件系统,Uboot现在支持cramfs、fat、fdos、jffs2和registerfs。
    8. include:Uboot使用的头文件,还有对各种硬件平台支持的汇编文件,系统的配置文件和对文件系统支持的文件。该目录下configs目录有与开发板相关的配置头文件,如leopard2a.h。该目录下的asm目录有与CPU体系结构相关的头文件,asm对应的是asmarm.
    9. lib_xxxx: 与体系结构相关的库文件。如与ARM相关的库放在lib_arm中。
    10. net:与网络协议栈相关的代码,BOOTP协议、TFTP协议、RARP协议和NFS文件系统的实现。
    11. tools:生成Uboot
    的工具,如:mkimage, crc等等。
    2          uboot的运行过程分析
    2.1 启动模式介绍
    大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
    启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 BootLoader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。
    下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 BootLoader 保存到目标机的 RAM 中,然后再被 BootLoader 写到目标机上的FLASH 类固态存储设备中。BootLoader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 BootLoader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。
    UBoot这样功能强大的 Boot Loader 同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。
     
    2.2 运行过程
           大多数bootloader都分为阶段1(stage1)和阶段2(stage2)两大部分,uboot也不例外。依赖于CPU体系结构的代码(如CPU初始化代码等)通常都放在阶段1中且通常用汇编语言实现,而阶段2则通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
     
    U - Boot 编译后的代码定义一般不超过100kB ,并且这100 kB 又分成两个阶段来执行. 第一阶段的代码在start . s 中定义,大小不超过10 kB ,它包括从系统上电后在0x00000000 地址开始执行的部分. 这部分代码运行在Flash 中,它包括对arm926ejs的一些寄存器的初始化和将U - Boot 的第二阶段代码从Flash 拷贝到SDRAM 中. 除去第一阶段的代码,剩下的部分都是第二阶段的代码. 第二阶段的起始地址是在第一阶段代码中指定的,被复制到SDRAM后,就从第一阶段跳到这个入口地址开始执行剩余部分代码. 第二阶段主要是进行一些BSS 段设置,堆栈的初始化等工作,最后会跳转到main -loop 函数中,接受命令并进行命令处理. 图1 给出了U - Boot 的详细的运行过程包括对内核的设置、装载及调用过程.
     
     
     
    系统复位进入u-boot stage l的入口点
     
    硬件设备的初始化
     
    为加载uboot stage 2准备ram空间
     
    设置好堆栈
     
    跳转到stage 2的C入口点
     
    初始化本阶段要用到的设备
     
    检查内存映射
     
    将kernel映像和文件映像从flash中读到ram中
     
    为内核设定启动参数
     
    调用内核
     

     
                                    图1
     
     
     
     
     
     
     
     
     
     
     
     
    2.3     本开发板的地址分布(leopard2a)
     
    本目标板是RAM 16M, Flash 8M,具体空间如图所示:
     
    1F12FFFF
     
    Uboot
     
     
    Uboot_env
     
     
    Kernel
     
     
    Rootfs
     
     
    1F000000
     
    1F020000
     
    1F01FFFF
     
    1F02FFFF
     
    1F030000
     
    1F130000
     
    1F7EFFFF
     
     
     
     
    Kernel
     
     
     
    Rootfs
     
     
    FLASH
     
    SDRAM
     
    0x00030000
     
    0x00130000
     
    0x00430000
     

     
     
    可以根据变换后的分区结构,设置
    uboot_addr,uboot_addr_end,kernel_addr,kernel_addr_end,rootfs_addr,rootfs_addr_end,
    config_addr, config_addr_end等环境变量,调整bootloader。
     
    SDRAM的调整修改linux-2.4.20_mvl31/drivers/mtd/maps/physmap.c
     
    2.4     运行代码分析
    2.4.1 stage 1
     
    uboot的stage1代码通常放在start.s文件中,它用汇编语言写成,其主要代码包括定义入口,设置异常向量,设置cpu的模式和频率,配置内存区控制寄存器,安装uboot的栈空间,关闭看门狗等。由于本人对ram的汇编不太熟悉,所以这一部分不作具体分析。
     
    2.4.2 stage 2
    lib_arm/board.c中的start armboot是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个uboot(armboot)的主函数,该函数主要完成如下操作:
     
    2.4.2.1 调用一系列初始化函数
     
    1. 指定初始函数表:
    init_fnc_t *init_sequence[] = {
    cpu_init, /* cpu的基本设置 */
    board_init, /* 开发板的基本初始化 */
    interrupt_init, /* 初始化中断 */
    env_init, /* 初始化环境变量 */
    init_baudrate, /* 初始化波特率 */
    serial_init, /* 串口通讯初始化 */
    console_init_f, /* 控制台初始化第一阶段 */
    display_banner, /* 通知代码已经运行到该处 */
    dram_init, /* 配制可用的内存区 */
    display_dram_config,
    #if defined(CONFIG_VCMA9) || defined (CONFIG_CMC_PU2)
    checkboard,
    #endif
    NULL,
    };
    执行初始化函数的代码如下:
        for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
            if ((*init_fnc_ptr)() != 0) {
                hang ();
            }
        }
    2. 配置可用的Flash区
    flash_init ()
    3. 初始化内存分配函数
    mem_malloc_init()
    4. nand flash初始化
    #if (CONFIG_COMMANDS & CFG_CMD_NAND)
        puts ("NAND:");
        nand_init();        /* go init the NAND */
    #endif
    5. 初始化环境变量
    env_relocate ();
    6. 外围设备初始化
    devices_init()
    7. I2C总线初始化
    i2c_init();
    8. LCD初始化
    drv_lcd_init();
    9. VIDEO初始化
    drv_video_init();
    10. 键盘初始化
    drv_keyboard_init();
    11. 系统初始化
    drv_system_init();
     
    2.4.2.2 初始化网络设备
    初始化相关网络设备,填写IP、MAC地址等。
    1. 设置IP地址
        gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
     
    2. 设置mac地址  
    {
            int i;
            ulong reg;
            char *s, *e;
            uchar tmp[64];
     
            i = getenv_r ((uchar*)("ethaddr"), tmp, sizeof (tmp));
            s = (i > 0) ? (char*)tmp : NULL;
     
            for (reg = 0; reg < 6; ++reg) {
                gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
                if (s)
                    s = (*e) ? e + 1 : e;
            }
        }
    2.4.2.3 进入主UBOOT 命令行
    进入命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行相应的工作。
    for (;;) {
            main_loop ();
        }}
    3         uboot的移植和测试
    3.1 移植的过程
    ① 在宿主机上建立交叉编译开发环境
     
    ② 修改cpu/arm926ejst目录中的文件内容,
    主要包含cpu.C,start.S,interrupts.C以及seria1.C,speed.C等文件
     
    ③ 在board目录下创建自己的目标板(开发板)目录leopard2a
    在目录下创建leopard2a.C,flash.C,memsetup.S
    以及Makefile,u-bot.1ds,config.mk文件
     
    ④在include/configs目录下创建leopard2a.h
     
    ⑤ 打开u-bot目录下Makefile文件,加入如下两行:
    leopard2a_config :      unconfig
    @./mkconfig $(@:_config=) arm arm926ejs leopard2a
     
    ⑨ 编译。运行命令:
    1. make leopard2a_config
    2. make
    编译成功.生成基本的u—b00t.
     
    ⑦ 烧写.把编译成的u-bot.bin
    至此移植u-bot过程结束.
     
    3.2 移植主要修改的文件
    移植u—boot到开发板上只需要修改和硬件相关的代码即可。这首先就联想到cpu目录下的启动代码,另外参考u—boot/readme文件可知其他还需要修改的主要文件有:
    Makefile文件,和include目录下的目标板.h头文件(leopard2a.h),board目录下的目标板.C文件(leopard2a.c),flash.C文件,u-boot.1ds链接文件,以及cpu目录下的串口驱动文件。
     
    具体修改如下:
    ①      cpu/arm926ejst目录下
     
    ◆ start.S启动代码。
     
    ②    board/leopard2a
      ◆  leopard2a.C文件。这个文件主要是SDRAM 的驱动程
    序,主要完成SDRAM 的UPM 表设置,上电初始化。暂时不
    改。
    ◆  flash.C文件。Flash的驱动程序就在此文件中。
     
    ◆      memsetup.S文件。
    ◆  config.mk文件.此文件用于设置程序链接的起始地
    址.
    ◆u-boot.Ids文件。
     
    ③ include/configs目录下leopard2a.h文件.此文件是
    leopard2a目标板头文件,大多数寄存器参数是在这一文件中
    设置完成的.
     
    3.3 uboot网络下载功能的添加和RAM调试
    在commom/main.c 中的main_loop函数中添加tftp下载的函数,可以通过按钮触发下载rimage,kimage。
     
    在烧录u-boot.bin之前,需要进行ram调试,保证uboot可以在EVB上正常运行。
    先下載U-boot 到SDRAM上, 然後執行SDRAM 上的U-boot 程序, 以確認U-boot可以正常執行,
    Command 如下:
    1.       “tftp a00000 u-boot.bin” <= 下載程序到SDRAM
    2.       “go a00000” <= 從SDRAM 執行程序
     
     
    如果U-boot 可以相容於目前的硬件, 5VT EVB 會重新正常啟動
    要是不能正常啟動,表示U-boot 不相容於目前的硬件, 請更換新的u-boot.
    再重新測試, 直到被測試的U-boot可以正常啟動