2009年10月12日 星期一

The enviroment varible initialization process of uboot

start_armboot()(lib_arm/board.c)呼叫env_init() (common/env_auto.c)與env_relocate ()(common/env_common.c)去initialize 指標"env_ptr",該指標所指的記憶體內容為runtime environment varibles。
&env_ptr是0xc7e4d8d0。而*(&env_ptr)就是指標"env_ptr"。

cat u-boot.map | grep env_ptr
0xc7e4d8d0 env_ptr

在uboot shell環境下memory dump runtime environment varibles:

SMDKC100 # md c7e4d8d0 4
c7e4d8d0: c7e7c8d0 00000000 00000000 00000000 ................
SMDKC100 #

SMDKC100 # md c7e7c8d0 44
c7e7c8d0: bb2e403a 7064746d 3d747261 30303034 :@..mtdpart=4000
c7e7c8e0: 63332030 30303030 30303320 30303030 0 3c0000 3000000
c7e7c8f0: 75616200 74617264 31313d65 30303235 .baudrate=115200
c7e7c900: 68746500 72646461 3a30303d 353a3034 .ethaddr=00:40:5
c7e7c910: 36323a63 3a61303a 69006235 64646170 c:26:0a:5b.ipadd
c7e7c920: 39313d72 36312e32 2e302e38 00313831 r=192.168.0.181.
c7e7c930: 76726573 70697265 3239313d 3836312e serverip=192.168
c7e7c940: 312e302e 67003038 77657461 70697961 .0.180.gatewayip
c7e7c950: 3239313d 3836312e 312e302e 74656e00 =192.168.0.1.net
c7e7c960: 6b73616d 3535323d 3535322e 3535322e mask=255.255.255
c7e7c970: 6200302e 63746f6f 6e3d646d 20646e61 .0.bootcmd=nand
c7e7c980: 61647075 6f626574 6f6c746f 72656461 updatebootloader
c7e7c990: 6d6f7266 30303620 34203030 30303030 from 60000 40000
c7e7c9a0: 6e616e3b 65722064 32206461 38303030 ;nand read 20008
c7e7c9b0: 20303030 30303061 33202030 30303030 000 a0000 30000
c7e7c9c0: 616e3b30 7220646e 20646165 30383032 0;nand read 2080
c7e7c9d0: 30303030 30613320 20303030 30303037 0000 3a0000 7000
SMDKC100 #


env_init() (common/env_auto.c)
int env_init(void){
....
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
...
return 0;
}

env_relocate ()(common/env_common.c)
void env_relocate (void){
.....
env_ptr = (env_t *)malloc (CFG_ENV_SIZE);
.....
if (gd->env_valid == 0) {
.....
}else{
env_relocate_spec ();
}
gd->env_addr = (ulong)&(env_ptr->data);
}

env_relocate_spec ()(common/env_auto.c)
void env_relocate_spec(void)
{
#if !defined(CONFIG_SMDK6440)
if (INF_REG3_REG >= 2 && INF_REG3_REG <= 6) env_relocate_spec_nand(); else if (INF_REG3_REG == 0 || INF_REG3_REG == 7) env_relocate_spec_movinand(); else if (INF_REG3_REG == 1) env_relocate_spec_onenand(); else printf("Unknown boot device\n"); #else ....... #endif } env_relocate_spec_nand()(common/env_auto.c) void env_relocate_spec_nand(void) { #if !defined(ENV_IS_EMBEDDED) size_t total; int ret; total = CFG_ENV_SIZE; ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr); if (ret || total != CFG_ENV_SIZE) return use_default(); if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();

#endif /* ! ENV_IS_EMBEDDED */
}

use_default()(common/env_auto.c)
static void use_default()
{
puts("*** Warning - using default environment\n\n");

if (default_environment_size > CFG_ENV_SIZE) {
puts("*** Error - default environment is too large\n\n");
return;
}

memset (env_ptr, 0, sizeof(env_t));
memcpy (env_ptr->data,
default_environment,
default_environment_size);
env_ptr->crc = crc32(0, env_ptr->data, ENV_SIZE);
gd->env_valid = 1;

}


runtime environment varibles有二種來源: (1)default environment varibles 和(2) environment saved in the SD, NAND, and OneNAND



(1)default environment varibles

-定義在common/env_common.c中的default_environment []儲存該environment varibles。
-&default_environment(&default_environment[0])是0xc7e2ed74。

cat u-boot.map | grep default_environment
0xc7e2ed74 default_environment
0xc7e32d74 default_environment_size

在uboot shell環境下memory dump該記憶體位置內容:

SMDKC100 # md c7e2ed74
c7e2ed74: 746f6f62 73677261 6964723d 3d74696e bootargs=rdinit=
c7e2ed84: 6374652f 696e692f 2f642e74 20536372 /etc/init.d/rcS
c7e2ed94: 736e6f63 3d656c6f 53797474 2c304341 console=ttySAC0,
c7e2eda4: 32353131 62003030 63746f6f 6e3d646d 115200.bootcmd=n
c7e2edb4: 20646e61 61647075 6f626574 6f6c746f and updatebootlo
c7e2edc4: 72656461 6d6f7266 30303620 34203030 aderfrom 60000 4
c7e2edd4: 30303030 6e616e3b 65722064 32206461 0000;nand read 2
c7e2ede4: 38303030 20303030 30303061 33202030 0008000 a0000 3
c7e2edf4: 30303030 616e3b30 7220646e 20646165 00000;nand read
c7e2ee04: 30383032 30303030 30613320 20303030 20800000 3a0000
c7e2ee14: 30303037 623b3030 6d746f6f 30303220 700000;bootm 200
c7e2ee24: 30303830 30322030 30303038 6d003030 08000 20800000.m
c7e2ee34: 61706474 343d7472 30303030 30633320 tdpart=40000 3c0
c7e2ee44: 20303030 30303033 00303030 746f6f62 000 3000000.boot
c7e2ee54: 616c6564 00333d79 64756162 65746172 delay=3.baudrate
c7e2ee64: 3531313d 00303032 61687465 3d726464 =115200.ethaddr=
SMDKC100 #




(2) environment saved in the SD, NAND, and OneNAND

以NAND為例,environment varibles會被儲存在NAND offset=CFG_ENV_OFFSET size=CFG_ENV_SIZE
在uboot shell環境下,執行"saveenv"指令時,才會將"env_ptr"所指的runtime environment varibles寫到NAND 中。在下一次開機時,uboot會從NAND 載入environment varibles,所以當更新u-boot時須先將該environment varible區域erase,讓系統載入u-boot.bin中的default environment varibles,看下面 env_relocate_spec_nand()中,由於erase 了environment varible區域,所以做crc check會failed,就載入新的default environment varibles。


void env_relocate_spec_nand(void)
{
#if !defined(ENV_IS_EMBEDDED)
size_t total;
int ret;

total = CFG_ENV_SIZE;
ret = nand_read(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*)env_ptr);
if (ret || total != CFG_ENV_SIZE)
return use_default();

if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
return use_default();

#endif /* ! ENV_IS_EMBEDDED */
}

saveenv-> do_saveenv() (common/cmd_nvedit.c)->saveenv()(common/env_auto.c)->saveenv_nand()(common/env_auto.c)



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)
{
#if !defined(CONFIG_SMDK6440)
if (INF_REG3_REG == 2 || INF_REG3_REG == 3){
printf("saveenv_nand\n");
saveenv_nand();
}else if (INF_REG3_REG == 4 || INF_REG3_REG == 5 || INF_REG3_REG == 6){
printf("saveenv_nand_adv\n");
saveenv_nand_adv();
}else if (INF_REG3_REG == 0 || INF_REG3_REG == 7){
printf("saveenv_movinand\n");
saveenv_movinand();
}else if (INF_REG3_REG == 1){
printf("saveenv_onenand\n");
saveenv_onenand();
}else
printf("Unknown boot device\n");
#else
......
#endif

return 0;
}


int saveenv_nand(void)
{
size_t total;
int ret = 0;

puts("Erasing Nand...");
nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE);

//#ifndef CONFIG_S5PC100_EVT1
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
//#endif

puts("Writing to Nand... ");
total = CFG_ENV_SIZE;

//#ifndef CONFIG_S5PC100_EVT1
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*) env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
//#endif

puts("done\n");
return ret;


}

但因saveenv_nand()中的nand_erase()不能work,我們須改寫saveenv_nand() ,另外我們規劃environment varible放置在NAND offset=0x40000所以須更改include/configs/smdkc100.h中的CFG_ENV_OFFSET,另外因為NAND的erase單位為block (128K=0x20000)所以更改include/configs/smdkc100.h中的CFG_ENV_SIZE。


1.改include/configs/smdkc100.h中的CFG_ENV_SIZE


#define CFG_ENV_SIZE 0x4000

#define CFG_ENV_SIZE 0x20000

2.改include/configs/smdkc100.h中的CFG_ENV_OFFSET



#define CFG_ENV_OFFSET 0x0007C000



#define CFG_ENV_OFFSET 0x00040000


3. 改common/env_auto.c中的saveenv_nand()
saveenv->do_saveenv() (common/cmd_nvedit.c)->saveenv() (common/env_auto.c)->saveenv_nand() (common/env_auto.c)

int saveenv_nand(void)
{
nand_erase_options_t opts;
int ret;
size_t total;
size_t erase_size;
nand_info_t *ptr= &nand_info[0];
memset(&opts, 0, sizeof(opts));
opts.offset = CFG_ENV_OFFSET;
if(CFG_ENV_SIZE erasesize)
opts.length =ptr->erasesize;
else
opts.length =CFG_ENV_SIZE;


opts.jffs2 = 0;
opts.quiet = 0;


printf("CFG_ENV_OFFSET=%x, CFG_ENV_SIZE=%x erase size=%x\n",CFG_ENV_OFFSET,CFG_ENV_SIZE,opts.length );

ret = nand_erase_opts(&nand_info[0], &opts);
printf("Erasing Nand %s\n", ret ? "ERROR" : "OK");
if(ret!=0)
goto exit;

total = CFG_ENV_SIZE;
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*) env_ptr);
printf("Writing Nnand %d bytes %s: %s\n", total, "write" , ret ? "ERROR" : "OK");
if (ret || total != CFG_ENV_SIZE)
goto exit;


exit:
return ret;

/*
size_t total;
int ret = 0;

puts("Erasing Nand...");
nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE);

//#ifndef CONFIG_S5PC100_EVT1
if (nand_erase(&nand_info[0], CFG_ENV_OFFSET, CFG_ENV_SIZE))
return 1;
//#endif

puts("Writing to Nand... ");
total = CFG_ENV_SIZE;

//#ifndef CONFIG_S5PC100_EVT1
ret = nand_write(&nand_info[0], CFG_ENV_OFFSET, &total, (u_char*) env_ptr);
if (ret || total != CFG_ENV_SIZE)
return 1;
//#endif

puts("done\n");
return ret;
*/

}

沒有留言: