锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Bootloader之uBoot简介

时间:2022-12-23 18:30:00 集成电路x0p492传感器传感器中splamic单点式传感器单点式传感器sp22

本文转载:http://blog.ednchina.com/hhuwxf/1915416/message.aspx

一、Bootloader的引入

从之前的硬件实验可以看出,系统上电后,需要一个程序来初始化:关闭
WATCHDOG、改变系统时钟、初始存储控制器、将更多代码复制到中等内存等。如果能将操作系统内核(无论是本地的,比如Flash;还是从远端,
比如通过网络)复制到内存中运行,就称这段程序为Bootloader。

简单地说,Bootloader这么短的程序,它在系统上电时就开始执行,初始化硬件设备,准备好软件环境,最后调用操作系统内核。

可以增强Bootloader比如增加网络功能,从PC通过串口或网络下载文件,
烧写文件,将Flash上压缩文件解压后再运行等──这是一个更强大的功能Bootloader,也称为Monitor。事实上,用户在最终产品中
不需要这些功能,只是为了方便开发。

Bootloader在嵌入式系统中,硬件配置非常不同,即使是相
同的CPU,它的外设(例如Flash)也可能不同,所以不可能有一个Bootloader支持所有的CPU、所有电路板。甚至支持CPU架构比较多
的U-Boot,不能一拿就用(除非里面的配置和你的板子一样),需要一些移植。

二、 Bootloader的启动方式

CPU上电后,将从某个地址执行。MIPS结构的CPU会从0xBFC00000取
第一条指令,而ARM结构的CPU则从地址0x从一万开始。嵌入式单板需要存储器件ROM或Flash等待映射到这个地方
址,Bootloader将其存储在此地址的开头,以便一上电就能执行。

在开发过程中,通常需要使用各种命令Bootloader,一般通过串口连接PC和开发
板,可以在串口上输入各种命令,观察操作结果等。这对开发人员来说只是有意义的,用户在使用产品时不需要接口来控制Bootloader的。从这个观点来
看,Bootloader可分为两种操作模式(Operation Mode):

(1)启动加载(Boot loading)模式。

上电后,Bootloader操作系统从板上的固态存储设备加载到RAM在运行过程中,用户没有干预整个过程。产品发布时,Bootloader在这种模式下工作。

(2)下载(Downloading)模式。

在这种模式下,开发人员可以通过串口连接或网络连接从主机使用各种命令(Host)下载文件(如内核图像、文件系统图像),直接放入内存操作或烧入Flash类固态存储设备。

板与主机之间传输文件时,可使用串口xmodem/ymodem/zmodem协议使用简单,但速度慢;也可以通过网络使用网络tftp、nfs协议传输时,主机应打开tftp、nfs服务;还有其他方法,比如USB等。

像Blob或U-Boot等等功能强大Bootloader这两种工作模式通常同时支持
允许用户在这两种工作模式之间切换。U-Boot启动时正常启动加载模式,但会延迟几秒钟(可以设置)等待终端用户按下
任意键而将U-Boot切换到下载模式。如果在指定时间内没有用户按钮,则U-Boot继续启动Linux内核。编辑] 15.1.2 Bootloader结构及启动过程

  • 1. 概述

移植前先了解Bootloader一些通用概念有助于理解它的代码。

嵌入式Linux从软件的角度来看,系统通常可以分为四个层次:

(1)引导加载程序,包括固化在固件(firmware)中的 boot 代码(可选)和Bootloader两大部分。

有些CPU在运行Bootloader固化程序(固件,firmware),比如x86结构的CPU就是先运行BIOS硬盘的第一个分区在运行之前是固件(MBR)中的Bootloader。

大多数嵌入式系统中没有固件,Bootloader是上电后执行的第一个程序。

(2)Linux内核。

嵌入式板的定制内核和内核的启动参数。内核的启动参数可以是默认的,也可以是默认的Bootloader传递给它的。

(3)文件系统。

包括根文件系统和根文件系统Flash内存设备之上的文件系统。里面包含了Linux系统可以操作所需的应用程序、库等,如为用户提供操作Linux控制界面shell动态连接程序运行所需的程序glibc或uClibc库,等等。

(4)用户应用程序。

特定于用户的应用程序也存储在文件系统中。有时,嵌入式图形用户界面可能包含在用户应用程序和核心层之间。常用的嵌入式 GUI 有:Qtopia 和 MiniGUI 等。

显然,嵌入系统的固态存储设备有相应的分区存储,图15.一是典型的分区结构。 [[Image:]]

图15.1 嵌入式Linux典型的分区结构在系统中

“Boot
parameters一些可设置的参数存储在分区中,例如IP要传递给核心的地址、串口波特率、命令行参数等。正常启动时,Bootloader首先
运行,然后将内核复制到内存中(一些内核可以直接在固态存储设备上运行),并在内存的固定地址设置传输到内核的参数,最后运行内核。内核启动
移动后,它会挂接(mount)根文件系统(Root filesystem)启动文件系统中的应用程序。

  • 2. Bootloader的两个阶段

Bootloader启动过程的启动过程可分为单阶段(Single
Stage)、多阶段(Multi-Stage)两种。通常是多阶段的Bootloader它可以提供更复杂的功能和更好的可移植性。启动固态存储设备
动的Bootloader大多都是 2 阶段的启动过程。这可以从之前的硬件实验中很好地理解:第一阶段是通过汇编来实现的,它完成了一些依赖 CPU
系统结构的初始化,并在第二阶段调用代码。C语言通常用于第二阶段,以实现更复杂的功能,代码具有更好的可读性和可移植性。

一般来说,这两个阶段的功能可以分类如下,但这不是绝对的:

(1)Bootloader功能的第一阶段。

    • 硬件设备的初始化。
    • 为加载Bootloader代码准备的第二阶段RAM空间。
    • 拷贝Bootloader代码的第二阶段 RAM 空间中。
    • 设置好栈。
    • 跳转到第二阶段代码的C入口点。

在第一阶段进行的硬件初始化一般包括:关闭WATCHDOG、关中断,设置CPU速度和时钟频率,RAM初始化等。这些都不是必须的,比如S3C2410/S3C2440开发板使用U-Boot中,就将CPU在第二阶段设置速度和时钟频率。

甚至在第二阶段复制代码RAM空间不是必要的,对NOR Flash等待存储设备,可以直接在上面执行代码,但与此相比RAM执行效率大大降低。

(2)Bootloader功能的第二阶段。

    • 初始化本阶段要使用到的硬件设备。
    • 内存映射检测系统(memory map)。
    • 内核图像和根文件系统图像Flash上读到RAM空间中。
    • 为内核设置启动参数。
    • 调用内核。

为了方便开发,程序员和Bootloader进行交互。

所谓检测内存映射,就是确定板上使用了多少内存,它们的地址空间是什么。由于嵌入式开发,Bootloader它主要是为某种板编写的,因此可以根据板的情况直接设置,不需要考虑适用于各种情况的复杂算法。

Flash上面的内核图像可能被压缩并读取RAM之后需要解压。当然,对于具有自解压功能的核心,不需要Bootloader来解压。

复制根文件系统的图像RAM这是不必要的。这取决于根文件系统的类型,以及内核访问它的方法。

下一节将介绍内核设置的启动参数。

将内核存放在适当的位置后,直接跳到其入口点调用内核。调用内核前,应满足以下条件:

(1)CPU 设置寄存器。

    • R0=0
    • R1=机器类型ID;对于ARM结构的CPU,其机器类型ID可以参见 linux/arch/arm/tools/mach-types。
    • R2=启动参数标记表 RAM 中始基地址

(2)CPU工作模式。

    • 禁止中断(IRQs和FIQs)
    • CPU 必须 SVC 模式

(3)Cace 和 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);

  • 3. Bootloader与内核的交互

Bootloader与内核的交互是单向的,Bootloader将各类参数传给内核。由于它们不能同时运行,传递办法只有一个:Bootloader将参数放在某个约定的地方之后,再启动内核,内核启动后从这个地方获得参数。

除了约定好参数存放的地址外,还要规定参数的结构。Linux 2.4.x 
以后的内核都期望以标记列表(tagged 
list)的形式来传递启动参数。标记,就是一种数据结构;标记列表,就是挨着存放的多个标记。标记列表以标记ATAG_CORE 
开始,以标记ATAG_NONE 
结束。标记的数据结构为tag,它由一个tag_header结构和一个联合(union)组成。tag_header结构表示标记的类型及长度,比如是 
表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合(union),比如表示内存时使用tag_mem32,表示命令行时使用 
tag_cmdline。数据结构tag和tag_header定义在Linux内核源码的include/asm/setup.h头文件中:

1
2
3
4
5
6
7
8
struct  tag_header { u32 size; u32 tag; };

struct  tag { struct  tag_header hdr; union  { struct
tag_corecore; struct  tag_mem32mem; struct  tag_videotextvideotext;
struct  tag_ramdiskramdisk; struct  tag_initrdinitrd; struct
tag_serialnrserialnr; struct  tag_revisionrevision; struct
tag_videolfbvideolfb; struct  tag_cmdlinecmdline;
/* * Acorn
specific */ struct  tag_acornacorn;
/* * DC21285 specific
*/ struct  tag_memclkmemclk; } u; };

下面以设置内存标记、命令行标记为例说明参数的传递:

(1)设置标记 ATAG_CORE。

标记列表以标记 ATAG_CORE开始,假设Bootloader与内核约定的参数存放地址为0x30000100,则可以以如下代码设置标记 ATAG_CORE:

params = (struct tag *) 0x30000100; 

params->hdr.tag = ATAG_CORE; params->hdr.size = 
tag_size (tag_core);
params->u.core.flags = 0; 
params->u.core.pagesize = 0; params->u.core.rootdev = 0; 

params = tag_next (params);

其中,tag_next定义如下,它指向当前标记的末尾:

#define tag_next(t)((struct tag *)((u32 *)(t) + (t)->hdr.size))

(2)设置内存标记。

假设开发板使用的内存起始地址为0x30000000,大小为0x4000000,则内存标记可以如下设置:

params->hdr.tag = ATAG_MEM;

params->hdr.size = tag_size (tag_mem32);

params->u.mem.start = 0x30000000;

params->u.mem.size = 0x4000000;

params = tag_next (params);

(3)设置命令行标记。

命令行就是一个字符串,它被用来控制内核的一些行为。比如"root=/dev 
/mtdblock2 init=/linuxrc 
console=ttySAC0"表示根文件系统在MTD2分区上,系统启动后执行的第一个程序为/linuxrc,控制台为ttySAC0(即第一个串 
口)。

命令行可以在Bootloader中通过命令设置好,然后如下构造标记传给内核:

char *p = "root=/dev/mtdblock2 init=/linuxrc console=ttySAC0";

params->hdr.tag = ATAG_CMDLINE;

params->hdr.size = (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;

strcpy (params->u.cmdline.cmdline, p);

params = tag_next (params);

(4)设置标记ATAG_NONE。

标记列表以标记ATAG_NONE结束,如下设置:

params->hdr.tag = ATAG_NONE;

params->hdr.size = 0;

常用Bootloader介绍

现在Bootloader种类繁多,比如x86上有LILO、GRUB等。对于ARM架构的CPU,有U-Boot、Vivi等。它们各有特点,下面列出Linux的开放源代码的Bootloader及其支持的体系架构,如表15.1所示。

开放源码的Linux引导程序

Bootloader 
Monitor 
描述 
X86 
ARM 
PowerPC

LILO 
否 
Linux磁盘引导程序 
是 
否 

GRUB 
否 
GNU的LILO替代程序 
是 
否 

Loadlin 
否 
从DOS引导Linux 
是 
否 

ROLO 
否 
从ROM引导Linux而不需要BIOS 
是 
否 

Etherboot 
否 
通过以太网卡启动Linux系统的固件 
是 
否 

LinuxBIOS 
否 
完全替代BUIS的Linux引导程序 
是 
否 

BLOB 
是 
LART等硬件平台的引导程序 
否 
是 

U-Boot 
是 
通用引导程序 
是 
是 

RedBoot 
是 
基于eCos的引导程序 
是 
是 

Vivi 
是 
Mizi公司针对SAMSUNG的ARM CPU设计的引导程序 
否 
是 

对于本书使用的S3C2410/S3C2440开发板,U-Boot和Vivi是两个好选 
择。Vivi是Mizi公司针对SAMSUNG的ARM架构CPU专门设计的,基本上可以直接使用,命令简单方便。不过其初始版本只支持串口下载,速度较 
慢。在网上出现了各种改进版本:支持网络功能、USB功能、烧写YAFFS文件系统映像等。U-Boot则支持大多CPU,可以烧写EXT2、JFFS2 
文件系统映像,支持串口下载、网络下载,并提供了大量的命令。相对于Vivi,它的使用更复杂,但是可以用来更方便地调试程序。

2 U-Boot分析与移植

2.1 U-Boot工程简介

U-Boot,全称为Universal Boot 
Loader,即通用Bootloader,是遵循GPL条款的开放源代码项目。其前身是由德国DENX软件工程中心的Wolfgang 
Denk基于8xxROM的源码创建的PPCBOOT工程。后来整理代码结构使得非常容易增加其他类型的开发板、其他架构的CPU(原来只支持 
PowerPC);增加更多的功能,比如启动Linux、下载S-Record格式的文件、通过网络启动、通过PCMCIA/CompactFLash 
/ATA disk/SCSI等方式启动。增加ARM架构CPU及其他更多CPU的支持后,改名为U-Boot。

它的名字“通用”有两层含义:可以引导多种操作系统、支持多种架构的CPU。它支持如下操作 
系统:Linux、NetBSD、 
VxWorks、QNX、RTEMS、ARTOS、LynxOS等,支持如下架构的CPU:PowerPC、MIPS、x86、ARM、NIOS、 
XScale等。

U-Boot有如下特性:

  • 开放源码;
  • 支持多种嵌入式操作系统内核,如Linux、NetBSD、VxWorks、QNX、RTEMS、ARTOS、LynxOS;
  • 支持多个处理器系列,如PowerPC、ARM、x86、MIPS、XScale;
  • 较高的可靠性和稳定性;
  • 高度灵活的功能设置,适合U-Boot调试、操作系统不同引导要求、产品发布等;
  • 丰富的设备驱动源码,如串口、以太网、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、键盘等;
  • 较为丰富的开发调试文档与强大的网络技术支持;
  • 支持NFS挂载、RAMDISK(压缩或非压缩)形式的根文件系统
  • 支持NFS挂载、从FLASH中引导压缩或非压缩系统内核;
  • 可灵活设置、传递多个关键参数给操作系统,适合系统在不同开发阶段的调试要求与产品发布,尤对Linux支持最为强劲;
  • 支持目标板环境变量多种存储方式,如FLASH、NVRAM、EEPROM;
  • CRC32校验,可校验FLASH中内核、RAMDISK镜像文件是否完好;
  • 上电自检功能:SDRAM、FLASH大小自动检测;SDRAM故障检测;CPU型号;
  • 特殊功能:XIP内核引导;

可以从http://sourceforge.net/projects/u-boot获得U-Boot的最新版本,如果使用过程中碰到问题或是发现Bug,可以通过邮件列表网站http://lists.sourceforge.net/lists/listinfo/u-boot-users/获得帮助。

最新的更新代码地址http://www.denx.de/wiki/U-Boot/WebHome

2.2 U-Boot源码结构

本书在u-boot-1.1.6的基础上进行分析和移植,从sourceforge网站下载u-boot-1.1.6.tar.bz2后解压即得到全部源码。U-Boot源码目录结构比较简单、独立,目录结构也比较浅,很容易全部掌握。

u-boot-1.1.6根目录下共有26个子目录,可以分为4类:

(1)平台相关的或开发板相关的。

(2)通用的函数。

(3)通用的设备驱动程序。

(4)U-Boot工具、示例程序、文档。

先将这26个目录的功能与作用如表15.2所示。

表2 U-Boot顶层目录说明

目录 
特性 
解释说明

board 
开发板相关 
对应不同配置的电路板(即使CPU相同),比如smdk2410、sbc2410x

cpu 
平台相关 
对应不同的CPU,比如arm920t、arm925t、i386等;在它们的子目录下仍可以进一步细分,比如arm920t下就有at91rm9200、s3c24x0

lib_i386类似 
某一架构下通用的文件

include 
通用的函数 
头文件和开发板配置文件,开发板的配置文件都放在include/configs目录下,U-Boot没有make menuconfig类似的莱单来进行可视化配置,需要手动地修改配置文件中的宏定义

lib_generic 
通用的库函数,比如printf等

common 
通用的函数,多是对下一层驱动程序的进一步封装

disk 
通用的设备驱动程序 
硬盘接口程序

drivers 
各类具体设备的驱动程序,基本上可以通用,它们通过宏从外面引入平台/开发板相关的函数

dtt 
数字温度测量器或者传感器的驱动

fs 
文件系统

nand_spl 
U-Boot一般从ROM、NOR Flash等设备启动,现在开始支持从NAND Flash启动,但是支持的CPU种类还不多

net 
各种网络协议

post 
上电自检程序

rtc 
实时时钟的驱动

doc 
文档 
开发、使用文档

examples 
示例程序 
一些测试程序,可以使用U-Boot下载后运行

tools 
工具 
制作S-Record、U-Boot格式映像的工具,比如mkimage

U-Boot中各目录间也是有层次结构的,虽然这种分法不是绝对的,但是在移植过程中可以提供一些指导意义,如图2所示。

2 U-Boot顶层目录的层次结构

比如common/cmd_nand.c文件提供了操作NAND 
Flash的各种命令,这些命令通过调用drivers/nand/nand_base.c中的擦除、读写函数来实现。这些函数针对NAND 
Flash的共性作了一些封装,将平台/开发板相关的代码用宏或外部函数来代替。而这些宏与外部函数,如果与平台相关,就要在下一层次的cpu 
/xxx(xxx表示某型号的CPU)中实现;如果与开发板相关,就要在下一层次的board/xxx目录(xxx表示某款开发板)中实现。本书移植的 
U-Boot,就是在cpu/arm920t/s3c24x0目录下增加了一个nand_flash.c文件来实现这些函数。

以增加烧写yaffs文件系统映像的功能为例──就是在common目录下的 
cmd_nand.c中增加命令,比如nand 
write.yaffs:这个命令要调用drivers/nand/nand_util.c中的相应函数,针对yaffs文件系统的特点依次调用擦除、烧 
写函数。而这些函数依赖于drivers/nand/nand_base.c、cpu/arm920t/s3c24x0/nand_flash.c文件中 
的相关函数。

目前u-boot-1.1.6支持10种架构──根目录下有10个类似lib_i386的目 
录、31个型号(类型)的CPU──cpu目录下有31个子目录,214种开发板──board目录下有214个子目录,很容易从中找到与自己的板子相似 
的配置,在上面稍作修改即可使用。

2.3 U-Boot的配置、编译、连接过程

1. U-Boot初体验

u-boot-1.1.6中有几千个文件,要想了解对于某款开发板,使用哪些文件、哪个文件首先执行、可执行文件占用内存的情况,最好的方法就是阅读它的Makefile。

根据顶层Readme文件的说明,可以知道如果要使用开发板board/,就先执行“make _config”命令进行配置,然后执行“make all”,就可以生成如下3个文件:

  • u-boot.bin:二进制可执行文件,它就是可以直接烧入ROM、NOR Flash的文件。
  • u-boot:ELF格式的可执行文件
  • u-boot.srec:Motorola S-Record格式的可执行文件

对于S3C2410的开发板,执行“make smdk2410_config”、“make all”后生成的u-boot.bin可以烧入NOR Flash中运行。启动后可以看到串口输出一些信息后进入控制界面,等待用户的输入。

对于S3C2440的开发板,烧入上面生成的u-boot.bin,串口无输出,需要修改代码。

在修改代码之前,先看看上面两个命令“make smdk2410_config”、“make all”做了什么事情,以了解程序的流程,知道要修改哪些文件。

另外,编译U-Boot成功后,还会在它的tools子目录下生成一些工具,比如mkimage等。将它们复制到/usr/local/bin目录下,以后就可以直接使用它们了,比如编译内核时,会使用mkimage来生成U-Boot格式的内核映像文件uImage。

2. U-Boot的配置过程

在顶层Makefile中可以看到如下代码:

SRCTREE:= $(CURDIR)

……

MKCONFIG:= $(SRCTREE)/mkconfig

……

smdk2410_config:unconfig

@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

假定我们在u-boot-1.1.6的根目录下编译,则其中的MKCONFIG就是根目录下 
的mkconfig文件。$(@:_config=)的结果就是将“smdk2410_config”中的“_config”去掉,结果为 
“smdk2410”。所以“make smdk2410_config”实际上就是执行如下命令:

./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

再来看看mkconfig的作用,在mkconfig文件开头第6行给出了它的用法:

06 # Parameters: Target Architecture CPU Board [VENDOR] [SOC]

这里解释一下概念,对于S3C2410、S3C2440,它们被称为SoC(System 
on Chip),上面除CPU外,还集成了包括UART、USB控制器、NAND 
Flash控制器等等设备(称为片内外设)。S3C2410/S3C2440中的CPU为arm920t。

以下,分步骤分析mkconfig的作用:

(1)确定开发板名称BOARD_NAME。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
11 APPEND=no# Default: Create new  config file
12 BOARD_NAME= "" # Name to print in make output
13
14 while  [ $# -gt 0 ] ; do
15 case  "$1"  in
16 --) shift ; break  ;;
17 -a) shift ; APPEND=yes ;;
18 -n) shift ; BOARD_NAME= "${1%%_config}"  ; shift ;;
19 *) break  ;;
20 esac
21 done
22
23 [ "${BOARD_NAME}"  ] || BOARD_NAME= "$1"

对于“./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0”命令,其中没有“--”、“-a”、“-n”等符号,所以第14~22行没做任何事情。第11、12行两个变量仍维持原来的值。

执行完第23行后,BOARD_NAME的值等于第1个参数,即“smdk2410”。

(2)创建到平台/开发板相关的头文件的链接。

略过mkconfig文件中的一些没有起作用的行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
30 #
31 # Create link to architecture specific headers
32 #
33 if  [ "$SRCTREE"  != "$OBJTREE"  ] ; then
……
45 else
46 cd ./include
47 rm -f asm
48 ln -s asm-$2 asm
49 fi
50

第33行判断源代码目录和目标文件目录是否一样,可以选择在其他目录下编译U-Boot,这可以令源代码目录保持干净,可以同时使用不同的配置进行编译。不过本书直接在源代码目录下编译的,第33行的条件不满足,将执行else分支的代码。

第46~48行进入include目录,删除asm文件(这是上一次配置时建立的链接文件),然后再次建立asm文件,并令它链接向asm-$2目录,即asm-arm。

继续往下看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
51 rm -f asm-$2/arch
52
53 if  [ -z "$6"  -o "$6"  = "NULL"  ] ; then
54 ln -s ${LNPREFIX}arch-$3 asm-$2/arch
55 else
56 ln -s ${LNPREFIX}arch-$6 asm-$2/arch
57 fi
58
59 if  [ "$2"  = "arm"  ] ; then
60 rm -f asm-$2/proc
61 ln -s ${LNPREFIX}proc-armv asm-$2/proc
62 fi
63

第51行删除asm-$2/arch目录,即asm-arm/arch。

对于“./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0”命令,$6为“s3c24x0”,不为空,也不是“NULL”,所以第53行的条件不满足,将执行else分支。

第56行中,LNPREFIX为空,所以这个命令实际上就是:ln -s arch-$6 asm-$2/arch,即:ln -s arch-s3c24x0 asm-arm/arch。

第60、61行重新建立asm-arm/proc文件,并让它链接向proc-armv目录。

(3)创建顶层Makefile包含的文件include/config.mk。

对于“./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0”命令,上面几行代码创建的config.mk文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
64 #
65 # Create include file for  Make
66 #
67 echo "ARCH = $2"  > config.mk
68 echo "CPU = $3"  >> config.mk
69 echo "BOARD = $4"  >> config.mk
70
71 [ "$5"  ] && [ "$5"  != "NULL"  ] && echo "VENDOR = $5"  >> config.mk
72
73 [ "$6"  ] && [ "$6"  != "NULL"  ] && echo "SOC = $6"  >> config.mk
74

ARCH = arm

CPU = arm920t

BOARD = smdk2410

SOC = s3c24x0

(4)创建开发板相关的头文件include/config.h。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
75 #
76 # Create board specific header file
77 #
78 if  [ "$APPEND"  = "yes"  ]# Append to existing config file
79 then
80 echo >> config.h
81 else
82 > config.h# Create new  config file
83 fi
84 echo "/* Automatically generated - do not edit */"  >>config.h
85 echo "#include "  >>config.h
86

前面说过,APPEND维持原值“no”,所以config.h被重新建立,它的内容如下:

/* Automatically generated - do not edit */

#include "

现在总结一下,配置命令“make 
smdk2410_config”,实际的作用就是执行“./mkconfig smdk2410 arm arm920t smdk2410 
NULL s3c24x0”命令。假设执行“./mkconfig $1 $2 $3 $4 $5 $6”命令,则将产生如下结果:

(1)开发板名称BOARD_NAME等于$1;

(2)创建到平台/开发板相关的头文件的链接:

ln -s asm-$2 asm

ln -s arch-$6 asm-$2/arch

ln -s proc-armv asm-$2/proc# 如果$2不是arm的话,此行没有

(3) 创建顶层Makefile包含的文件include/config.mk。

ARCH = $2

CPU = $3

BOARD = $4

VENDOR = $5# $5为空,或者是NULL的话,此行没有

SOC = $6# $6为空,或者是NULL的话,此行没有

(4)创建开发板相关的头文件include/config.h。

/* Automatically generated - do not edit */

#include "

从这4个结果可以知道,如果要在board目录下新建一个开发 
的目录,则在include/config目录下也要建立一个文件.h,里 
面存放的就是开发板的配置信息。

U-Boot还没有类似Linux一样的可视化配置界面(比如使用make menuconfig来配置),要手动修改配置文件include/config/.h来裁减、设置U-Boot。

配置文件中有两类宏:

(1)一类是选项(Options),前缀为“CONFIG_”,它们用于选择CPU、SOC、开发板类型,设置系统时钟、选择设备驱动等。比如:

#define CONFIG_ARM920T1/* This is an ARM920T Core*/

#defineCONFIG_S3C24101/* in a SAMSUNG S3C2410 SoC */

#define CONFIG_SMDK24101/* on a SAMSUNG SMDK2410 Board */

#define CONFIG_SYS_CLK_FREQ12000000/* the SMDK2410 has 12MHz input clock */

#define CONFIG_DRIVER_CS89001/* we have a CS8900 on-board */

(2)另一类是参数(Setting),前缀为“CFG_”,它们用于设置malloc缓冲池的大小、U-Boot的提示符、U-Boot下载文件时的默认加载地址、Flash的起始地址等。比如:

#define CFG_MALLOC_LEN(CFG_ENV_SIZE + 128*1024)

#defineCFG_PROMPT"100ASK> "/* Monitor Command Prompt*/

#defineCFG_LOAD_ADDR0x33000000/* default load address*/

#define PHYS_FLASH_10x00000000 /* Flash Bank #1 */

从下面的编译、连接过程可知,U-Boot中几乎每个文件都被编译和连接,但是这些文件是否包含有效的代码,则由宏开关来设置。比如对于网卡驱动drivers/cs8900.c,它的格式为:

#include /* 将包含配置文件include/config/.h */

……

#ifdef CONFIG_DRIVER_CS8900

/* 实际的代码 */

……

#endif/* CONFIG_DRIVER_CS8900 */

如果定义了宏CONFIG_DRIVER_CS8900,则文件中包含有效的代码;否则,文件被注释为空。

可以这样粗糙地认为,“CONFIG_”除了设置一些参数外,主要用来设置U-Boot的功能、选择使用文件中的哪一部分;而“CFG_”用来设置更细节的参数。

3. U-Boot的编译、连接过程

配置完后,执行“make all”即可编译,从Makefile中可以了解U-Boot使用了哪些文件、哪个文件首先执行、可执行文件占用内存的情况。

先确定用到哪些文件,下面只摘取Makefile中与arm相关的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
117 include $(OBJTREE)/include/config.mk
118 exportARCH CPU BOARD VENDOR SOC
119
……
127 ifeq ($(ARCH),arm)
128 CROSS_COMPILE = arm-linux-
129 endif
……
163 # load other configuration
164 include $(TOPDIR)/config.mk
165

第117、164行用于包含其他的config.mk文件,第117行所要包含文件的就是在 
上面的配置过程中制作出来的include/config.mk文件,其中定义了ARCH、CPU、BOARD、SOC等4个变量的值为arm、 
arm920t、smdk2410、s3c24x0。

第164行包含顶层目录的config.mk文件,它根据上面4个变量的值确定了编译器、编译选项等。其中对我们理解编译过程有帮助的是BOARDDIR、LDFLAGS的值,config.mk中:

1
2
3
4
5
6
7
8
9
10
11
12
13
88 BOARDDIR = $(BOARD)
……
91 sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk# include board specific rules
……
143 LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章