U-Boot编程
介绍
为了使U-Boot适应自定义的硬件,通常需要对U-Boot进行一些细微的更改。例如,支持特定于电路板的功能或添加一些例程,这些例程向终端用户发出信号,表明设备确实已经启动,并且在。启动的过程发生时发生了一些事情。
这篇简短的教程主要介绍用于ARM的U-Boot,但是在其它架构上上使用的技术是相似的,而且通常是完全相同的。假设读者熟悉命令级的U-Boot用法以及编译和部署。
建议首先读取项目根目录中的自述文件。它包括以下主题:
•源文件树结构
•配置的含义定义
•U-Boot构建说明。
•如何将U-Boot移植到新平台
•对Hush shell简介
•如何构建Linux映像(mkimage)
•常见环境变量列表
•“Hello world”示例及其使用方法
boards.cfg包含支持的板的列表。也值得一看。
本教程是针对U-Boot版本v2013.07编写的,但是这些原则适用于各种版本。
明智的黑客
当遇到大量的软件资源时,最直接的本能是寻找第一个地方注入一个小的黑客,并对必要的功能进行硬编码。这不仅会在将来导致令人生畏的重新破解和重新编译,而且也没有必要:U-Boot实际上是为了方便添加自定义功能而设计的。
可以将可能的修改分为三类:
•修改U-Boot的初始化过程,以便尽早设置定制板的特定硬件
•通过添加或修改低级驱动程序,增加对特定硬件的支持
•扩展命令界面以支持所需功能,可能作为新硬件的前端
在电路板的初始化程序中添加几行黑客代码来执行特定的操作可能很诱人。这很有可能有效,但正如刚刚提到的,硬编码也有其缺点。如果硬件的设置可以推迟到命令执行阶段,那么编写一个小型的自定义驱动程序和命令支持就更加优雅,而且可重用。
本教程分为三个部分:关于U-Boot的概述(本部分)、关于如何添加功能的实际操作说明(第二部分)以及一些有关U-Boot启动过程的背景知识,用于那些需要很早初始化某些东西的人使用(第三部分)。
软件组织
Linux内核黑客会对U-Boot感到相对舒服,因为很多编码风格和组织方式都受到Linux内核的启发。然而,这种结构更简单,但灵活性更低。在驱动程序和用户前端之间没有中间层。
例如,要获取GPIO pin的值,只需在代码中的任何位置使用GPIO的pin编号调用gpio_get_value(gpio)。没有地方可以将多个GPIO驱动程序编译到系统中:只能启用一个定义此函数的源文件进行编译,否则链接将失败。当然,如果在某个地方使用了gpio_get_value(),则必须编译这个源文件。
因此,U-Boot中的“硬件驱动程序”只是一段代码,它实现了一组链接到全局名称空间的函数。对于一个需要紧凑的实用程序来说,这是有意义的:在任何不使用的东西中都没有编译,而且大多数时候都涉及一组固定的硬件,每种类型最多只能有一个实例。
当然,一个驱动可能依赖另一个驱动。例如,SOFT_I2C驱动程序依赖于连接到I2C设备的两个GPIO引脚。这些引脚是使用GPIO的API函数访问的。任何其他软件也可以访问GPIO API (希望不是相同的引脚)。
make XXX_config的幕后
任何建立过U-Boot的人都会输入类似
$ make zynq_zed_config
在编译项目之前,许多人还发现有一个/include/configs/目录,在这个目录中可以找到相应的文件,例如zynq_zed.h,它的内容如下(顶部的GPLv2标头未显示在这里):
#ifndef __CONFIG_ZYNQ_ZED_H
#define __CONFIG_ZYNQ_ZED_H
#define PHYS_SDRAM_1_SIZE (512 * 1024 * 1024)
#define CONFIG_ZYNQ_SERIAL_UART1
#define CONFIG_ZYNQ_GEM0
#define CONFIG_ZYNQ_GEM_PHY_ADDR0 0