uboot移植之修改支持NandFlash识别篇6(超详细)
目录
前程回顾:
剔除掉一些多余的宏开关之后,以及一些多余的函数之后,init_sequence_f数组内容如下:
static init_fnc_t init_sequence_f[] = {
setup_mon_len, //设置gd结构体成员mon_len//gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE
//CONFIG_SYS_MONITOR_BASE为0, 所以gd->mon_len为u-boot.bin+bss段大小
board_early_init_f,
env_init, //初始化环境变量,其默认的环境变量在include/env_default.h中定义
init_baud_rate, //波特率初始化为115200
serial_init, //串行通信设置,初始化
console_init_f, // 第一阶段平台的初始化
display_options, //打印uboot信息
display_text_info, //可以通过在 include/common.h 定义DEBUG 开启显示及打印一些debug信息功能,
print_cpuinfo, //显示cpu的id以及频率
announce_dram_init, //调用puts打印一些信息
/* TODO: unify all these dram functions? */
dram_init, //gd->ram_size = PHYS_SDRAM_1_SIZE; (将sdram的大小64M,存在gd->ram_size中)setup_dest_addr,
reserve_round_4k,
reserve_mmu,
reserve_uboot,
reserve_malloc,
reserve_board,
reserve_global_data,
reserve_fdt,
reserve_stacks,
setup_dram_config, //bank_size块大小设置
show_dram_config, //显示sdram的一些信息
display_new_sp, //打印出当前gd->start_addr_sp
reloc_fdt,
setup_reloc,
NULL,
}
下面分析几个比较重要的函数:
1、board_early_init_f开启MPLL,UPLL。(移植需修改)
PLL在上电复位后开始是不稳定的,所以在上电 复位后12Mhz直接作为Fclk,这时MPLL是不起作用的。如果要想是MPLL起作用,那么要先配置锁定时间寄存器(LOCKTIME),根据公式在寄存器中设置好对应的MPS位
再配置MPLLCON寄存器值,然后等待LOCKTIME时间 后,新的Fclk开始工作,另外,时钟分频系数早在start.s中已经配置好了。(翻译:用户可以通过写入PMS值和PLL的locktime来改变频率,并自动插入锁相环锁定时间。在锁定时间内,时钟不提供给s3c2440a中的内部块。)
2、init_baud_rate,串口波特率初始化为CONFIG_BAUDRATE,即115200
在uboot菜单输入print打印环境变量,发现结果匹配
3、display_options,打印uboot信息
version_string其实就是存放了一些关于uboot字符串的一个缓冲区,再启动的时候打印出uboot的一些版本信息等等。
定义:const char __weak version_string[] = U_BOOT_VERSION_STRING;
uboot启动输出:
4、setup_dest_addr,设置gd->relocaddr,gd->ram_top的指向,指向sdram最顶端0x34000000。
宏CONFIG_SYS_SDRAM_BASE在include\configs\smdk2440.h被定义为0x30000000。在加上从get_effective_memsize函数中返回的gd->ram_size,刚好是0x34000000。gd->ram_size在dram_init函数已经被赋值了。所以,执行完这函数之后:
gd->relocaddr=0x34000000,gd->ram_top=0x34000000。
5、reserve_round_4k,4KB对齐。
4kb对齐,其临界值是0x00001000,所以,gd->relocaddr对齐之后,还是不变,gd->relocaddr=0x34000000。小测试:
6、reserve_mmu, 预留空间存放TLB,以及64kb对齐。
宏PGTABLE_SIZE被定义为4096 * 4,1kb=1024字节,所以保留了16kb的空间给TLB后,gd->relocaddr=0x33ffc000。
64kb对齐后,gd->relocaddr=0x33ff0000。
7、reserve_uboot,预留空间给uboot。
这是我个人的想法,关于uboot的大小不能单纯地看u-boot.bin,因为u-boot.bin并没有包含bss段大小,而u-boot.elf当中又包含了一些多余的调试信息,所以先执行命令:
arm-linux-objdump -h u-boot (u-boot是elf格式)
Idx Name Size VMA LMA File off Algn
9 .bss 0004edf8 00078a70 00078a70 00000000 2**8 //size的单位是字节
所以,bss段大小为323064字节,即315kb,uboot大小(含bss段)为836kb。gd->relocaddr=0x33f1f000。
4kb对齐后,gd->relocaddr和gd->start_addr_sp都等于0x33f1f000。
8、reserve_malloc,保留malloc区域。
宏TOTAL_MALLOC_LEN被定义为4 * 1024 * 1024,相减后,gd->start_addr_sp=0x33b1f000。在uboot中,分配释放堆这些操作都要自己去实现,该段空间就是用来实现这个功能,因为c库是在挂接根文件系统之后才能使用的。
9、reserve_board,预留bd_info结构体大小空间,并清零。
bd_t其实就是bd_info结构体,里面存放了许多单板相关的变量成员。关于sizeof(gd_t)的大小,我们可以通过查看反汇编文件得知:
立即数后缺省情况下表示十进制,所以sizeof(gd_t)=80byte,相减后,gd->start_addr_sp=0x33b1efb0。
10、reserve_global_data,预留空间给gd_t结构体。
同上方法,查出sizeof(gd_t)=168byte,相减后,gd->start_addr_sp=0x33b1ef08。在函数数组的最后会调用setup_reloc()将gd结构体复制到这来。
11、reserve_fdt,应该并没有预留空间给设备树驱动。
我的做法:搜索 gd->fdt_blob = 的索引
---- gd->fdt_blob = Matches (9 in 3 files) ----
reloc_fdt in board_f.c (u-boot-2016.07\common) : gd->fdt_blob = gd->new_fdt; //排除
do_fdt in fdt.c (u-boot-2016.07\cmd) : gd->fdt_blob = blob;
do_fdt in fdt.c (u-boot-2016.07\cmd) : gd->fdt_blob = blob;
fdtdec_setup in fdtdec.c (u-boot-2016.07\lib) : gd->fdt_blob = __dtb_dt_begin;
fdtdec_setup in fdtdec.c (u-boot-2016.07\lib) : gd->fdt_blob = (ulong *)&_image_binary_end;
fdtdec_setup in fdtdec.c (u-boot-2016.07\lib) : gd->fdt_blob = (ulong *)&__bss_end;
fdtdec_setup in fdtdec.c (u-boot-2016.07\lib) : gd->fdt_blob = (ulong *)&_end;
fdtdec_setup in fdtdec.c (u-boot-2016.07\lib) : gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16,
do_fdt开头的类似函数大多都是在uboot菜单输入命令的时候,调用对应的do_前缀函数来处理输入的命令及参数。或者在程序中显示地调用run_command();函数去调用执行,
其余的来自于fdtdec_setup函数:
其中,由于宏没有定义,所以并没有对gd->fdt_blob的赋值。
12、reserve_stacks,预留空间给栈。空间大小和特定的架构有关。
相减后,gd->start_addr_sp=0x33b1eef8。与操作后,gd->start_addr_sp=0x33b1eef0。调用函数:
16字节对齐后,gd->irq_sp=0x33b1eef0。之后,留出3字节给栈,为了对齐再加上1字节,共4字节。
所以,gd->start_addr_sp=0x33b1eee0。
13、reloc_fdt,什么也没做。
判断决定是否将gd->fdt_blob里面的内容,拷贝到之前划分出来的区域段中。
在void board_init_f( ulong boot_flags ) 函数中gd->flags = boot_flags,而 r0=0 作为参数传入board_init_f函数,所以并没有执行重定位设备树。
14、setup_reloc,重定位gd结构体。
宏CONFIG_SYS_TEXT_BASE被定义为0x0,gd->new_gd指向在reserve_global_data分配出来的新空间,所以该函数主要是通过调用memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); 将gd结构体中的东西存放在之前分配的空间处。
内存分布总结:
最后,结合上面分析,可以得出内存划分图如下:
注:为了测试方便,板子中采用的uboot版本和分析的源码版本不匹配,后期有时间会修改回来,但是这并不影响我们分析整个流程。
参考资料:
《ARM9嵌入式系统设计与应用开发》 熊茂华 杨震伦 主编
《汇编语言程序设计——基于ARM体系结构》 文全刚 赫志刚 主编
《嵌入式Linux应用开发完全手册》 韦东山著
《S3C2440A_UserManual_Rev13》