从实践中学嵌入式Linux应用程序开发
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

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在开发板上能够正常启动。调试的过程是很艰难的,需要借助工具,并且有些问题可能会困扰很长时间。