1.2 Bootloader
Bootloader是在操作系统运行之前执行的一段小程序。通过这段小程序,可以初始化硬件设备、建立内存空间的映像表,从而建立适当的系统软、硬件环境,为最终调用操作系统内核做好准备。
对于嵌入式系统,Bootloader是基于特定硬件平台来实现的,因此,几乎不可能为所有的嵌入式系统都建立一个通用的Bootloader,不同的处理器架构有不同的Bootloader。Bootloader不但依赖于CPU的体系结构,而且依赖于嵌入式系统板级设备的配置。对于两块不同的嵌入式主板而言,即使它们使用同一种处理器,要想让运行在一块主板上的Bootloader程序也能运行在另一块主板上,一般也都需要修改Bootloader的源程序。
反过来,大部分Bootloader仍然具有很多共性,某些Bootloader也能够支持多种体系结构的嵌入式系统。例如,U-Boot就同时支持PowerPC、ARM、MIPS和X86等体系结构,支持的主板有上百种。通常,它们都能够自动从存储介质上启动,都能够引导操作系统启动,并且大部分都可以支持串口和以太网接口。
1.2.1 Bootloader的种类
嵌入式系统世界已经有各种各样的Bootloader,种类划分也有多种方式。除了按照处理器体系结构不同划分以外,还有通过功能复杂程度进行划分的。
首先区分一下“Bootloader”和“Monitor”的概念。严格来说,“Bootloader”只是引导设备并且执行主程序的固件;而“Monitor”还提供了更多的命令行接口,进行调试、读写内存、烧写Flash、配置环境变量等。“Monitor”在嵌入式系统开发过程中提供很好的调试功能,开发完成以后,就完全设置成了一个“Bootloader”。所以,习惯上把它们统称为Bootloader。
表1.4列出了Linux的开放源码引导程序及其支持的体系结构,表中给出了X86、ARM、PowerPC体系结构的常用引导程序,并且注明了每一种引导程序是不是“Monitor”。
表1.4 Linux的开放源码引导程序
1.X86
X86的工作站和服务器上一般使用LILO和GRUB。LILO曾经是Linux发行版主流的Bootloader,不过,现在几乎所有的发行版都已经使用了GRUB,GRUB比LILO有更友好的显示接口,使用配置也更加灵活方便。
在某些X86嵌入式单板机或者特殊设备上,会采用其他的Bootloader,如ROLO。这些Bootloader可以取代BIOS的功能,能够从Flash中直接引导Linux启动。现在ROLO支持的开发板已经并入U-Boot,所以U-Boot也可以支持X86平台。
2.ARM
ARM处理器的芯片提供商很多,所以每种芯片的开发板都有自己的Bootloader,使得ARM Bootloader也变得多种多样。最早有ARM720处理器开发板的固件,之后又有了armboot、StrongARM平台的BLOB,还有S3C2410处理器开发板上的Vivi等。现在armboot已经并入了U-Boot,所以U-Boot也支持ARM/XSCALE平台。U-Boot已经成为ARM平台事实上的标准Bootloader。
3.PowerPC
PowerPC平台的处理器有标准的Bootloader,就是PPCBOOT。PPCBOOT在合并armboot等之后,创建了U-Boot,成为各种体系结构开发板的通用引导程序。U-Boot仍然是PowerPC平台的主要Bootloader。
4.MIPS
MIPS公司开发的YAMON是标准的Bootloader,也有许多MIPS芯片提供商为自己的开发板写了Bootloader。现在,U-Boot也已经支持MIPS平台。
5.SH
SH平台的标准Bootloader是sh-boot,RedBoot在这种平台上也很好用。
6.M68K
M68K平台没有标准的Bootloader。RedBoot能够支持M68K系列的系统。
值得说明的是,RedBoot几乎能够支持所有的体系结构,包括MIPS、SH、M68K等。RedBoot是以eCos为基础,采用GPL许可的开源软件工程,现在由core eCos的开发人员维护,源码下载网站是http://www.ecoscentric.com/snapshots。RedBoot的文档也相当完善,有详细的使用手册RedBoot User’s Guide。
1.2.2 U-Boot编译与使用
最早,DENX软件工程中心的Wolfgang Denk基于8xxrom的源码创建了PPCBOOT工程,并且不断添加处理器的支持。后来,Sysgo Gmbh把PPCBOOT移植到ARM平台上,创建了ARMBOOT工程,然后以PPCBOOT工程和ARMBOOT工程为基础,创建了U-Boot工程。
现在,U-Boot已经能够支持PowerPC、ARM、X86、MIPS体系结构的上百种开发板,已经成为功能最多、灵活性最强并且开发最积极的开放源码Bootloader。U-Boot的源码包可以从sourceforge网站下载,还可以订阅该网站活跃的U-Boot Users邮件论坛,这个邮件论坛对于U-Boot的开发和使用都很有帮助。
- U-Boot软件包下载网站:http://sourceforge.net/project/U-Boot。
- U-Boot邮件列表网站:http://lists.sourceforge.net/lists/listinfo/U-Boot-users。
- DENX相关的网站:http://www.denx.de。
1.U-Boot编译
解压u-boot-2010.03.tar.bz2就可以得到全部U-Boot源程序。在顶层目录下有29个子目录,分别存放和管理不同的源程序。这些目录中所要存放的文件有其规则,可以分为3类。
- 与处理器体系结构或者开发板硬件直接相关。
- 一些通用的函数或者驱动程序。
- U-Boot的应用程序、工具或者文件。
表1.5列出了U-Boot顶层目录下各级目录的存放原则。
表1.5 U-Boot的源码顶层目录说明
U-Boot的源代码包含对几十种处理器、数百种开发板的支持。可是对于特定的开发板,配置编译过程只需其中部分程序。这里以S3C2410处理器为例,具体分析S3C2410处理器和开发板所依赖的程序,以及U-Boot的通用函数和工具。
U-Boot的源码是通过gcc和Makefile组织编译的。顶层目录下的Makefile可以设置开发板的定义,然后递归地调用各级子目录下的Makefile,最后把编译过的程序链接成U-Boot映像。
1)顶层目录下的Makefile
Makefile负责U-Boot整体配置编译,按照配置的顺序阅读其中关键的几行。
每一种开发板在Makefile下都需要有主板配置的定义。例如,smdk2410开发板的定义如下:
smdk2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0
执行配置U-Boot的命令make smdk2410_config,通过mkconfig脚本生成include/config.mk的配置文件,文件内容正是根据Makefile对开发板的配置生成的。
ARCH = arm CPU = arm920t BOARD = smdk2410 VENDOR = samsung SoC = s3c24x0
上面的include/config.mk文件定义了ARCH、CPU、BOARD、VENDOR、SoC这些变量,这样,硬件平台依赖的目录文件可以根据这些定义来确定。SMDK2410平台相关目录如下:
board/Samsung/smdk2410 cpu/arm920t/ cpu/arm920t/s3c24x0/ lib_arm/ include/configs/smdk2410.h
再回到顶层目录的Makefile文件开始的部分,其中,下列几行包含了这些变量的定义:
# load ARCH, BOARD, and CPU configuration include $(obj)include/config.mk export ARCH CPU BOARD VENDOR SOC
Makefile的编译选项和规则在顶层目录的config.mk文件中定义,各种体系结构通用的规则直接在这个文件中定义。通过ARCH、CPU、BOARD、VENDOR、SoC等变量为不同硬件平台定义不同选项。不同体系结构的规则分别包含在ppc_config.mk、arm_config.mk、mips_config.mk等文件中。
顶层目录的Makefile中还要定义交叉编译器,以及编译U-Boot所依赖的目标文件 ifeq (arm,$(ARCH)) CROSS_COMPILE ?=arm-none-linux-gnueabi- # 交叉编译器的前缀 endif # load other configuration include $(TOPDIR)/config.mk # U-Boot objects....order is important (i.e. start must be first) O …BJS = cpu/$(CPU)/start.o # 处理器相关的目标文件 #定义依赖的目录,每个目录下先把目标文件连接成*.a文件 LIBS = lib_generic/libgeneric.a LIBS += lib_generic/lzma/liblzma.a LIBS += lib_generic/lzo/liblzo.a LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; Then echo "board/$(VENDOR)/common/lib$(VENDOR).a"; fi) LIBS += cpu/$(CPU)/lib$(CPU).a ifdef SOC LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a endif ifeq ($(CPU),ixp) LIBS += cpu/ixp/npe/libnpe.a endif L …IBS += lib_$(ARCH)/lib$(ARCH).a
还有U-Boot镜像编译的依赖关系如下:
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND) all: $(ALL) $(obj)u-boot.hex: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ $(obj)u-boot.srec: $(obj)u-boot $(OBJCOPY) -O srec $< $@ $(obj)u-boot.bin: $(obj)u-boot $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ $(obj)u-boot.ldr: $(obj)u-boot $(CREATE_LDR_ENV) $(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS) $(obj)u-boot.ldr.hex: $(obj)u-boot.ldr $(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@ -I binary $(obj)u-boot.ldr.srec: $(obj)u-boot.ldr $(OBJCOPY) ${OBJCFLAGS} -O srec $< $@ -I binary $(obj)u-boot.img: $(obj)u-boot.bin ./tools/mkimage -A $(ARCH) -T firmware -C none \ -a $(TEXT_BASE) -e 0 \ -n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \ sed -e 's/"[ ]*$$/ for $(BOARD) board"/') \-d $< $@ $(obj)u-boot.imx: $(obj)u-boot.bin $(obj)tools/mkimage -n $(IMX_CONFIG) -T imximage \ -e $(TEXT_BASE) -d $< $@ $(obj)u-boot.kwb: $(obj)u-boot.bin $(obj)tools/mkimage -n $(KWD_CONFIG) -T kwbimage \ -a $(TEXT_BASE) -e $(TEXT_BASE) -d $< $@ $(obj)u-boot.sha1: $(obj)u-boot.bin $(obj)tools/ubsha1 $(obj)u-boot.bin $(obj)u-boot.dis: $(obj)u-boot $(OBJDUMP) -d $< > $@
Makefile默认的编译目标为all,包括u-boot.srec、u-boot.bin和System.map。u-boot.srec和u-boot.bin就是通过ld命令按照U-Boot.map地址表把目标文件组装成U-Boot的。其他Makefile内容就不再详细分析了,通过上述代码分析应该可以为读者阅读代码提供一些线索。
2)开发板配置头文件
除了编译过程Makefile以外,还要在程序中为开发板定义配置选项或者参数。这个头文件是include/configs/<board_name>.h。<board_name>用相应的BOARD定义代替。
这个头文件中主要定义了两类形式的参数。
一类形式的参数用来选择处理器、设备接口、命令、属性等,以及定义总线频率、串口波特率、Flash地址等参数。
大部分参数前缀是CONFIG_,例如:
#define CONFIG_ARM920T 1 #define CONFIG_KGDB_BAUDRATE 115200 #define CONFIG_CS8900 #define CONFIG_KGDB_BAUDRATE 115200
另一类形式的参数为:
#define PHYS_FLASH_SIZE 0x00100000 #define USE_920T_MMU 1
根据对Makefile的分析,编译分为两步。第1步是配置,如make smdk2410_config;第2步是编译,执行make就可以了。
编译完成后,可以得到U-Boot各种格式的映像文件和符号表,如表1.6所示。
表1.6 U-Boot编译生成的映像文件
U-Boot的3种映像格式都可以烧写到Flash中,但需要看加载器能否识别这些格式。一般u-boot.bin最为常用,直接按照二进制格式下载,并且按照绝对地址烧写到Flash中就可以了。U-Boot和u-boot.srec格式映像都自带定位信息。
2.U-Boot的常用命令
U-Boot上电启动后,按任意键可以退出自动启动状态,进入命令行。
U-Boot 2010.03 (Sep 25 2011 - 16:18:50) DRAM: 64 MB Flash: 2 MB NAND: 64 MiB In: serial Out: serial Err: serial Net: CS8900-0 Hit any key to stop autoboot: 1
在命令行提示符下,输入U-Boot的命令并执行。U-Boot可支持几十个常用命令,通过这些命令,可以对开发板进行调试,引导Linux内核,还可以擦写Flash完成系统部署等功能。掌握这些命令的使用,才能够顺利地进行嵌入式系统的开发。
输入help命令,可以得到当前U-Boot的所有命令列表。每一条命令后面是简单的命令说明。
U-Boot还提供了更加详细的命令帮助,通过help命令还可以查看每个命令的参数说明。由于开发过程的需要,有必要先把U-Boot命令的用法弄清楚。接下来,根据每一条命令的帮助信息,解释一下这些命令的功能和参数。
1)bootm命令
bootm命令可以引导启动存储在内存中的程序映像,这些内存包括RAM和可以永久保存的Flash。
# help bootm bootm - boot application image from memory Usage: bootm [addr [arg ...]] - boot application image stored in memory passing arguments 'arg ...'; when booting a Linux kernel, 'arg' can be the address of an initrd image Sub-commands to do part of the bootm sequence. The sub-commands must beissued in the order below (it's ok to not issue all sub-commands): start [addr [arg ...]] loados - load OS image cmdline - OS specific command line processing/setup bdt - OS specific bd_t processing prep - OS specific prep before relocation or go go - start OS
- 第1个参数addr是程序映像的地址,这个程序映像必须转换成U-Boot的格式。
- 第2个参数对于引导Linux内核有用,通常作为U-Boot格式的RAMDISK映像存储地址;也可以是传递给Linux内核的参数(默认情况下传递bootargs环境变量给内核)。
2)bootp命令
bootp命令要求DHCP服务器分配IP地址,然后通过TFTP协议下载指定的文件到内存。
# help bootp bootp - boot image via network using BOOTP/TFTP protocol ssUsage: bootp [loadAddress] [[hostIPaddr:]bootfilename]
- 第1个参数是load Address下载文件存放的内存地址。
- 第2个参数是bootfilename要下载的文件名称,这个文件应该在开发主机上准备好。
3)cmp命令
cmp命令可以比较两块内存中的内容。.b以字节为单位;.w以字为单位;.l以长字为单位。注意:cmp.b中间不能保留空格,需要连续输入命令。
# help cmp cmp - memory compare Usage: cmp [.b, .w, .l] addr1 addr2 count
- 第1个参数addr1是第一块内存的起始地址。
- 第2个参数addr2是第二块内存的起始地址。
- 第3个参数count是要比较的数目,单位是字节、字或者长字。
4)cp命令
cp命令可以在内存中复制数据块,包括对Flash的读写操作。
# help cp cp - memory copy Usage: cp [.b, .w, .l] source target count
- 第1个参数source是要复制的数据块起始地址。
- 第2个参数target是数据块要复制到的地址。这个地址如果在Flash中,那么会直接调用写Flash的函数操作。所以U-Boot写Flash就使用这个命令,当然需要先把对应Flash区域擦干净。
- 第3个参数count是要复制的数目,根据cp.b、cp.w、cp.l分别以字节、字、长字为单位。
5)crc32命令
crc32命令可以计算存储数据的校验和。
# help crc32 crc32 - checksum calculation Usage: crc32 address count [addr] - compute CRC32 checksum [save at addr]
- 第1个参数address是需要校验的数据起始地址。
- 第2个参数count是要校验的数据字节数。
- 第3个参数addr用来指定保存结果的地址。
6)echo命令
echo命令回显参数。
# help echo echo - echo args to console Usage: echo [args..] - echo args to console; \c suppresses newline
7)erase命令
erase命令可以擦除Flash。参数必须指定Flash擦除的范围。
# help erase erase - erase FLASH memory Usage: erase start end - erase FLASH from addr 'start' to addr 'end' erase start +len - erase FLASH from addr 'start' to the end of sect w/addr 'start'+'len'-1 erase N:SF[-SL] - erase sectors SF-SL in FLASH bank # N erase bank N - erase FLASH bank # N erase all - erase all FLASH banks
按照起始地址和结束地址,start必须是擦除块的起始地址;end必须是擦除末尾块的结束地址,这种方式最常用。举例说明:擦除0x20000~0x3ffff区域命令为erase 20000 3ffff。
按照组和扇区,N表示Flash的组号,SF表示擦除起始扇区号,SL表示擦除结束扇区号。另外,还可以擦除整个组,擦除组号为N的整个Flash组。擦除全部Flash只要给出一个all的参数即可。
8)nand命令
nand命令可以通过不同的参数实现对Nand Flash的擦除、读、写操作。
常见的几种命令的含义如下(具体格式见help nand)。
# help nand nand - NAND sub-system Usage: nand info - show available NAND devices nand device [dev] - show or set current device nand read - addr off|partition size nand write - addr off|partition size read/write 'size' bytes starting at offset 'off' to/from memory address 'addr', skipping bad blocks. nand erase [clean] [off size] - erase 'size' bytes from offset 'off' (entire device if not specified) nand bad - show bad blocks nand dump[.oob] off - dump page nand scrub - really clean NAND erasing bad blocks (UNSAFE) nand markbad off [...] - mark bad block(s) at offset (UNSAFE) nand biterr off - make a bit error at offset (UNSAFE)
- nand erase:擦除Nand Flash。
- nand read:读取Nand Flash,遇到flash坏块时会出错。
- nand write:写Nand Flash,nand write命令遇到flash坏块时会出错。
9)flinfo命令
flinfo命令打印全部Flash组的信息,也可以只打印其中某个组。一般嵌入式系统的Flash只有一个组。
# help flinfo flinfo - print FLASH memory information Usage: flinfo - print information for all FLASH memory banks flinfo N - print information for FLASH memory bank # N
10)go命令
go命令可以执行应用程序。
# help go go - start application at address 'addr' Usage: go addr [arg ...] - start application at address 'addr' passing 'arg' as arguments
- 第1个参数addr是要执行程序的入口地址。
- 第2个可选参数是传递给程序的参数,可以不用。
11)iminfo命令
iminfo命令可以打印程序映像的开头信息,包含了映像内容的校验(序列号、头和校验和)。
# help iminfo iminfo - print header information for application image Usage: iminfo addr [addr ...] - print header information for application image starting at address 'addr' in memory; this includes verification of the image contents (magic number, header and payload checksums)
第1个参数addr指定映像的起始地址。可选的参数是指定更多的映像地址。
12)loadb命令
loadb命令可以通过串口线下载二进制格式文件。
# help loadb loadb - load binary file over serial line (kermit mode) Usage: loadb [ off ] [ baud ] - load binary file over serial line with offset 'off' and baudrate 'baud'
13)loads命令
loads命令可以通过串口线下载S-Record格式文件。
# help loads loads - load S-Record file over serial line Usage: loads [ off ] - load S-Record file over serial line with offset 'off'
14)mw命令
mw命令可以按照字节、字、长字写内存,.b、.w、.l的用法与cp命令相同。
# help mw mw - memory write (fill) Usage: mw [.b, .w, .l] address value [count]
- 第1个参数address是要写的内存地址。
- 第2个参数value是要写的值。
- 第3个可选参数count是要写单位值的数目。
15)nfs命令
nfs命令可以使用NFS网络协议通过网络启动映像。
# help nfs nfs - boot image via network using NFS protocol Usage: nfs [loadAddress] [[hostIPaddr:]bootfilename]
16)printenv命令
printenv命令打印环境变量。可以打印全部环境变量,也可以只打印参数中列出的环境变量。
# help printenv printenv - print environment variables Usage: printenv - print values of all environment variables printenv name ... - print value of environment variable 'name'
17)protect命令
protect命令是对Flash写保护的操作,可以使能和解除写保护。
help protect protect - enable or disable FLASH write protection Usage: protect on start end - protect FLASH from addr 'start' to addr 'end' protect on start +len - protect FLASH from addr 'start' to end of sect w/addr 'start'+'len'-1 protect on N:SF[-SL] - protect sectors SF-SL in FLASH bank # N protect on bank N - protect FLASH bank # N protect on all - protect all FLASH banks protect off start end - make FLASH from addr 'start' to addr 'end' writable protect off start +len - make FLASH from addr 'start' to end of sect w/addr 'start'+'len'-1 wrtable protect off N:SF[-SL] - make sectors SF-SL writable in FLASH bank # N protect off bank N - make FLASH bank # N writable protect off all - make all FLASH banks writable
- 第1个参数on代表使能写保护;off代表解除写保护。
- 第2和3个参数是指定Flash写保护操作范围,与擦除的方式相同。
18)rarpboot命令
rarpboot命令可以使用TFTP协议通过网络启动映像,也就是把指定的文件下载到指定地址,然后执行。
# help rarpboot rarpboot - boot image via network using RARP/TFTP protocol Usage: rarpboot [loadAddress] [[hostIPaddr:]bootfilename]
- 第1个参数是loadAddress映像文件下载到的内存地址。
- 第2个参数是bootfilename要下载执行的镜像文件。
19)run命令
run命令可以执行环境变量中的命令,后面参数可以跟几个环境变量名。
# help run run - run commands in an environment variable Usage: run var [...] - run the commands in the environment variable(s) 'var'
20)setenv命令
setenv命令可以设置环境变量。
# help setenv setenv - set environment variables Usage: setenv name value ... - set environment variable 'name' to 'value ...' setenv name - delete environment variable 'name'
- 第1个参数是name环境变量的名称。
- 第2个参数是value要设置的值,如果没有第2个参数,表示删除这个环境变量。
21)sleep命令
sleep命令可以使用TFTP协议通过网络下载文件,按照二进制文件格式下载。另外,使用这个命令,必须配置好相关的环境变量,例如serverip和ipaddr。
help sleep sleep - delay execution for some time Usage: sleep N - delay execution for N seconds (N is _decimal_ !!!)
sleep命令可以延迟N秒执行,N为十进制数。
22)nm命令
nm命令可以修改内存,可以按照字节、字、长字操作。
# help nm nm - memory modify (constant address) Usage: nm [.b, .w, .l] address
参数address是要读出并且修改的内存地址。
23)tftpboot命令
tftpboot命令可以通过使用TFTP协议在网络上下载二进制格式文件。
tftpboot - boot image via network using TFTP protocol Usage: tftpboot [loadAddress] [[hostIPaddr:]bootfilename]
24)saveenv 命令
saveenv命令可以保存环境变量到存储设备。
# help saveenv saveenv - save environment variables to persistent storage Usage: saveenv
这些U-Boot命令为嵌入式系统提供了丰富的开发和调试功能。在Linux内核启动和调试过程中,都可以用到U-Boot的命令。但是一般情况下,不需要使用全部命令。比如已经支持以太网接口,可以通过tftpboot命令来下载文件,那么就没有必要使用串口下载的loadb。反过来,如果开发板需要特殊的调试功能,也可以添加新的命令。
1.2.3 U-Boot移植
U-Boot能够支持多种体系结构的处理器,支持的开发板也越来越多,因为Bootloader是完全依赖硬件平台的,所以在新电路板上需要移植U-Boot程序。
开始移植U-Boot之前,要先熟悉硬件电路板和处理器,确认U-Boot是否已经支持新开发板的处理器和I/O设备。假如U-Boot已经支持一块非常相似的电路板,那么移植的过程将非常简单。移植U-Boot工作就是添加开发板硬件相关的文件、配置选项,然后配置编译。开始移植之前,需要先分析一下U-Boot已经支持的开发板,比较出硬件配置最接近的开发板。选择的原则是,首先处理器相同,其次处理器体系结构相同,然后是以太网接口等外围接口相同。还要验证一下这个参考开发板的U-Boot,至少能够配置编译通过。
以S3C2410处理器的FS2410开发板为例,U-Boot的高版本已经支持SMDK2410开发板。我们可以基于SMDK2410移植,那么先把SMDK2410编译通过。移植U-Boot的基本步骤如下。
(1)在顶层Makefile为开发板添加新的配置选项,以使用已有的配置项目为例:
smdk2410_config : unconfig @./mkconfig $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
参考上面两行,添加下面两行:
fs2410_config : unconfig @./mkconfig $(@:_config=) arm arm920t EduKit2410 NULL s3c24x0
(2)创建一个新目录存放开发板相关的代码,并且添加新文件。
① board/fs2410/config.mk。
② board/ fs2410/flash.c。
③ board/ fs2410/EduKit2410.c。
④ board/ fs2410/Makefile。
⑤ board/ fs2410/memsetup.S。
⑥ board/ fs2410/U-Boot.lds。
(3)为开发板添加新的配置文件。可以先复制参考开发板的配置文件,再修改,例如:
$cp include/configs/smdk2410.h include/configs/fs2410.h
如果是为一颗新的CPU移植,还要创建一个新的目录存放CPU相关的代码。
(4)配置开发板。
$ make fs2410_config
(5)编译U-Boot。执行make命令,编译成功可以得到U-Boot映像。有些错误是与配置选项有关系的,通常打开某些功能选项会带来一些错误,一开始可以尽量与参考板配置相同。
(6)添加驱动或者功能选项。在能够编译通过的基础上,还要实现U-Boot的以太网接口、Flash擦写等功能。对于FS2410开发板的以太网驱动和smdk2410完全相同,所以可以直接使用。CS8900驱动程序代码包括:
drivers/cs8900.c drivers/cs8900.h
对于Flash的选择就麻烦多了,Flash芯片价格或者采购方面的因素都有影响。多数开发板大小、型号都不相同,所以还需要移植Flash的驱动。每种开发板目录下一般都有flash.c这个文件,需要根据具体的Flash类型修改。例如:
board/fs2410/flash.c
(7)调试U-Boot源代码,直到U-Boot在开发板上能够正常启动。调试的过程是很艰难的,需要借助工具,并且有些问题可能会困扰很长时间。