1 void env_relocate (void)
2 {
3 /*
4 * We must allocate a buffer for the environment
5 */
6 env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
7 if (gd->env_valid == 0) {
8 puts ("*** Warning - bad CRC, using default environment\n\n");
9 show_boot_progress (-60);
10 set_default_env();
11 } else {
12 env_relocate_spec ();
13 }
14 gd->env_addr = (ulong)&(env_ptr->data);
15 }
|
第6行 由于在配置文件中要定义环境变量区域的大小,即#define CFG_ENV_SIZE 0x10000, 这里从
heap堆里分配出这么大的空间来,并用env_ptr指向它
第7行 前面在循环体的 env_init() 中有
gd->env_addr = (ulong)&default_environment[0]; gd->env_valid = 1;第10行 使用默认的环境变量.env_init()中已经看到default_environment[],这是程序初始时的一份
环境变量默认设置,set_default_env()即将default_environment[]数组中的各环境变量项复制到
env_ptr所指向的env_t结构里(确切地说是复制到env_t结构的数据区里)。
第12行 环境变量存在nand中,将其从nand中读出,并填入env_ptr指向的env_t结构里
从nand读出时,配置项中有 CFG_ENV_OFFSET, 即环境变量在nand中存储的起始地址
CFG_ENV_SIZE 环境变量大小
数据读错 或 数据校验出错,都会使用默认的环境变量配置use_default(), 第一次运行uboot时板子会打
印如下信息
*** Warning - bad CRC or NAND, using default environment
就是因为读出的数据经过crc32校验出错(此时读出的数据不是环境变量),进而调用use_default(),在
use_default()中会打印该信息。
第14行 又将gd->env_addr指向env_ptr->data
来看下env_t结构, 在include/environment.h中
typedef struct environment_s { uint32_t crc; /* CRC32 over data bytes */ unsigned char data[ENV_SIZE]; /* Environment data */} env_t;整个env_t结构占CFG_ENV_SIZE大小,所以data区就占CFG_ENV_SIZE - sizeof(crc) 大小,足够
使用了。
小结;env_relocate 所做的事情有3件
1. 从heap中分配一段空间,用于env_t结构
2. 找到环境变量(或从内存中找或从nand中找),填充env_t结构
3. 将gd->env_addr指向env_ptr->data, 这个也就是这里的relocate所在吧。
1 /* IP Address */
2 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
|
将环境变量弄完之后,紧接着就是从环境变量的相应项中获取信息,环境变量是用户与u-boot的一个交互方式,
有了它之后,用户即可通过修改环境变量来修改板子的一些信息配置。这里的ip地址和网卡地址即是其中的一
个典型例子。来看上面的程序:
第2行,获取ip地址,注意gd->bd->bi_ip_addr是ungisned long 类型,而ip地址是类似于
"192.168.1.111"的字符串。往下跟踪:
1 IPaddr_t getenv_IPaddr (char *var)
2 {
3 return (string_to_ip(getenv(var)));
4 }
|
getenv("ipaddr") 即在环境变量中找到ipaddr这一项对应的字符串,假设这里为"192.168.1.111"
将
"192.168.1.111"传入string_to_ip。
IPaddr_t 类型是unsigned long 的一个typedef
5 IPaddr_t string_to_ip(char *s)
6 {
7 IPaddr_t addr;
8 char *e;
9 int i;
10 if (s == NULL)
11 return(0);
12 for (addr=0, i=0; i<4; ++i) {
13 ulong val = s ? simple_strtoul(s, &e, 10) : 0;
14 addr <<= 8;
15 addr |= (val & 0xFF);
16 if (s) {
17 s = (*e) ? e+1 : e;
18 }
19 }
20 return (htonl(addr));
21 }
|
12~19行 192.168.1.111 分为四个段,也就是要做4次 simple_strtoul()转换成10进制的整型
第次转换后的值赋给val。addr是unsigned long型,32位的,将其分为4段,每8位存储ip地址中的一个
段,比如这里,
最后
addr = (((((192 << 8) | 168) << 8) | 1) << 8 ) | 111 = 0xc0a8016f第20行,主机字节顺序转换为网络字节顺序返回
若CPU为小端模式时,addr如下存储
31 24 23 16 15 8 7 0+--------------+---------------+----------------+-----------------+| 192 = 0xc0 | 168 = 0xa8 | 1 = 0x01 | 111 = 0x6f |+--------------+---------------+----------------+-----------------+ 3 2 1 0若CPU为大端模式时,addr如下存储
31 24 23 16 15 8 7 0+--------------+---------------+----------------+-----------------+| 111 = 0x6f | 1 = 0x01 | 168 = 0xa8 | 192 = 0xc0 |+--------------+---------------+----------------+-----------------+ 3 2 1 0当与另一台计算机通信时,通常不知道对方存储数据时是先存放最高位字节 (MSB)还是最低位字节 (LSB)恰恰网络字节顺序跟大端模式时相同,htonl函数就是将主机字节顺序转为网络字节顺序,在最高位字节(MSB)-最前 的系统上,这些函数什么都不做。在 最低位字节(LSB)-最前的系统上它们将值转换为正确的顺序。最后将值返回给了gd->bd->bi_ip_addr, 所以其值应该是
0x6f01800a 3 /* MAC Address */
4 {
5 int i;
6 ulong reg;
7 char *s, *e;
8 char tmp[64];
9 i = getenv_r ("ethaddr", tmp, sizeof (tmp));
10 s = (i > 0) ? tmp : NULL;
11 for (reg = 0; reg < 6; ++reg) {
12 gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
13 if (s)
14 s = (*e) ? e + 1 : e;
15 }
16 }
|
网卡地址以十六进制的形式存于gd->bd->bi_enetaddr[]数组中
阅读(2821) | 评论(0) | 转发(1) |