/******初始化malloc空间,将其清零*******/
mem_malloc_init (_armboot_start - CONFIG_SYS_MALLOC_LEN,CONFIG_SYS_MALLOC_LEN);
/******打印nand信息*******/
#if defined(CONFIG_CMD_NAND)
puts ("NAND: ");
nand_init();
//初始化nandflash
#endif
以上两句代码执行完毕后,便打印出nand信息,如:NAND: 1024 MB
nand_init函数在drivers/mtd/nand/nand.c中
void nand_init(void)
{
int i;
unsigned int size = 0;
/*******下面这个循环用于确定出nandflash的大小*********/
for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) {
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
size += nand_info[i].size / 1024;
if (nand_curr_device == -1)
nand_curr_device = i;
}
printf("%u MiB\n", size / 1024);
//打印出nand的大小
#ifdef CONFIG_SYS_NAND_SELECT_DEVICE
/*
* Select the chip in the board/cpu specific driver
*/
board_nand_select_device(nand_info[nand_curr_device].priv, nand_curr_device);
#endif
}
CONFIG_SYS_MAX_NAND_DEVICE在include/config/相应的头文件中定义,用于定义板子上用了几块nandflash:
#define CONFIG_SYS_MAX_NAND_DEVICE
1
nand_info是一个结构体数组,数组中的每个元素代表一个难道的信息,如nand_info[0]代表第一块nandflash的信息,依次类推。
而这个结构体中则包含了一个nand的所有信息,包括块大小,每块的oob数据及oob字节数还有要对这个nand进行操作的一系列函数指针等,这个结构体在include/linux/mtd/mtd.h中定义,因为这个结构体信息太多,所以不详细列出:
struct mtd_info {
······
}
typedef struct mtd_info nand_info_t;
/*************重定位环境变量***************/
env_relocate ();
//这个函数的作用是实现对环境变量的重定位,从nand中将环境变量搬移到DDR2中
env_relocate函数在commo/env_common.c中定义,加黑部分是真正要执行的代码
void env_relocate (void)
{
#ifdef ENV_IS_EMBEDDED
········
#else
env_ptr = (env_t *)malloc (CONFIG_ENV_SIZE); //为环境变量申请一段空间
DEBUGF ("%s[%d] malloced ENV at %p\n", __FUNCTION__,__LINE__,env_ptr);
#endif
if (gd->env_valid == 0) {
#if defined(CONFIG_GTH)
|| defined(CONFIG_ENV_IS_NOWHERE)
/* Environment not changable */
puts ("Using default environment\n\n");
#else
puts ("*** Warning - bad CRC, using default environment\n\n");
show_boot_progress (-60);
#endif
set_default_env();
}
else {
env_relocate_spec (); //调用真正的重定位代码
}
gd->env_addr = (ulong)&(env_ptr->data); //将重定位后的环境变量的地址赋给gd->env_addr
}
nv_relocate_spec函数开始实现对环境变量的重定位,这个函数在common/env_nand中定义:
void env_relocate_spec (void)
{
#if !defined(ENV_IS_EMBEDDED)
int ret;
ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
//读取nand中保存的环境变量的值,并将其存放到env_ptr指向的
if (ret)
//地址中,完成环境变量从nand到DDR2的搬移
return use_default();
//根据返回值确定是否读取失败,如果失败则使用默认的环境变量
if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
//进行CRC效验,确定环境变量是否有效
return use_default();
//如果无效则使用默认的环境变量
#endif /* ! ENV_IS_EMBEDDED */
}
上面的代码很清楚的表明了env_relocate_spec的意图 ,调用readenv将环境变量从nand的CFG_ENV_OFFSET 处读出,环境变量的大小为 CFG_ENV_SIZE ,注意 CFG_ENV_OFFSET 和CFG_ENV_SIZE 要和 Nand Flash 的块/页边界对齐。读出数据后再调用crc32 对env_ptr->data 进行校验并与保存在 env_ptr->crc 的校验码对比,看数据是否出错。从这里也可以看出在系统第一次启动时Nand Flash 里面没有存储任何环境变量,crc校验肯定回出错,当我们保存环境变量后,接下来再启动板子u-boot就不会再报crc32出错了。
代码中相关宏的作用:
ENV_IS_EMBEDDED : 环境变量是否存在于 u-boot 的 text 段中
CFG_ENV_SIZE : 环境变量的大小
CFG_ENV_IS_IN_NAND : 环境变量是否存放在Nand Flash 中
CFG_ENV_OFFSET : 环境变量在 Nand Flash 中的偏移地址
如果CRC效验出错,说明nand中的环境变量无效,所以就会使用默认的环境变量,默认的环境变量在数组default_environment中,这个数组定义在common/env_common.c中。这时会调用函数use_default()
这个函数在common/env_nand中:
static void use_default()
{
puts ("*** Warning - bad CRC or NAND, using default environment\n\n");
set_default_env();
}
set_default_env 函数定义在common/env_common.c:
void set_default_env(void)
{
if (sizeof(default_environment) > 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,
//将默认环境变量的值复制到环境变量的存储区中
sizeof(default_environment));
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
env_ptr->flags = 0xFF;
#endif
env_crc_update ();
//进行CRC效验
gd->env_valid = 1;
//设置环境变量为有效
}
/**********************初始化多串口*********************************/
#ifdef CONFIG_SERIAL_MULTI
serial_initialize();
#endif
serial_initialize函数在common/seria.c中定义:
void serial_initialize (void)
{
#if defined(CONFIG_S5PC1XX)
serial_register(&s5pc1xx_serial0_device);
//这个函数做的主要操作就是将每个串口的私有结构体插入到链表中
serial_register(&s5pc1xx_serial1_device);
serial_register(&s5pc1xx_serial2_device);
serial_register(&s5pc1xx_serial3_device);
#endif
serial_assign (default_serial_console ()->name);
//将先前在default_serial_console 函数中返回的默认使用的串口结构体的
//指针赋给当前串口结构体指针 serial_current
}
serial_register
函数在common/seria.c中定义:
int serial_register (struct serial_device *dev)
{
dev->next = serial_devices;
//这两句代码就是插入链表的操作,
serial_devices = dev;
return 0;
}
serial_assign 函数在common/seria.c中定义:
int serial_assign (char *name)
{
struct serial_device *s;
for (s = serial_devices; s; s = s->next) {
//根据传进来的串口名字,设置当前串口serial_current 结构体的指针
if (strcmp (s->name, name) == 0) {
serial_current = s;
return 0;
}
}
return 1;
}
在common/seria.c定义了serial_devices和serial_current 变量:
static struct serial_device *serial_devices = NULL;
static struct serial_device *serial_current = NULL;