【转】基于mips架构的uboot 启动流程 (2)连载三:

2) 石器时代: FLASH 中的 C 代码在临时栈空间中活跃:
这部分的代码的使命是致力于建立一个“正常”的 C 运行环境,主要是内存的初始化及整个寻址空间的部分初始化。而这部分代码本身所运行的环境受到较多限制,只有一个大小受限的 scratch memory 作为临时运行的栈空间。

/***************************************************************************************/
board_init_f() 函数一开始出现一个宏, DECLARE_GLOBAL_DATA_PTR ,查看该宏的定义 (include/asm-mips/Global_data.h) :
#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm ("k0")

结合注释可以了解到,这些关于系统信息的结构体 (GD 是指 Global Data, BD 是指 Board info Data) 应该存放于在 DRAM 控制器未初始化之前就能使用的空间中,比如锁定的缓存中。在这里我们可以暂时把它放在已经初始化好的临时栈空间 scratch memory 中。
GD 和 BD 是很重要的结构体,后面当 DRAM 初始化完成后,会将其拷贝入 DRAM 空间保存。

/***************************************************************************************/
接着往下是循环调用 init_sequence 函数指针数组中的成员,来依次调用数组列表中的函数进行初始化。
init_sequence 的定义如下(将部分预编译指令去掉后的代码):
init_fnc_t * init_sequence[] = {
octeon_boot_bus_init,
timer_init,
env_init, /* initialize environment */
early_board_init,
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f,
display_banner, /* say that we are here */
init_dram,
dram_test,
init_func_ram,
NULL,
};

/***************************************************************************************/
从调用完 init_sequence 中的函数后往下看:
/*
* Now that we have DRAM mapped and working, we can
* relocate the code and continue running from DRAM.
*/
#if defined(CONFIG_NO_RELOCATION) && defined(CONFIG_RAM_RESIDENT)
/* If loaded into ram, we can skip relocation , and run from the spot we were loaded into */
addr = CFG_MONITOR_BASE;
u_boot_mem_top = CFG_SDRAM_BASE + MIN(gd->ram_size, (1*1024*1024));
#else
/* Locate at top of first Megabyte */
addr = CFG_SDRAM_BASE + MIN(gd->ram_size, (1*1024*1024));
u_boot_mem_top = addr;

其中 CFG_SDRAM_BASE = 0x8000 0000 ,是 MIPS 虚拟寻址空间中 kseg0 段的起始地址(参考《 See MIPS Run 》),它经过 CPU TLB 翻译后是 DRAM 内存的起始物理地址。
这里显然是将 u_boot_mem_top 和 addr 指向了 DRAM 中 1M 地址处 ( 从 DRAM 起始地址到 1M 地址处的 1M 空间是为 U-boot 自己运行分配的 ) , 即从 0x8000 0000 到 0x8010 0000 的 1M 空间是 U-boot 自己活跃的天下了。

/***************************************************************************************/
现在 U-boot 有了对自己来说很富裕的 1M 字节可以自由分配的 DRAM 空间了,下面很大一段代码都是对这 1M 内存的划分和分配。

这部分代码精简后,加入详细注释如下:
/* We can reserve some RAM "on top" here. */ // 从 0x8010 0000 处开始向下划分势力范围
/* round down to next 4 kB limit. */
addr &= ~(4096 - 1); //addr &= ~0x0FFF 这种计算是常用的地址对齐的算法,这里是向下 4K 字节对齐
/* Reserve memory for U-Boot code, data & bss*/
addr -= MAX(len, (512*1024)); // 为 code, data, bss 段保留 512K 的空间
/* round down to next 64k (allow us to create image at same addr for debugging)*/
addr &= ~(64 * 1024 - 1); // 向下 64K 字节对齐
/* Reserve memory for malloc() arena. */
addr_sp = addr - TOTAL_MALLOC_LEN; // 划分 malloc() 使用的空间,即所谓的堆空间,大小有宏来确定
/* (permanently) allocate a Board Info struct and a permanent copy of the "global" data*/
addr_sp -= sizeof(bd_t); // 分配 BD 结构体大小的空间
bd = (bd_t *)addr_sp;
gd->bd = bd; //GD 中的指针关联到此处的 BD 结构体地址
addr_sp -= sizeof(gd_t); // 分配 GD 结构体大小的空间
id = (gd_t *)addr_sp; //id 指针指向 GD 结构体地址
/* Reserve memory for boot params. */
addr_sp -= CFG_BOOTPARAMS_LEN; // 分配 boot param 的空间,这里的宏大小是 128K 字节
bd->bi_boot_params = addr_sp; // 在 BD 中记录此 boot param 空间的地址
/* Finally, we set up a new (bigger) stack. Leave some safety gap for SP, force alignment on 16 byte boundary */
addr_sp -= 16; // 向下一帧,保证栈空间的开始没有和之前分配的空间冲突
addr_sp &= ~0xF; // 栈空间 16 字节对齐
#define STACK_SIZE (16*1024UL)
bd->bi_uboot_ram_addr = (addr_sp - STACK_SIZE) & ~(STACK_SIZE - 1); // 将栈地址 16K 对齐后记录入 BD
bd->bi_uboot_ram_used_size = u_boot_mem_top - bd->bi_uboot_ram_addr; // 在 BD 中记录使用的 DRAM 大小
/* Save local variables to board info struct */
bd->bi_memstart = CFG_SDRAM_BASE; /* start of DRAM memory */ //0x80000000
bd->bi_memsize = gd->ram_size; /* size of DRAM memory in bytes */
bd->bi_baudrate = gd->baudrate; /* Console Baudrate */
memcpy (id, (void *)gd, sizeof (gd_t)); // 将在临时栈空间 scratch memory 中的 GD 数据拷贝入 DRAM 中,至此, BD 和 GD 都已经存在于 DRAM 中了。

根据这部分代码可以画出 U-boot 这 1M 空间的示意图:

/***************************************************************************************/
1M 空间瓜分完毕后,出现一条语句:
relocate_code (addr_sp, id, addr);
该语句使程序回到 cpu/mips/start.S 的汇编中,在之后的汇编中, U-boot 将自己的代码段、数据段、 BSS 段等搬到在 DRAM 中新家,为以后跨入速度时代而过渡。

--电子创新网--
粤ICP备12070055号