最后,设置 ATAG_NONE 标记,结束整个启动参数列表:
| static void setup_end_tag(void) { params->hdr.tag = ATAG_NONE; params->hdr.size = 0; } |
3.2.5 调用内核
Boot Loader 调用 Linux 内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到 MEM_START + 0x8000 地址处。在跳转时,下列条件要满足:
1 . CPU 寄存器的设置:
· R0 = 0 ;
@R1 =机器类型 ID ;关于 Machine Type Number ,可以参见 linux/arch/arm/tools/mach-types 。
@R2 =启动参数标记列表在 RAM 中起始基地址;
2 . CPU 模式:
·必须禁止中断( IRQs 和 FIQs );
· CPU 必须 SVC 模式;
3 . Cache 和 MMU 的设置:
· MMU 必须关闭;
·指令 Cache 可以打开也可以关闭;
·数据 Cache 必须关闭;
如果用 C 语言,可以像下列示例代码这样来调用内核:
| void (*theKernel)(int zero, int arch, u32 params_addr) = (void (*)(int, int, u32))KERNEL_RAM_BASE; …… theKernel(0, ARCH_NUMBER, (u32) kernel_params_start); |
注意, theKernel() 函数调用应该永远不返回的。如果这个调用返回,则说明出错。
四、 关于串口终端
在 boot loader 程序的设计与实现中,没有什么能够比从串口终端正确地收到打印信息能更令人激动了。此外,向串口终端打印信息也是一个非常重要而又有效的调试手段。但是,我们经常会碰到串口终端显示乱码或根本没有显示的问题。造成这个问题主要有两种原因: (1) boot loader 对串口的初始化设置不正确。 (2) 运行在 host 端的终端仿真程序对串口的设置不正确,这包括:波特率、奇偶校验、数据位和停止位等方面的设置。
此外,有时也会碰到这样的问题,那就是:在 boot loader 的运行过程中我们可以正确地向串口终端输出信息,但当 boot loader 启动内核后却无法看到内核的启动输出信息。对这一问题的原因可以从以下几个方面来考虑:
(1) 首先请确认你的内核在编译时配置了对串口终端的支持,并配置了正确的串口驱动程序。
(2) 你的 boot loader 对串口的初始化设置可能会和内核对串口的初始化设置不一致。此外,对于诸如 s 3c 44b0x 这样的 CPU , CPU 时钟频率的设置也会影响串口,因此如果 boot loader 和内核对其 CPU 时钟频率的设置不一致,也会使串口终端无法正确显示信息。
(3) 最后,还要确认 boot loader 所用的内核基地址必须和内核映像在编译时所用的运行基地址一致,尤其是对于 uClinux 而言。假设你的内核映像在编译时用的基地址是 0xc0008000 ,但你的 boot loader 却将它加载到 0xc0010000 处去执行,那么内核映像当然不能正确地执行了。
五、 结束语
Boot Loader 的设计与实现是一个非常复杂的过程。如果不能从串口收到那激动人心的
| "uncompressing linux .................. done, booting the kernel …… " |
内核启动信息,恐怕谁也不能说: " 嗨,我的 boot loader 已经成功地转起来了! " 。
关于作者
詹荣开,研究兴趣包括:嵌入式 Linux 、 Linux 内核、驱动程序、文件系统等。您可以通过 zhanrk@sohu.com 连系他。
1 2 3 4 5