• Linux系统——访问U-BOOT环境变量


    Linux系统下访问U-BOOT环境变量

    移植过U-BOOT的人,都知道:在U-BOOT中存有ENV。但U-BOOT在引导内核启动之后,U-BOOT的生命周期就结束了。那么启动LINUX内核之后,U-Boot的环境变量还在么?
    按照u-boot对Flash的规划:ENV存放在Flash的0x60000~0x80000。

    那么我们如何在Linux下查看U-boot的环境变量呢?
    其实U-BOOT源码内已经提供了这么一种方式:在tools/env/目录下,有相应的源码,通过在u-boot根目录下执行:make env就可生成fw_printenv应用程序,并将该应用程序拷贝到根文件系统中,就可以查看到U-BOOT的相应的环境变量了。

    具体实现方法,及操作步骤见下面:(转)
    1、编译fw_printenv工具
    在你使用的uboot代码中用以下编译指令:
    make env
    这样就可以编译tools/env下的代码,编译出的fw_printenv工具有读写uboot环境变量区的能力。这个工具是针对目标机的,也就是说如果你的uboot代码之前是针对ARM编译的话,fw_printenv也是交叉编译给ARM芯片的。如果编译不成功,则按照如下操作执行:
    make distclean
    make mini2440_config
    make env

    2、安装fw_printenv工具
    到/tools/env目录中,将编译好的fw_printenv拷贝到目标机的文件系统中,并通过"ln -s fw_printenv fw_setenv",创建一个fw_setenv到fw_printenv的软链。
    这个工具还需要一个配置文件,以获取uboot的ENV区域的位置信息。默认状态下,请将fw_env.config文件拷贝到目标机的文件系统的/etc目录下。然后结合uboot配置中定义的ENV区和Linux下mtd分区的情况修改配置文件。具体的修改方法见fw_env.config文件中的说明及/tools/env/README文件。

    3、fw_printenv工具的使用
    其实fw_printenv使用起来和uboot下的printenv和setenv指令是一模一样的。
    • 打印uboot环境变量:
    1. fw_printenv [[ -n name ] | [ name ... ]]
    2. # ./fw_printenv -n baudrate
    3. 115200
    4. # ./fw_printenv baudrate
    5. baudrate=115200
    如果不指定name,fw_printenv会打印出ENV区中的所有环境变量
    • 设置uboot环境变量:
    1. fw_setenv name [ value ... ]
    2. 如果不指定value,表示要删除这个name的环境变量。
    3. # ./fw_setenv temp tekkaman
    4. # ./fw_printenv -n temp
    5. tekkaman
    6. # ./fw_setenv temp
    7. # ./fw_printenv -n temp
    8. ## Error: "temp" not defined



    linux程序读写uboot env变量:

    分析发现uboot env的存储格式是,开始4个字节是crc32,后面是一个接一个结束的字符串,每个串都是envname=enavalue的格式。
    挪用uboot部分的相关代码,实现以下函数:
    int set_env_ptr(unsigned char * ptr);
    char *get_env (char *name);
    int set_env (char *varname, char *varvalue);
    int printenv(void);

    使用时,我们读取env分区的数据到内存;
    调用set_env_ptr(数据指针),该函数会进行crc校正确保env分区正确,并且返回0;
    get_env, set_env, printenv相应uboot 中的echo $envname; setenv envname envstr; printenv
    Usage: ./uboot_env read|set [envname] [value] -i envimage -o outimage

    linux 程序读写Env分区 --- mtdparts,/dev/mtd*,mtd_debug

    1. uboot $mtdparts 和 linux /dev/mtd* 的联系
    比如:
    uboot:# setenv mtdparts 'mtdparts=nx_2016:1408k@0k(boot),128k@1408k(env),-(extra);nx_2017:16m(k0),16m(k1),-(nandextra)'

    linux:# cat /proc/mtd
    dev: size erasesize name
    mtd0: 00160000 00010000 "boot"
    mtd1: 00020000 00010000 "env"
    mtd2: 00280000 00010000 "extra"
    mtd3: 00400000 00010000 "nx_2016"
    mtd4: 04000000 00004000 "nx_2017"
    mtd5: 01000000 00004000 "k0"
    mtd6: 01000000 00004000 "k1"
    mtd7: 02000000 00004000 "nandextra"

    2. mtd_debug usage
    参考
    http://blog.csdn.net/yinkaizhong/archive/2008/12/25/3604794.aspx

    比如,进一步看env分区的信息:
    linux:# mtd_debug info /dev/mtd1
    mtd.type = MTD_NORFLASH
    mtd.flags = MTD_CAP_NORFLASH
    mtd.size = 131072 (128K)
    mtd.erasesize = 65536 (64K)
    mtd.writesize = 1
    mtd.oobsize = 0
    regions = 0

    3. 分区的操作
    比如对env分区进行擦除:
    # mtd_debug erase /dev/mtd1 0 0x20000


    linux 下更新uboot环境变量:

    参考网址:
    http://www.denx.de/wiki/DULG/HowCanIAccessUBootEnvironmentVariablesInLinux

    http://blog.csdn.net/hangbing0203/article/details/4314576
    http://labs.igep.es/index.php/How_to_modify_the_uboot_environment_from_userspace

    代码分析:
    README:
    This is a demo implementation of a Linux command line tool to access
    the U-Boot's environment variables.
    For the run-time utiltity configuration uncomment the line
    #define CONFIG_FILE "/etc/fw_env.config"
    in fw_env.h.

    这个有误,应该是用配置文件时,不要注释掉这个宏
    See comments in the fw_env.config file for definitions for the
    particular board.
    Configuration can also be done via #defines in the fw_env.h file. The
    following lines are relevant:
    #define HAVE_REDUND /* For systems with 2 env sectors */
    #define DEVICE1_NAME "/dev/mtd1"
    #define DEVICE2_NAME "/dev/mtd2"
    #define DEVICE1_OFFSET 0x0000
    #define ENV1_SIZE 0x4000
    #define DEVICE1_ESIZE 0x4000
    #define DEVICE2_OFFSET 0x0000
    #define ENV2_SIZE 0x4000
    #define DEVICE2_ESIZE 0x4000
    Current configuration matches the environment layout of the TRAB
    board.

    HAVE_REDUND是用来环境变量备份用的
    Un-define HAVE_REDUND, if you want to use the utlities on a system
    that does not have support for redundant environment enabled.
    If HAVE_REDUND is undefined, DEVICE2_NAME is ignored,
    as is ENV2_SIZE and DEVICE2_ESIZE.
    The DEVICEx_NAME constants define which MTD character devices are to
    be used to access the environment.
    The DEVICEx_OFFSET constants define the environment offset within the
    MTD character device.
    ENVx_SIZE defines the size in bytes taken by the environment, which
    may be less then flash sector size, if the environment takes less
    then 1 sector.
    DEVICEx_ESIZE defines the size of the first sector in the flash
    partition where the environment resides.

    DEVICEx_NAME设备名
    DEVICEx_OFFSET设备中环境变量的偏移
    ENVx_SIZE 环境变量大小,可能比1sector小




    查看环境变量大小:
    pri查看
    Environment size: 1560/4092 bytes
    include/configs/mv_kv.h
    #define CFG_ENV_SIZE 0x1000
    所以大小是0x1000




    查看环境变量偏移:
    #define CFG_MONITOR_LEN (512 << 10) /* Reserve 512 kB for Monitor */ uboot镜像长度 0x80000 =512k
    //uboot的基址和环境变量的基址
    #define CFG_MONITOR_BASE (CFG_FLASH_BASE)
    #define CFG_ENV_ADDR (CFG_MONITOR_BASE + CFG_MONITOR_LEN) 环境变量开始位置
    #define CFG_ENV_SIZE 0x1000 //4k
    环境变量从0x80000开始 到0x80000+0x1000
    根据CFG_ENV_ADDR 知道环境变量偏移是0x80000




    查看erasesize
    /opt/qtmarvell/mvqt/tools # cat /proc/mtd
    dev: size erasesize name
    mtd0: 00100000 00010000 "uboot"
    mtd1: 00700000 00010000 "linux-root"

    编译fw_printenv:
    下载http://ftp.denx.de/pub/u-boot/u-boot-2011.03.tar.bz2
    根目录下:
    make env HOSTCC=arm-mv5sft-linux-gnueabi-gcc
    ln -s fw_printenv fw_setenv

    修改fw_env.config ,根据上面的信息:
    /opt/qtmarvell/mvqt/tools # cat fw_env.config
    # Configuration file for fw_(printenv/saveenv) utility.
    # Up to two entries are valid, in this case the redundant
    # environment sector is assumed present.
    # Notice, that the "Number of sectors" is ignored on NOR.
    # MTD device name Device offset Env. size Flash sector size Number of sectors
    /dev/mtd0 0x80000 0x1000 0x10000


    U-Boot添加命令的方法及U-Boot命令执行过程(转)

    下面以添加menu命令(启动菜单)为例讲解U-Boot添加命令的方法。
    (1) 建立common/cmd_menu.c
    习惯上通用命令源代码放在common目录下,与开发板专有命令源代码则放在board/<board_dir>目录下,并且习惯以“cmd_<命令名>.c”为文件名。
    (2) 定义“menu”命令
    在cmd_menu.c中使用如下的代码定义“menu”命令:
    _BOOT_CMD(
    menu, 3, 0, do_menu,
    "menu - display a menu, to select the items to do something ",
    " - display a menu, to select the items to do something"
    );
    其中U_BOOT_CMD命令格式如下:
    U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)
    各个参数的意义如下:
    name:命令名,非字符串,但在U_BOOT_CMD中用“#”符号转化为字符串
    maxargs:命令的最大参数个数
    rep:是否自动重复(按Enter键是否会重复执行)
    cmd:该命令对应的响应函数
    usage:简短的使用说明(字符串)
    help:较详细的使用说明(字符串)
    在内存中保存命令的help字段会占用一定的内存,通过配置U-Boot可以选择是否保存help字段。若在include/configs/mini2440.h中定义了CONFIG_SYS_LONGHELP宏,则在U-Boot中使用help命令查看某个命令的帮助信息时将显示usage和help字段的内容,否则就只显示usage字段的内容。
    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}
    “##”与“#”都是预编译操作符,“##”有字符串连接的功能,“#”表示后面紧接着的是一个字符串。
    其中的cmd_tbl_t在include/command.h中定义如下:
    struct cmd_tbl_s {
    char *name; /* 命令名 */
    int maxargs; /* 最大参数个数 */
    int repeatable; /* 是否自动重复 */
    int (*cmd)(struct cmd_tbl_s *, int, int, char *[]); /* 响应函数 */
    char *usage; /* 简短的帮助信息 */
    #ifdef CONFIG_SYS_LONGHELP
    char *help; /* 较详细的帮助信息 */
    #endif
    #ifdef CONFIG_AUTO_COMPLETE
    /* 自动补全参数 */
    int (*complete)(int argc, char *argv[], char last_char, int maxv, char *cmdv[]);
    #endif
    };
    typedef struct cmd_tbl_s cmd_tbl_t;
    一个cmd_tbl_t结构体变量包含了调用一条命令的所需要的信息。
    其中Struct_Section在include/command.h中定义如下:
    #define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
    凡是带有__attribute__ ((unused,section (".u_boot_cmd"))属性声明的变量都将被存放在".u_boot_cmd"段中,并且即使该变量没有在代码中显式的使用编译器也不产生警告信息。
    在U-Boot连接脚本u-boot.lds中定义了".u_boot_cmd"段:
    . = .;
    __u_boot_cmd_start = .; /*将 __u_boot_cmd_start指定为当前地址 */
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .; /* 将__u_boot_cmd_end指定为当前地址 */
    这表明带有“.u_boot_cmd”声明的函数或变量将存储在“u_boot_cmd”段。这样只要将U-Boot所有命令对应的cmd_tbl_t变量加上“.u_boot_cmd”声明,编译器就会自动将其放在“u_boot_cmd”段,查找cmd_tbl_t变量时只要在__u_boot_cmd_start与__u_boot_cmd_end之间查找就可以了。
    因此“menu”命令的定义经过宏展开后如下:
    cmd_tbl_t __u_boot_cmd_menu __attribute__ ((unused,section (".u_boot_cmd"))) = {menu, 3, 0, do_menu, "menu - display a menu, to select the items to do something ", " - display a menu, to select the items to do something"}
    实质上就是用U_BOOT_CMD宏定义的信息构造了一个cmd_tbl_t类型的结构体。编译器将该结构体放在“u_boot_cmd”段,执行命令时就可以在“u_boot_cmd”段查找到对应的cmd_tbl_t类型结构体。
    (3) 实现命令的函数
    在cmd_menu.c中添加“menu”命令的响应函数的实现。具体的实现代码略:
    int do_menu (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
    /* 实现代码略 */
    }
    (4) 将common/cmd_menu.c编译进u-boot.bin
    在common/Makefile中加入如下代码:
    COBJS-$(CONFIG_BOOT_MENU) += cmd_menu.o
    在include/configs/mini2440.h加入如代码:
    #define CONFIG_BOOT_MENU 1
    重新编译下载U-Boot就可以使用menu命令了
    (5)menu命令执行的过程
    在U-Boot中输入“menu”命令执行时,U-Boot接收输入的字符串“menu”,传递给run_command函数。run_command函数调用common/command.c中实现的find_cmd函数在__u_boot_cmd_start与__u_boot_cmd_end间查找命令,并返回menu命令的cmd_tbl_t结构。然后run_command函数使用返回的cmd_tbl_t结构中的函数指针调用menu命令的响应函数do_menu,从而完成了命令的执行。

  • 相关阅读:
    bzoj 3744: Gty的妹子序列 主席树+分块
    bzoj 3110: [Zjoi2013]K大数查询 树状数组套线段树
    bzoj 3041: 水叮当的舞步 迭代加深搜索 && NOIP RP++
    约瑟夫问题例题小结
    bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化
    人生第一场CTF的解题报告(部分)
    ZOJ 3811 Untrusted Patrol【并查集】
    POJ 2112: Optimal Milking【二分,网络流】
    Codeforces Round #277 (Div. 2 Only)
    POJ 2195 Going Home【最小费用流 二分图最优匹配】
  • 原文地址:https://www.cnblogs.com/sun-frederick/p/4763333.html
Copyright © 2020-2023  润新知