首先说明一下,本人是一个刚刚入行的新手。第一次写这样的博客可能有很多不足之处,还望各位同僚能够包容。不喜勿喷。
那么现在就开始进入今天的重头戏,bootloader的启动流程以及VIVI的源码分析。
什么是Bootloader :
Bootloader 是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序,其作用类似于 PC 机上的 BIOS。在完成对系统的初始化任务之后,它会将Linux 内核拷贝到 RAM 中去,然后跳转到内核的第一条指令处继续执行,从而启动 Linux 内核。
Bootloader的启动流程 :
一般来说bootloader的启动分为两大阶段:
第一阶段:第一阶段主要包含依赖于CPU的体系结构硬件初始化的代码,通常都用汇编语言来实现。在这个阶段的中它初始化基本的硬件设备(关闭看门狗、屏蔽所有的中断、关闭处理器内部指令/数据Cache等)。初始化SDRAM为第二阶段准备RAM空间,如果是从某个固态存储媒质中,则复制Bootloader的第二阶段代码到RAM。设置堆栈跳转到第二阶段的C程序入口点,在C程序中完成更多的初始化设置。
第二阶段:第二阶段通常用C语言完成,以便实现更复杂的功能,也使程序有更好的可读性和可移植性。这个阶段的任务有:
1.初始化本阶段要使用到的硬件设备。
2.检测系统内存映射。
3.将内核映像和根文件系统映像从Flash读到RAM。
4.为内核设置启动参数。调用内核。
下面一起来看看VIVI的源码 :
head.S
关闭看门狗
mov r1, #0x53000000
mov r2, #0x0
str r2, [r1]
关闭所有中断
mov r1, #INT_CTL_BASE
mov r2, #0xffffffff
str r2, [r1, #oINTMSK]
ldr r2, =0x7ff
str r2, [r1, #oINTSUBMSK]
初始化SDRAM
mov r1, #MEM_CTL_BASE
adrl r2, mem_cfg_val
add r3, r1, #52
1: ldr r4, [r2], #4
str r4, [r1], #4
cmp r1, r3
bne 1b
mov pc, lr
跳转到main
mrs r0, cpsr
bic r0, r0, #0x1f
orr r1, r0, #(0x12|0xc0)
msr cpsr_c, r1
msr cpsr_c,#0xd2
ldr sp, IRQ_STACK_START
msr cpsr_c,#0xdf
@ get read to call C functions
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
mov a2, #0 @ set argv to NULL
bl main @ call main
main.c
1.打印版本信息
putstr(vivi_banner);
const char *vivi_banner =
"VIVI version " VIVI_RELEASE " (" VIVI_COMPILE_BY "@"
VIVI_COMPILE_HOST ") (" VIVI_COMPILER ") " UTS_VERSION "\r\n";
2.初始化板子相关的时钟和默认GPIO
ret = board_init();
init_time();
set_gpios();
3.MMU初始化
mem_map_init();
mem_map_nand_boot();
cache_clean_invalidate();
tlb_invalidate();
mmu_init();
arm920_setup();
4.分配堆栈空间
ret = heap_init();
mmalloc_init((unsigned char *)(HEAP_BASE), HEAP_SIZE);
5.MTD初始化
ret = mtd_dev_init();
ret = mtd_init();
add_command(&flash_cmd);
6.改变系统倍频进入shell
ChangeUPllValue(56,2,2);
boot_or_vivi();
7.Shell中启动内核
exec_string("boot");