start.s完成后,跳转到start_armboot继续执行相关操作。
1.gd相关初始化。放在sdram中,记录一些相关信息。如环境变量等,下面会用到。
2.nor falsh识别及初始化
flash_init
flash_detect_legacy (BANK_BASE(i), i) //jedec协议查找flash类型
cmdset_intel_read_jedec_ids //获取厂家ID和设备ID
manufacturer_id = flash_read_uchar (info,MANUFACTURER_ID);//厂家ID
device_id = flash_read_uchar (info,FLASH_OFFSET_DEVICE_ID); //设备ID
jedec_flash_match(info, base)//得到厂家ID和设备ID后,进行匹配.
//根据厂家ID和设备ID获取 名字,位宽,大小,flash区域信息
/*******************************match array**********************************/
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29DL800BT,
.name = "AMD AM29DL800BT",
.uaddr = {
[0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */
[1] = MTD_UADDR_0x0555_0x02AA, /* x16 */
},
.DevSize = SIZE_1MiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 6,
.regions = {
ERASEINFO(0x10000,14),
ERASEINFO(0x04000,1),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,4),
ERASEINFO(0x08000,1),
ERASEINFO(0x04000,1)
}
***************************************************************************/
flash_get_size//如果查找不到,就用cfj协议继续查找。
__flash_detect_cfi // cfi 协议
flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP, 'Q') //读Q
flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 1, 'R')//读R
flash_isequal (info, 0, FLASH_OFFSET_CFI_RESP + 2, 'Y') //读Y
3.nand falsh识别及初始化
nand_init
nand_init_chip(&nand_info[i], &nand_chip[i], base_address[i]);
board_nand_init(nand);//将片选,读写,判断读写完成命令,写到chip中。知道怎么发。最终给MTD
s3c24x0_nand_inithw();//填好时序
chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA; //读flash
chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA; //写flash
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
chip->select_chip = s3c2410_nand_select_chip; //选中
nand_scan(mtd, 1);
struct nand_chip *this = mtd->priv;
this->select_chip = nand_select_chip;//构造片选
this->cmdfunc = nand_command;//构造命令
this->select_chip(mtd, 0); //选中
this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1);//发命令 cle信号
nand_maf_id = this->read_byte(mtd);//读取厂家ID
nand_dev_id = this->read_byte(mtd);//读取设备ID
//相关oob设置
mtd->read = nand_read;
mtd->write = nand_write; //MTD层应用chip中函数,组成MTD协议。知道如何发
4.环境变量
4.1 环境变量初始化及重定位
a. 从heap中分配一段空间,用于env_t结构
b. 找到环境变量(或从内存中找或从nand中找),填充env_t结构
c. 将gd->env_addr指向env_ptr->data。
env_init(void) // 先看开始循环体中此函数做了什么
gd->env_addr = (ulong)&default_environment[0]; //使用默认的环境变量
gd->env_valid = 1; //valid
env_relocate //环境变量重定位。从nandflash的params分区中考到内存中
env_ptr = (env_t *)malloc (CFG_ENV_SIZE); //从heap中分配一段内存
env_relocate_spec ();
/**************************smdk2410_config.h*********************/
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0x40000
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
/****************************************************************/
tmp_env1 = (env_t *) malloc(CFG_ENV_SIZE);
nand_read(&nand_info[0], CFG_ENV_OFFSET, &total,(u_char*) tmp_env1);//从nand中读取环境变量
free(env_ptr); //crc验证OK,释放开始的默认堆中分配的环境变量
env_ptr = tmp_env1;//ok,把目前存放环境变量的地址赋给全局指针变量
gd->env_addr = (ulong)&(env_ptr->data);// 把环境变量的数据指针保存在gd中
4.2 获取环境变量(以启动kernel为例)
/*就以bootcmd为例
#define CONFIG_BOOTCOMMAND "nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0"
uboot输入 print后会显示:
bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
下面分析 如何获取环境变量:
首先想到的是匹配名字,如先查找bootcmd,然后解析后面的内容。
*/
s = getenv ("bootcmd");
val=envmatch((uchar *)name, i) //进行名字匹配,直到匹配成功
return ((char *)env_get_addr(val)); //返回“=”后面的地址
//现在s = “nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0”
4.3执行环境变量中的命令(以启动kernel为例)
//分析执行环境变量中的参数
run_command (s, 0);
//首先分割字符串。;一行命令结束标志
process_macros (token, finaltoken);
parse_line (finaltoken, argv);//按照 ‘ ’,‘\t’分割字符串。放到argv[]中
cmdtp = find_cmd(argv[0]);//查找命令
// __u_boot_cmd_start放置在lds中,会在这段内存中查找,匹配名字
for (cmdtp = &__u_boot_cmd_start;cmdtp != &__u_boot_cmd_end;cmdtp++)
(cmdtp->cmd) (cmdtp, flag, argc, argv);//执行命令
//分析上面字符串,第一个命令时nand。根据“nand”名字匹配,找到do_nand函数。
//nand read.jffs2 0x30007FC0 kernel。从kernel分区中读到0x30007FC0内存中
U_BOOT_CMD(
nand, 5, 1, do_nand,
"nand - legacy NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2[s]] addr off size\n"
"nand write[.jffs2] addr off size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand read.oob addr off size - read out-of-band data\n"
"nand write.oob addr off size - read out-of-band data\n"
);
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#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}
//bootm 0x30007FC0.从0x30007fc0boot kernel
同样按照上述方法查找到 执行do_bootm
do_bootm
memmove (&header, (char *)addr, sizeof(image_header_t)); // 64字节uImage头
switch (hdr->ih_comp)//根据头文件指示进行解压缩
switch (hdr->ih_os)//Operating System
do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);//我们是linux
setup_start_tag (bd);//设置tag。uboot和kernel进行交接
setup_memory_tags (bd);//memroy
setup_end_tag (bd);//结束
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);//机器ID,tag。uboot完成了最终的使命。
到此uboot算完事了。最重要的就是获取环境变量和分析并run_command命令。进入uboot,可以按help查看当前uboot支持哪些命令。