翻译原文来自:https://rocketboards.org/foswiki/Documentation/EmbeddedLinuxBeginnerSGuide

 

在preloader加载完时, SOC 底层(时钟、引脚和SDRAM等)的初始化工作已经完成,在这个状态下就可以启动bootloader了。U-Boot是嵌入式Linux设计中最流行的bootloader(当然也许你偶尔也会看到一个供应商为他们的 SOC 使用其他的bootloader)。但总的来说,大多数人还是会选择u-Boot。

 

U-Boot的唯一目的是让系统启动并运行到可以启动Linux内核的状态。就如同preloader唯一目的是使系统初始化到足以运行bootloader的状态一样。 boot flow中的每个阶段可以只用准备好运行下一阶段所需的硬件。这样就可以得到更精简、更快速的boot flow。

 

在我们这个案例中,U-Boot将需要至少初始化SD/MMC硬件,因为我们的内核将放在SD卡上。U-Boot包含初始化SD/MMC硬件以及读取SD卡上的FAT分区所需的驱动程序。U-Boot还负责向内核传递一系列名为"引导参数"的参数,这些参数都是一些用于告诉内核如何启动的底层细节(比如有关于打印调试消息的串行端口的配置、在哪里找到根文件系统等)。

 

 U-Boot还执行另一项对Altera SoC器件非常重要的任务:对FPGA结构进行编程。这不是一个内置到主线U-Boot代码的功能,所以我们将使用经过修改的Altera版U-Boot。虽然您可以从prelaoder程序 或编写 Linux软件来编程FPGA,但推荐的方法是在Linux内核开始之前让U-Boot加载bitstream并对FPGA进行编程。这样,当内核启动时,它可以在运行任何可能依赖于FPG硬件电路的应用程序之前初始化该电路(自定义逻辑)所需的驱动程序。这将在本节后面介绍。

 

也就是说,U-Boot并不能神奇地知道所有东西在SD卡上的具体位置,以及它应该以什么顺序加载这些东西。为了解决这个问题,U-Buot在启动时提供了一个shell,您可以输入命令来告诉它该做什么。 U-Boot网站载有完整的命令列表 (Altera在其U-Boot版本中也添加了一些自定义命令,如下所示)。其实就像一个普通的Linux shell,这个shell是可编写脚本的。稍后在本节中,我们将编写一个脚本,该脚本告诉U-Boot去给FPGA编程,加载设备树和内核,并开始运行内核。

 

获取源码

现在我们将获得U-Boot的源代码,然后配置它,编译它。首先,cd回到由preloader创建的software目录中(假设你在spl_bps子目录中)。

 

cd ..

 

 我们将使用ARMv7指令集的标准Linaro GCC工具链来编译U-Boot(以及编译后面要介绍的的根文件系统中的软件),因此我们需要下载并解压它。

wget http://releases.linaro.org/14.09/components/toolchain/binaries/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux.tar.xz
tar -xvf gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux.tar.xz

 

接下来,我们需要通过设置交叉编译环境变量来告诉U-Boot(和其他makefile文件)使用这个工具链进行编译。如果你曾经关闭你的终端,那么再打开时记得再设置这个环境变量。

export CROSS_COMPILE=$PWD/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/arm-linux-gnueabihf-

 

既然工具链已经建立,我们需要从 GitHub下载 Altera版本的U-Boot

git clone https://github.com/altera-opensource/u-boot-socfpga.git
cd u-boot-socfpga

 

Altera为Quartus、SoCEDS和ARM Development Studio的每个版本都验证并发布了黄金系统参考设计(GSRD)用户手册(包括U-Boot、内核和GHRD)。也就是说,我们将使用这些经过回归测试的版本,而不是使用来自主分支(也称为“development”或“possibly buggy”的分支)的前沿代码。运行以下命令以查看按日期或Quartus/SoCEDS版本分别标记的所有版本的列表。

 

git tag -l rel*
git tag -l ACDS*

 如果您不熟悉Git版本控制系统是如何工作的,现在是时候停下手头的工作,去阅读Git网站上的教程了。这将引导您了解有关标记、分支以及如何下载源代码的所有信息。许多开源项目(包括U-Boot和Linux内核)使用git为他们的C代码做版本控制,知道如何浏览github仓库是一项尤为重要的技能。

 

 一旦你阅读了git并知道你在做什么,运行以下命令切换到包含2015年9月发布的Altera U-Boot的分支。如果你读到这篇文章的时候有其他更新的版本,我鼓励你尝试一下新版本,尽管我不能保证本指南中的以下步骤仍然有效。

git checkout rel_socfpga_v2013.01.01_15.09.01_pr

 

如果您想对这个分支进行更改并提交它们,则需要创建一个新的分支。

 

编译U-Boot

在编译之前,先清除U-Boot文件夹。

 

make mrproper

 

理解默认配置

在这次编译中,我们将使用默认的Cyclone V配置文件。在编译U-Boot之前,让我们先简单看看这个默认配置文件。使用以下命令在vim中查看配置文件,或者使用您喜欢的文本编辑器也行。

 

vim include/configs/socfpga_cyclone5.h

 

查看该配置文件可以看到其内容很少,除了指定U-Boot中的命令提示符为“SOCFPGA_CYCLONE5 #”之外,它没有做太多事情。从头文件includes中可以看出,这个文件包含了另一个名为“socfpga_common.h”的文件,该文件里面包含有大多数的配置。

 

在您喜欢的文本编辑器中打开“include/configs/socfpga_common.h”。花点时间浏览这个文件,看看它为您配置的所有设置。如果你要设计自己的电路板,你可能需要改变其中的一些设置。特别有用的是在第154行设置为' 5 '的CONFIG_BOOTDELAY选项。这意味着U-Boot在继续启动之前将等待5秒钟,让您有5秒钟时间选择是否按下按钮停止自动启动过程。如果是到了最终生产的系统上,将会把这个选项设置为0,以便U-Boot立即运行引导脚本而无需等待。

 

另一个重要内容是在第181行定义的环境变量。这些环境变量将在我们的引导脚本中使用,为从SD卡加载数据和引导内核提供一些快捷方式。我们将在引导脚本部分更详细地讨论这些环境变量。

 

最后,从大约第349行开始,有许多U-Boot支持的驱动程序的配置选项。您可以随意浏览这些内容,感受一下U-Boot的功能。

 

编译U-Boot

现在您已经确切地知道了默认配置在做什么(当您的设备启动失败时,了解这一点非常重要),接下来配置U-Boot以使用该配置,然后进行编译。

make socfpga_cyclone5_config
make

 

这时会出现一个新的U-Boot image文件叫做“U-Boot.img”,它应该位于u-boot-socfpga目录中。我们将会把它放在SD卡上,在本指南的后面部分,将会演示如何从SD卡boot这个文件。

编写引导脚本

如前所述,引导脚本是一个U-Boot命令列表,它将在设备启动时自动运行(您不需要按任何键进入命令shell)。该脚本将对FPGA进行编程,加载设备树,加载内核,并使用一组引导参数运行内核。

 

在software路径下创建名为“boot.script”的新文件。拷贝如下内容到文件:

echo -- Programming FPGA --
fatload mmc 0:1 $fpgadata soc_system.rbf;
fpga load 0 $fpgadata $filesize;
run bridge_enable_handoff;

echo -- Setting Env Variables --
setenv fdtimage soc_system.dtb;
setenv mmcroot /dev/mmcblk0p2;
setenv mmcload 'mmc rescan;${mmcloadcmd} mmc 0:${mmcloadpart} ${loadaddr} ${bootimage};${mmcloadcmd} mmc 0:${mmcloadpart} ${fdtaddr} ${fdtimage};';
setenv mmcboot 'setenv bootargs console=ttyS0,115200 root=${mmcroot} rw rootwait; bootz ${loadaddr} - ${fdtaddr}';

run mmcload;
run mmcboot;

 

理解引导脚本

 该脚本首先从SD卡(也称为“mmc”)上的第一个分区加载FPGA的配置比特流文件(.rbf),然后将其放置在RAM中的地址$ fpdata(如果您回顾配置头文件可以看到该值相当于0x2000000)。然后对FPGA进行编程,并使用一些Altera特定的命令/脚本启用HPS-to-FPGA桥。

 

 接下来,它设置设备树二进制文件的名称(将在下一节中创建并解释),并设置一个变量,该变量将告诉内核在哪里找到根文件系统(也将在下一节中解释)。这个脚本中有趣的部分与我们创建的两个“快捷”命令有关:mmload和mmcboot。

 

 第一个命令将从SD卡加载内核镜像和设备树二进制文件,并将其放入RAM的预定地址(同样是已经在配置文件中定义了)中。为此,它使用fatload命令(别名为${mmcloadcmd}变量)获取文件所在的设备(第0个SD卡)和分区(第一个分区,将是我们的FAT分区),然后分别将这些文件加载到${loadaddr}和${fdtaddr}中(同样,这些地址也在配置文件中预先定义了)。

 

有关此脚本中使用的“mmc”和“fatload”命令的更多信息,请使用内置在U-Boot shell中的帮助系统(在后面的教程中我们会启动它)。例如,要学习fatload的确切语法,在U-Boot shell中输入以下命令:

help fatload

第二个命令实际上启动了Linux内核。它首先为内核设置"引导参数"。这些参数告诉内核应该如何启动。有些设置在编译时暂没有配置,但以后可能需要。在我们的例子中,我们所做的就是设置调试控制台作为第一个串行设备(在Atlas板上连接到一个USB-to-UAT转换器芯片),并告诉内核在哪里找到根文件系统。文件系统将被放置在/dev/mmcblk0p2上,也就是第一张SD卡上的第二个分区。当我们创建SD卡时,我们将在这里创建根文件系统。

 

“rw”参数指定我们的根文件系统应该以读/写方式挂载,而“rootwwait”告诉内核等待SD卡初始化并对内核可见,然后再继续。所有这些内核参数和更多参数的描述都可以在我们稍后下载的内核源代码中的Documentation/kernel-parameters.txt文件中找到(或者您可以通过前面的链接在GitHub上查看)。

 

设置好引导参数后,将使用bootz命令启动内核。该命令会去获取这些地址(设备树二进制文件的地址和要传入的压缩内核映像的地址)。一旦这个命令运行,控制权就会转移到内核了。

 

编译引导脚本

U-Boot要求将引导脚本编译成二进制文件。运行以下命令编译引导脚本:

mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "Boot Script Name" -d boot.script u-boot.scr

 

如上面的命令所述我们需要将这个文件命名为“u-boot.scr”,这样U-Boot才可以找到它。这其实也是配置文件内容的一部分。在默认配置文件设置的环境变量的大列表中,其中一个是“scriptfile=u-boot.scr”。因为我们使用的是默认值,所以我们需要遵循这个名称。

 

这样U-Boot就编译好了可以运行了!继续下一节了解设备树。

资源

 

如果您正在创建自己的自定义板,我强烈建议您阅读本文,了解如何设置U-Boot以初始化板上的关键硬件。