RedBoot (bootloader)
- 概述
- RedBoot所作的工作
概述
(本示例讲解基于ARM9的Cirrus EP9302) Bootloader 在 ARM 中依然是加电后的第一道程序,其作用简单,相当于 PC 机器上的 BIOS 固件程序。Bootloader 负责完成系统初始化,它将非易失性储存器中的 Linux 内核 拷贝到 RAM 中去,然后跳转到内核的第一道指令,将控制权交给内核。从这个意义上讲, 嵌入式 Bootloader 要做的事情比 x86 等机器多很多。
一般ARM Linux的第一条指令地址是0x0000_0000,而通常嵌入式系统会将FLASH等存储寄存 器映射到这个地址,而Bootloader就位于该存储器顶端,这保证了Bootloader的顺利执行。
以 RedBoot for EP93xx 为例,EP93xx 采用 NAND Flash 作为存储介质,在 RedBoot 中可 以罗列存储器的根目录如下:
RedBoot> fis init
Name FLASH addr Mem addr Length Entry point
RedBoot 0x60000000 0x60000000 0x00040000 0x00000000
RedBoot config 0x60FC0000 0x60FC0000 0x00001000 0x00000000
FIS directory 0x60FE0000 0x60FE0000 0x00020000 0x00000000
zImage 0x60040000 0x00080000 0x00120000 0x00080000
ramdisk 0x60140000 0x00800000 0x00800000 0x00800000
这里可以看出在 Flash 文件系统中存储了他的系统文件 RedBoot(内核)、RedBoot config(设置信息)、FIS directory(系统目录),另外就是 Linux 的内核 zImage 和内 存盘 ramdisk.gz。
RedBoot做的工作
- SDRAM初始化,没有内存,啥东西也玩不转 (cyg/hal/hal_platform_setup.h)
- 初始化串口 (hal/arch/ARCH/src/hal_diag.c)
- 检测处理器类型 (宏指定,cdl/hal_ARCH_MACHINE.cdl)
- 设置Linux启动参数 (hal/ARCH/arch/src/redboot_linux_exec.c)
- 将Linux内核装载到内存中,跳转执行
启动内核
启动内核函数do_exec的这段代码在 hal/ARCH/arch/src/redboot_linux_exec.c,最重要的 就是末尾处的内联汇编语句:
asm volatile (首先关闭MMU,保证代码跳转位置是绝对的物理地址,然后重置内核(如果需要)到entry处, 执行跳转,跳转前保证了:r0置0,r1装载机器类型,r2装载struct tag数组地址。
CYGARC_HAL_MMU_OFF(%5)
"__tramp_start__:\n"
" cmp %1,%4;\n" // Default kernel load address. Relocate
" beq 2f;\n" // kernel image there if necessary, and
" cmp %2,#0;\n" // if size is non-zero
" beq 2f;\n"
"1:\n"
" ldr r0,[%1],#4;\n"
" str r0,[%4],#4;\n"
" subs %2,%2,#4;\n"
" bne 1b;\n"
"2:\n"
" mov r0,#0;\n" // Set board type
" mov r1,%3;\n" // Machine type
" mov r2,%6;\n" // Kernel parameters
" mov pc,%0;\n" // Jump to kernel
"__tramp_end__:\n"
: :
"r"(entry),
"r"(CYGARC_PHYSICAL_ADDRESS(base_addr)),
"r"(length),
"r"(CYGHWR_REDBOOT_ARM_MACHINE_TYPE),
#ifdef CYGHWR_HAL_ARM_EDB93XX_VARIANT
"r"((CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS & 0x3ffffff) +
ConfigInfo[3]),
#else
"r"(CYGHWR_REDBOOT_ARM_LINUX_EXEC_ADDRESS),
#endif
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_TRAMPOLINE_ADDRESS)),
"r"(CYGARC_PHYSICAL_ADDRESS(CYGHWR_REDBOOT_ARM_LINUX_TAGS_ADDRESS))
: "r0", "r1"
);
这样RedBoot结束了其短暂而又伟大的一生,我们进入Linux的世界。