uboot跨平台

1       简介

u-boot跨平台是为了最大化的共用代码,提高开发效率,节约开发时间。

2       目录结构

|--u-boot                       (根目录)

|-- arch                                         (平台目录)

|    |--arm                (arm架构)

|    |--(config.mk)          (指明基于arm的编译器路径)

|    |   |--cpu            (CPU种类目录,如armv7, arm926)

|    |    |   |--armv7     (CPU下的板级目录,和CPU有关的操作)

|    |   |    |    |--sunxi (bsp层函数,以及自定义操作)

|    |   |    |    |--(config.lds) (armv7的链接脚本,所有armv7都用它)

|    |   |--lib             (基于函数,如字符串/除法等操作,初始化主函数)

|    |   |--include         (所有头文件操作)

|    |   |    |--asm

|    |   |    |    |--arch-sum(自定义IC头文件,CPU相关)

|--board                    (板级目录)

|    |--mtk           (自定义方案目录)

|    |   |--a9       (方案下的分支)

|--common                 (所有命令存放目录,以及shell)

|--disk                     (分区格式操作目录)

|--doc                      (文档目录)

|--drivers                   (驱动)

|    |--dma                (dma)

|    |--i2c                 (i2c)

|    |--net                 (net)

|    |--others…             (以及其它驱动模块)

|--fs                       (文件系统目录)

|    |--ext2

|    |--fat

|    |--other fs…

|--include                   (头文件目录)

|    |--asm

|    |   |--arch-sum    (arch/arn/include/arch-sum的软链接)

|    |--others

|--lib                       (C库,标准算法,crc32)

|--nanx_sum                (nand目录)

|--net                      (协议层目录,dns, nfs, tftp)

|--…                       (其它自定义目录)

|--(boards.cfg)                (IC或者方案的配置添加)

|--(Makefile)                 (顶层makefile)

|--(config.mk)                (顶层配置,用宏定义路径,参数)

|--(other file…)               (其它文件)

 


3       新平台支持

3.1     编译方式

通常情况下,u-boot的完整编译命令是

make distclean   //清除掉所有的编译信息,包括.o文件

make xxx_config //选择一个平台进行编译,平台信息下面介绍

make –j8        //开始编译,-jx表示使用x个线程,可以没有-jx,数字选择从1-16,数字越大编译越快

uboot中添加一个新平台的支持,主要做好以下几方面的工作。

3.2     编译支持

打开根目录下,board.cfg文件,按照如下的格式

Target  ARCH  CPU  Board_name  Vendor  SoC  Options

在原有的数据下添加新的支持。中间使用一个或者多个空格或者tab隔开。

下面说明其中每个符号的含义,以及需要完成的工作。

3.2.1  Target

目标名称,用于指定编译时候的名称

比如,如果添加sum,则编译时候就使用make sum_config;如果添加a9,则编译时候使用make a9_config。

此外,它也决定了所使用的编译时的总头文件,这个头文件位于include/configs目录下,文件名即为$(Target).h。比如sum.h,a9.h。

其中存放的是编译宏,决定了哪些代码需要编译,哪些不需要;或者定义了部分变量,比如目前用到的MMU_BASE,即在这个头文件中定义。

3.2.2  ARCH

CPU架构,比如arm,mips,等等。对于我们的IC,就直接使用arm。

举例来说,当使用arm的时候,则编译器会自动到目录arch/arm目录下寻找相关内容。

我们需要记住这个添加的ARCH。

3.2.3  CPU

通常这里表示指令集分类,比如我们用到的armv7,以前用过的arm926ejs,等等。编译的时候,会使用这里的参数来区分使用不同指令集。

同时,它和ARCH一起决定了我们添加的代码,应该存放在arch/arm/cpu/armv7这个目录下。

CPU也需要记住,我们将在$(ARCH)/cpu/$(CPU)/目录下添加自己的代码

3.2.4  SOC

指基于同一指令集的不同IC,即不同的bsp。

以armv7为例,这个目录下存放了相同指令集,但是不同IC的bsp,习惯上一颗IC使用一个目录,则目录的名字就是SOC,目录存放在arch/arm/cpu/armv7目录下。编译的时候会根据SOC来寻找指定的目录。

除了代码外,还需要完成自己的底层makefile。

3.2.5  Vendor

这是一个目录的名词,位于board目录下,说明了顶层板级方案的添加,用来指明同一颗CPU下的不同方案。习惯上,Vendor根目录下没有代码,而是有下一层目录。具体的内容包括在下级目录中。

3.2.6  Board_name

这就是Vendor目录下的名词,包括了具体的方案内容。不同的IC可以使用相同的Vendor/Board_name的内容。

3.2.7  Options

说明部分,没有实际含义。可以直接留空不写。

3.3     跨平台

跨平台的要点主要有:

1. 合适的bsp接口,可以保持在bsp独立的情况下,驱动层保持不变

2. 不同平台独有的文件,可以在makefile中使用编译宏来区分

3. 文件中如果不同的平台需要使用不同的功能,比如调用不同函数,也可以在文件中使用编译宏来区分

具体如何实现,请参见下一节的举例说明。

3.4     举例说明

为了添加对于a9的支持,需要完成以下的工作。

3.4.1  完成编译支持

在board.cfg文件中新起一行,添加以下内容

a9  arm  armv7  sunxi  allwinner     a9

3.4.2  添加bsp

在arch/arm/cpu/armv7目录下添加a9目录,在目录中添加bsp层支持。

3.4.3  添加bsp头文件

在arch/arm/include/asm/目录下添加arch-a9目录,添加bsp的全部头文件。

3.4.4  添加全局头文件

在include/config目录中,添加文件a9.h。文件内容可以参照目前有的完成。

3.4.5  添加板级代码

在board目录下,添加mtk目录,然后在其中添加sum目录,在里面完成自己需要的板级配置函数。

一般,板级配置函数中,包括了获取内存大小。

对于我们的方案而已,由于采用了外部配置脚本的方式,因此这里的函数很少,主要的有板级初始化(有u-boot初始化调用),其中可以添加自己的内容,比如扫描分区信息,等等。

由于这个目录下全部是逻辑操作,和硬件无关,因此所有方案/IC可以使用同样的代码。

3.4.6  添加方案独有代码

如果代码可以给所有方案所使用,就不需要在文件对应的makefile中加入任何宏定义。否则,对于方案独有的代码,可以按照如下的格式,修改makefile。

比如,有一个C文件,名为a9.c,需要在配置a9的时候进行编译,否则不应该编译,则makefile中应该如下写法

COBJS-$(CONFIG_A9) += a9.o

它表示,如果在全局头文件(a9.h)中定义了宏CONFIG_A9,则编译这个文件,否则不编译。

如果一个文件,无论如果都应该编译,则应该写作

COBJS-y += a9.o

通常,我们都应该在方案的全局头文件中定义方案的宏,比如CONFIG_A9,CONFIG_A8

bsp是为驱动服务的,有必要做到只有bsp做出修改的情况下,保持驱动不变。因此,驱动编写前应该考虑好结构,抽出恰当的接口,使所有bsp提供相同的函数。

如果驱动变化很大,就需要用前面所介绍的编译宏来决定不同的代码是否参与编译。

3.4.8  细分功能

如果一个文件中,某个函数,甚至函数中的某个部分,只有某个平台才能涌动,可以代码中用宏加以区分,比如

#ifdef  A9_CONFIG

printf(“a9\n”);

#else

printf (“not a9\n”);

#endif

但是不推荐这么做,因为可能导致后面维护的时候,漏掉了这些用宏加以区分的代码。

建议的做法是,把不同的地方做成函数调用,然后不同的IC维护各种的代码,最终在makefile中形成统一。

4       其它细节

4.1     编译器路径

u-boot编译的时候,编译器只能使用绝对路径,不能使用相对路径。这是因为编译的时候,将进入到每个目录下之后,再调用编译器。这时候,由于目录层次的变化,最初设定的编译器路径相对关系将失效。

解决方案:

u-boot编译脚本中定义了一个全局宏CURDIR,其实就是`pwd,可以取得u-boot的绝对路径。

由于已知编译器和u-boot的相对路径关系,假设二者处于同一个目录下,其中编译器目录为gcc,则可以在文件arch/arm/cpu/config.mk中,修改如下的代码

原为   CROSS_COMPILE ?= gcc-

修改为 CROSS_COMPILE ?= $(CURDIR)/../gcc/bin/gcc-

由于顶层编译的时候,CURDIR已经转换成了绝对路径,所以这里使用的也是绝对路径,因此编译的时候能够找到编译器。

如果修改为

原为   CROSS_COMPILE ?= gcc-

修改为 CROSS_COMPILE ?= ./../gcc/bin/gcc-

那么,在编译顶层目录的时候正确,但编译下一级目录的时候将报错。这就是因为到了下一级目录,编译器相对关系变成了

CROSS_COMPILE ?= ./../../gcc/bin/gcc-

但是makefile认为没有变化,因此会出现找不到编译器的错误。

4.2     链接脚本参数

原始的u-boot中,编译脚本中的.o都是绝对路径,但是这对于跨平台来说是不合适的。

比如,有必要在uboot的头部添加一个数据用于校验uboot的正确性,原来的做法是

OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

     . = 0x00000000;

. = ALIGN(4);

.head   :

{

    arch/arm/cpu/armv7/a9/spare_head.o  (.data)

}

它表示,把arch/arm/cpu/armv7/a9/spare_head.o中的数据段放到head段中。

如前文所述,a9表示了一颗IC的bsp,但是不同的IC有不同的bsp目录,比如a9,a8,等等,总不能一颗IC就自带一个链接脚本。

实际上,合适的做法是

OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm","elf32-littlearm")

OUTPUT_ARCH(arm)

ENTRY(_start)

SECTIONS

{

     . = 0x00000000;

. = ALIGN(4);

.head   :

{

    SOCDIR/spare_head.o  (.data)

}

SOCDIR是一个路径,它的含义是

SOCDIR=arch/$(ARCH)/cpu /$(SOC)

这样,当选择不同的IC时,也能使用相同的代码结构了。

当然,真正使用的链接脚本中是不能够带宏的。实际上,uboot编译的时候,会根据基本的链接脚本,利用shell语法在uboot根目录下重新生成,这个过程中会执行宏展开,这样,原始定义的宏就能够被识别了。

为了让编译器能够识别这样的符号,需要在在调用的时候,把宏的含义传递给shell。

生成链接脚本的makefile语句是

$(obj)u-boot.lds: $(LDSCRIPT)

          $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >$@

传递的参数就在LDPPFLAGS中。

目前传递的参数如下所示。

$(obj)u-boot.lds: $(LDSCRIPT)

LDPPFLAGS += \

     -include $(TOPDIR)/include/u-boot/u-boot.lds.h \

     -DCPUDIR=$(CPUDIR) \

     -DSOCDIR=$(SOCDIR) \

     $(shell $(LD) --version | \

       sed -ne 's/GNU ld version \([0-9][0-9]*\)\.\([0-9][0-9]*\).*/-DLD_MAJOR=\1 -DLD_MINOR=\2/p')

其中,-DSOCDIR表示了SOC所代表的路径。这样,重新生成uboot.lds的时候,就会自动展开成arch/arm/cpu/armv7/a9了。

 

 

你可能感兴趣的:(uboot跨平台)