嵌入式linux开发uboot移植(六)——uboot环境变量
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了嵌入式linux开发uboot移植(六)——uboot环境变量,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9278字,纯文字阅读大概需要14分钟。
内容图文
![嵌入式linux开发uboot移植(六)——uboot环境变量](/upload/InfoBanner/zyjiaocheng/924/3b12ea676492462abb08bfe42b468c2e.jpg)
嵌入式linux开发uboot移植(六)——uboot环境变量
一、uboot环境变量简介
u-boot的缺省情况下会有一些基本的环境变量,当执行saveenv时,环境变量会保存到flash存储设备中。如果环境变量的值为空,则uboot会使用uboot代码中的值;如果环境变量不为空,则优先使用环境变量的值。默认环境变量在uboot源码中common/Env_common.c文件中。
uchar?default_environment[CFG_ENV_SIZE]?=?{
#ifdef?CONFIG_BOOTARGS
"bootargs="CONFIG_BOOTARGS"\0"
#endif
#ifde?fCONFIG_BOOTCOMMAND
"bootcmd="CONFIG_BOOTCOMMAND"\0"
#endif
#ifdef?CONFIG_MTDPARTITION
"mtdpart="CONFIG_MTDPARTITION"\0"
#endif
#ifdef?CONFIG_RAMBOOTCOMMAND
"ramboot="CONFIG_RAMBOOTCOMMAND"\0"
#endif
#ifdef?CONFIG_NFSBOOTCOMMAND
"nfsboot="CONFIG_NFSBOOTCOMMAND"\0"
#endif
#if?defined(CONFIG_BOOTDELAY)?&&?(CONFIG_BOOTDELAY?>=?0)
"bootdelay="MK_STR(CONFIG_BOOTDELAY)"\0"
#endif
#if?defined(CONFIG_BAUDRATE)?&&?(CONFIG_BAUDRATE?>=?0)
"baudrate="MK_STR(CONFIG_BAUDRATE)"\0"
#endif
#ifdef?CONFIG_ETHADDR
"ethaddr="MK_STR(CONFIG_ETHADDR)"\0"
#endif
#ifdef?CONFIG_IPADDR
"ipaddr="MK_STR(CONFIG_IPADDR)"\0"
#endif
#ifdef?CONFIG_SERVERIP
"serverip="MK_STR(CONFIG_SERVERIP)"\0"
#endif
#ifdef?CONFIG_GATEWAYIP
"gatewayip="MK_STR(CONFIG_GATEWAYIP)"\0"
#endif
#ifdef?CONFIG_NETMASK
"netmask="MK_STR(CONFIG_NETMASK)"\0"
#endif
#ifdef?CONFIG_HOSTNAME
"hostname="MK_STR(CONFIG_HOSTNAME)"\0"
#endif
#ifdef??CONFIG_EXTRA_ENV_SETTINGS
CONFIG_EXTRA_ENV_SETTINGS
#endif
"\0"
};
所有的环境变量存储在一个16KB大小的一维数组中,每个环境变量以"\0"结束。uboot在启动时,在遍历调用执行init_sequence函数指针数组中的env_init函数时已经对环境变量进行校验,通过调用env_relocate函数,将环境变量从Flash启动设备重定位到SDRAM中。uboot启动时环境变量的初始化如下:
环境变量的使用示例:
setenv bootcmd "nand read 0x20008000 0x80000 0x500000;bootm 0x30008000"
saveenv
常见的uboot环境变量:
bootdelay 执行自动启动的等候秒数
baudrate 串口控制台的波特率
netmask 以太网接口的掩码
ethaddr 以太网卡的网卡物理地址
bootfile 缺省的下载文件
bootargs 传递给内核的启动参数
bootcmd 自动启动时执行的命令
serverip 服务器端的ip地址
ipaddr 本地ip 地址
stdin 标准输入设备
stdout 标准输出设备
stderr 标准出错设备
二、环境变量操作的源码分析
在对环境变量的操作中,u-boot调用的对环境变量操作的通用函数接口位于common/env_common.c文件,环境变量存储在不同的启动设备时的操作函数接口存放在不同的文件,如common/env_epprom.c、common/env_flash.c、common/env_nand.c,对环境变量的操作函数接口存放在common/env_nvedit.c。
1、printenv
int?do_printenv?(cmd_tbl_t?*cmdtp,?int?flag,?int?argc,?char?*argv[])
{
int?i,?j,?k,?nxt;
int?rcode?=?0;
if?(argc?==?1)?{//printenv命令没有参数时打印出所有变量信息
for?(i=0;?env_get_char(i)?!=?'\0';?i=nxt+1)?{//遍历环境变量数组中的变量
for?(nxt=i;?env_get_char(nxt)?!=?'\0';?++nxt)//遍历变量获取字符数量
;
for?(k=i;?k<nxt;?++k)遍历打印出变量的信息
putc(env_get_char(k));
putc??('\n');//变量信息输出完毕打印换行
if?(ctrlc())?{
puts?("\n?**?Abort\n");
return?1;
}
}
printf("\nEnvironment?size:?%d/%ld?bytes\n",
i,?(ulong)ENV_SIZE);
return?0;
}
for?(i=1;?i<argc;?++i)?{//遍历打印单个或多个变量的信息
char?*name?=?argv[i];
k?=?-1;
for?(j=0;?env_get_char(j)?!=?'\0';?j=nxt+1)?{//遍历打印的多个环境变量
for?(nxt=j;?env_get_char(nxt)?!=?'\0';?++nxt)//遍历计算变量的字符数
;
k?=?envmatch((uchar?*)name,?j);//查找变量是否存在
if?(k?<?0)?{
continue;
}
puts?(name);
putc?('=');
while?(k?<?nxt)//打印变量信息
putc(env_get_char(k++));
putc?('\n');
break;
}
if?(k?<?0)?{
printf?("##?Error:?\"%s\"?not?defined\n",?name);
rcode?++;
}
}
return?rcode;
}
2、setenv
int?do_setenv?(cmd_tbl_t?*cmdtp,?int?flag,?int?argc,?char?*argv[])
{
if?(argc?<?2)?{//setenv命令无参数输入处理情况
printf?("Usage:\n%s\n",?cmdtp->usage);
return?1;
}
return?_do_setenv?(flag,?argc,?argv);
}
3、saveenv
int?do_saveenv?(cmd_tbl_t?*cmdtp,?int?flag,?int?argc,?char?*argv[])
{
extern?char?*?env_name_spec;
printf?("Saving?Environment?to?%s...\n",?env_name_spec);
return?(saveenv()???1?:?0);
}
int?saveenv(void)
{
movi_write_env(virt_to_phys((ulong)env_ptr));//将所列环境变量写入SD卡
puts?("done\n");
return?1;
}
4、字符串解析
uboot中对环境变量的操作充分利用了对环境变量字符串的解析。本部分将字符串的解析提取出来进行分析。
环境变量存储在default_environment[CFG_ENV_SIZE]数组中,每个环境变量以"\0"结束。通过对环境变量数组default_environment[CFG_ENV_SIZE]进行解析,将环境变量分别打印出来。
实验源码:
#include?<stdio.h>
unsigned?char?environment[]?=?
{
????"bootdelay="????"10"????"\0"
????"ipaddr="???"192.168.1.210"?"\0"
????"serverip="?"192.168.1.200"?"\0"
????"bootcmd="??"tftp?0x20008000?uImage;bootm?0x20008000"???"\0"
????"baudrate="?"115200"????"\0"
};
int?main(int?argc,?char?**argv)
{
????int?i,?s,k;
????for(i?=?0;?*(environment+i)?!=?'\0';?i?=?s?+?1)?//按照变量遍历环境变量数组
????{???//
????????for(s?=?i;?*(environment?+?s)?!=?'\0';?s++)//计算出变量的字符数量
????????????;???
????????for(k?=?i;?k?<?s;?k++)//打印出变量的信息
????????????putc(?*(environment?+?k),?stdout);
????????putc('\n',?stdout);
????}???
????return?0;
}
编译运行结果:
bootdelay=10
ipaddr=192.168.1.210
serverip=192.168.1.200
bootcmd=tftp 0x20008000 uImage;bootm 0x20008000
baudrate=115200
三、uboot中的SD/MMC设备驱动
1、uboot中的SD/MMC设备的初始化
uboot在启动的第二阶段BL2的start_armboot函数中在对开发板初始化部分使用mmc_initialize函数对SD/MMC设备进行初始化,初始化分为两部分:
A、cpu_mmc_init
cpu_mmc_init函数完成对SoC内部SD/MMC控制器的初始化,包括使用setup_hsmmc_clock函数初始化SD/MMC控制器的时钟,setup_hsmmc_cfg_gpio函数初始化SoC中SD/MMC控制器的GPIO引脚。
返回时调用了smdk_s3c_hsmmc_init函数,smdk_s3c_hsmmc_init根据SD/MMC通道调用函数s3c_hsmmc_initialize初始化struct mmc结构体实例的属性和操作方法。struct mmc结构体实例的操作方法指定了SD/MMC设备操作硬件设备的方法函数。
B、mmc_init
mmc_init函数完成对SD/MMC硬件设备的初始化。mmc_init函数内部通过调用mmc_go_idle、mmc_send_if_cond、mmc_send_app_op_cond、mmc_send_cmd等函数最终调用struct mmc结构体实例中操作方法send_cmd、set_ios、init挂接的s3c_hsmmc_send_command、s3c_hsmmc_set_ios、s3c_hsmmc_init硬件操作函数,最终完成对SD/MMC硬件设备的初始化。
SD/MMC设备驱动stuct mmc结构体封装了SD/MMC设备的属性和操作方法。
struct?mmc?{
struct?list_head?link;
char?name[32];
void?*priv;
uint?voltages;
uint?version;
uint?f_min;
uint?f_max;
int?high_capacity;
uint?bus_width;
uint?clock;
uint?card_caps;
uint?host_caps;
uint?ocr;
uint?scr[2];
uint?csd[4];
uint?cid[4];
ushort?rca;
uint?tran_speed;
uint?read_bl_len;
uint?write_bl_len;
u32?capacity;
struct?mmc_ext_csdext_csd;/*?mmc?v4?extended?card?specific?*/
block_dev_desc_t?block_dev;
int?(*send_cmd)(struct?mmc?*mmc,
struct?mmc_cmd?*cmd,?struct?mmc_data?*data);
void?(*set_ios)(struct?mmc?*mmc);
int?(*init)(struct?mmc?*mmc);
};
SD/MMC设备驱动构建就是对SD/MMC设备结构体struct mmc类型实例的初始化。
2、uboot中对SD/MMC设备的操作
saveenv命令保存环境变量到Flash设备时需要调用驱动程序操作Flash设备。uboot硬件驱动程序是从linux kernel移植的。saveenv的命令函数为do_saveenv。saveenv命令保存环境变量的工作流程如下:
A、调用common/cmd_nvedit.c中do_saveenv函数
int do_saveenv (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
extern char * env_name_spec;
printf ("Saving Environment to %s...\n", env_name_spec);
return (saveenv() ? 1 : 0);
}
B、调用common/env_auto.c文件中saveenv函数:
int?saveenv(void)
{
#if?defined(CONFIG_S5PC100)?||?defined(CONFIG_S5PC110)?||?defined(CONFIG_S5P6442)
if?(INF_REG3_REG?==?2)
saveenv_nand();//环境变量保存到nand设备
else?if?(INF_REG3_REG?==?3)
saveenv_movinand();//环境变量保存到SD/MMC设备
else?if?(INF_REG3_REG?==?1)
saveenv_onenand();
else?if?(INF_REG3_REG?==?4)
saveenv_nor();
#elifdefined(CONFIG_SMDK6440)
if?(INF_REG3_REG?==?3)
saveenv_nand();
else?if?(INF_REG3_REG?==?4?||?INF_REG3_REG?==?5?||?INF_REG3_REG?==?6)
saveenv_nand_adv();
else?if?(INF_REG3_REG?==?0?||?INF_REG3_REG?==?1?||?INF_REG3_REG?==?7)
saveenv_movinand();
#else???//?others
if?(INF_REG3_REG?==?2?||?INF_REG3_REG?==?3)
saveenv_nand();
else?if?(INF_REG3_REG?==?4?||?INF_REG3_REG?==?5?||?INF_REG3_REG?==?6)
saveenv_nand_adv();
else?if?(INF_REG3_REG?==?0?||?INF_REG3_REG?==?7)
saveenv_movinand();
else?if?(INF_REG3_REG?==?1)
saveenv_onenand();
#endif
else
printf("Unknown?boot?device\n");
return?0;
}
C、调用common/env_auto.c文件中saveenv_movinand函数
int saveenv_movinand(void)
{
#if defined(CONFIG_CMD_MOVINAND)
movi_write_env(virt_to_phys((ulong)env_ptr));
puts("done\n");
return 1;
#else
return 0;
#endif/* CONFIG_CMD_MOVINAND */
}
E、调用cpu/s5pc11x/movi.c文件中的movi_write_env函数
void movi_write_env(ulong addr)
{
movi_write(raw_area_control.p_w_picpath[2].start_blk,
raw_area_control.p_w_picpath[2].used_blk, addr);
}
F、调用drivers/mmc/mmc.c文件中movi_write函数
ulong movi_write(ulong start, lbaint_t blkcnt, void *src)
{
return mmc_bwrite(0, start, blkcnt, src);
}
G、调用drivers/mmc/mmc.c文件中mmc_bwrite函数,最终调用drivers/mmc/s3c_hsmmc.c文件中s3c_hsmmc_send_command函数完成数据保存写入。
3、uboot中的驱动分层
uboot中与SD/MMC设备有关的操作接口函数位于drivers/mmc/mmc.c文件中,这些接口函数最终指向了struct mmc结构体的函数指针成员。与SD/MMC设备硬件有关的操作函数接口位于drivers/mmc/s3c_hsmmc.c文件中,主要是SoC内部的SD/MMC控制器对SD/MMC设备的操作,如SD/MMC设备的命令发送函数s3c_hsmmc_send_command、SD/MMC设备的数据读写函数s3c_hsmmc_set_ios。SD/MMC设备驱动在驱动构建初始化函数s3c_hsmmc_initialize中将struct mmc结构体实例中的函数指针与对相对应的SD/MMC设备操作方法接口进行了挂接。
uboot将对SoC内部与SD/MMC设备有关的初始化操作函数如setup_hsmmc_clock、setup_hsmmc_cfg_gpio放在了与SoC相关的文件目录cpu/s5pc11x/setup_hsmmc.c文件中。
uboot中对于linux设备驱动分层的继承移植极大方便了开发者对uboot的移植。
内容总结
以上是互联网集市为您收集整理的嵌入式linux开发uboot移植(六)——uboot环境变量全部内容,希望文章能够帮你解决嵌入式linux开发uboot移植(六)——uboot环境变量所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。