新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 基于cortex-A8的Bootloader设计

基于cortex-A8的Bootloader设计

作者: 时间:2016-09-12 来源:网络 收藏

图2  U-Boot第一阶段启动流程

图2 U-Boot第一阶段启动流程

U-Boot上电后首先会设置cpu为管理模式,禁用L1缓存,关闭MMU和清除caches。之后会调用底层初始化函数lowlevel_init()。该函数实现如下:

.globl lowlevel_init

lowlevel_init:

push {lr}

#if defined(CONFIG_SPL_BUILD)

/* 初始化时钟 */

bl system_clock_init

/* 初始化内存 */

bl mem_ctrl_asm_init

/* 初始化串口 */

bl uart_asm_init

#endif

pop {pc}

上述代码中system_clock_init(), mem_ctrl_asm_init(),uart_asm_init()这三个函数需要开发者结合具体硬件环境进行修改和实现。

初始化完成之后,U-Boot会调用一个拷贝函数将BL2拷贝到内存地址为0x3FF00000处,然后跳转到该位置执行BL2。在U-Boot中,BL1 和BL2是基于相同的一些源文件编译生成的。开发者在编写代码时需要使用预编译宏CONFIG_SPL_BUILD来实现BL1和BL2不同的功能。其拷贝函数实现如下:

void copy_code_2_sdram_and_run(void)

{

unsigned long ch;

void (*u_boot)(void);

ch = *(volatile unsigned int *)(0xD0037488); /* 根据该地址的值判断传输通道 */

/* copy_bl2()函数不需要开发者去实现,在出厂时已经固化在了0xD0037F98地址处 */

copy_sd_mmc_to_mem copy_bl2 = (copy_sd_mmc_to_mem) (*(unsigned int *) (0xD0037F98));

unsigned int ret;

if (ch == 0xEB000000) { /* CONFIG_SYS_TEXT_BASE = 0x3FF00000 */

ret = copy_bl2(0, 49, 1024,(unsigned int *)CONFIG_SYS_TEXT_BASE, 0);

} else if (ch == 0xEB200000) {

ret = copy_bl2(2, 49, 1024,(unsigned int *)CONFIG_SYS_TEXT_BASE, 0);

} else {

return;

}

u_boot = (void *)CONFIG_SYS_TEXT_BASE;

(*u_boot)(); /* 跳转到该地址执行 */

}

值得注意的是以上代码中,copy_bl2()函数不需要开发者去实现,在出厂时已经将该函数固化在了0xD0037F98地址处。其函数原型如下:

u32 (*copy_sd_mmc_to_mem)(u32 channel, u32 start_block, u16 block_size, u32 *trg, u32 init);

/*

参数介绍:

channel:通道数2或0,该值通过读取0xD0037488地址上的值判断。

start_block:从第几个扇区开始拷贝,一个扇区为512byte。

block_size:拷贝多少个扇区,这里拷贝512K

trg:目的地址:0x3FF00000, 即离内存顶部1M的位置

init:是否需要初始化sd卡,写0即可。

*/

2.3.2 第二阶段初始化

U-Boot进入第二阶段后会首先声明一个gd_t结构体类型的指针指向内存地址(0x40000000 - GD_SIZE)处。0x40000000为内存结束地址,GD_SIZE为结构体gd_t的大小。这样相当于在内存最顶端分配了一段空间用于存放一个临时结构体gd_t。该结构体在global_data.h中被定义,U-Boot用它来存储所有的全局变量。之后U-Boot会调用 board_init_f()和board_init_r()两个函数进一步对底板进行初始化。

(1)board_init_f()

进入board_init_f()之后,U-Boot首先设置之前分配的临时结构体,然后开始划分内存空间,其内存分配示意图如下:

图3  U-Boot内存分配状态

图3 U-Boot内存分配状态

从内存分配状态图中我们可以看到,gd指针指向的临时结构体存放在内存的最顶部。BL2代码存放在内存地址0x3ff00000处,即距离内存顶部1M空间的位置。接下来依次分配malloc空间,bd_t结构体空间和gd_t结构体空间,并且重新设置栈。最后将临时结构体拷贝到id指针所指向的位置。 board_init_f()实现过程大致如下:

unsigned int board_init_f(ulong bootflag)

{

memset((void *)gd, 0, sizeof(gd_t));

...

设置gd结构体;

...

addr = CONFIG_SYS_TEXT_BASE; /* CONFIG_SYS_TEXT_BASE = 0x3ff00000000 */

addr_sp = addr - TOTAL_MALLOC_LEN;

addr_sp -= sizeof (bd_t);

bd = (bd_t *) addr_sp;

gd->bd = bd;

addr_sp -= sizeof (gd_t);

id = (gd_t *) addr_sp;

...

memcpy(id, (void *)gd, sizeof(gd_t));

base_sp = addr_sp;

return (unsigned int)id;

}

(2)board_init_r()

board_init_r()负责对其他硬件资源进行初始化。如网卡、Flash、MMC、中断等。最后调用main_loop(),等待用户输入命令。

3 设计实现

3.1 支持Nand Flash读写

Nand Flash是嵌入式系统中重要的存储设备,其储存对象包括Bootloader本身,操作系统内核,环境变量,根文件系统等,所以使能Nand Flash读写是U-Boot移植过程中必须完成的一个步骤。U-Boot中Nand Flash初始化函数调用关系为:

board_init_r()->nand_init()->nand_init_chip()->board_nand_init()。

board_nand_init() 完成两件事:(1)对关于Nand Flash控制器的相关寄存器进行设置。(2)对nand_chip结构体进行设置。我们需要设置的成员项有IO_ADDR_R,IO_ADDR_W,这两个成员都指向地址0xB0E00010,即 Nand Flash控制器的数据寄存器的地址。另外还需要实现以下三个成员函数:

① void (*select_chip)(struct mtd_info *mtd, int chip);

该函数实现Nand Flash设备选中或取消选中。

② void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl);



评论


相关推荐

技术专区

关闭