jephen

翻译:U-Boot programming: A tutorial Part III

0
阅读(620)

英文原文:http://xillybus.com/tutorials/uboot-hacking-howto-3


U-Boot的启动

尽管在大多数情况下是不必要的,但有时需要修改U-Boot自身的启动过程,特别是在早期阶段初始化自定义硬件。 本节介绍U-Boot这一部分的基础知识。

U-Boot是处理器上首先运行的东西之一,可能负责最基本的硬件初始化。 在某些平台上,当U-Boot开始运行时,处理器的RAM未配置,因此潜在的假设是U-Boot可以直接从ROM(通常是闪存)运行。

因此,启动过程的关键事件是U-Boot将自身从最初运行的位置复制到RAM中,从而运行更复杂的任务(特别是处理启动命令)。 这种自我复制被称为“重定位”(relocation)。

几乎不用说,处理器以“实模式”运行:MMU(如果有的话)关闭。 没有内存映射和保护。 U-Boot基于此发挥了一些技巧。

总的来说,U-Boot加载程序运行以下阶段:

预重定位初始化(可能直接来自闪存或其他类型的ROM)

重定位:将代码复制到RAM

重新定位后初始化(从适当的RAM)

执行命令:通过自动引导或控制台shell

将控制权传递给Linux内核(或其他目标应用程序)

请注意,在几种情况下,U-Boot从适当的RAM开始,因此不会发生实际的重定位。 在这些情况下,对重定位前和重定位后的划分变得有点人为,但这是术语。

更详细的探究

ARM体系结构的顺序可以从arch/arm/lib/crt0.S推导出来,这是绝对首先运行的代码。 这段汇编代码调用函数如下(以及一些非常低级的初始化):

    board_init_f()(在例如arch/arm/lib/board.c中定义):调用init_sequence_f函数指针数组中列出的函数(使用initcall_run_list()),该函数在此文件中列入了大量ifdef。 然后,此函数运行各种ifdef相关的init片段。

    relocate_code()

    coloured_LED_init()和red_led_on()由crt0.S直接调用。 定义这些功能允许挂钩程序在早期启动进度可见。

   board_init_r()(也可能在arch/arm/lib/board.c中定义):将初始化作为从RAM运行的“普通”程序运行。 此功能永不返回。此外,board_init_r()永远在main_loop()(在common / main.c中定义)上循环。 这实际上是命令解析器输入的命令的自动引导或执行(很可能是静默)。

在某个阶段,main_loop()中的命令将控件提供给Linux内核(或者替代加载的任何内容)。

对于那些希望在这些初始阶段添加一些代码的人:CONFIG_BOARD_EARLY_INIT_F,CONFIG_BOARD_EARLY_INIT_R,CONFIG_BOARD_LATE_INIT和CONFIG_BOARD_POSTCLK_INIT可以定义为在各个阶段请求调用board_early_init_f(),board_early_init_r(),board_late_init()和board_postclk_init()。 这些可以用作简单的钩子,用于需要任何特定平台的功能。

SPL boot

SPL(辅助程序加载器)引导功能在大多数情况下都无关紧要,但当U-Boot本身对于平台的引导顺序来说太大了的时候其提供了解决方案。 例如,Altera SoC FPGA中ARM处理器的硬件引导加载程序只能处理60KB映像。 典型的U-Boot ELF容易达到300 KB。

SPL的要点是创建一个非常小的预加载器,它可以加载“完整”的U-Boot映像。 它是从U-Boot的源代码构建的,但只有一小部分代码。 因此,当为需要SPL的平台构建U-Boot时,通常会执行两次:一次用于生成SPL,另一次用于完整的U-Boot。

SPL构建是在定义CONFIG_SPL_BUILD的情况下完成的。 只有预定位阶段在SPL构建上运行。 它所做的只是最小的初始化集,然后加载完整的U-Boot映像,并将控制传递给它。