所以要想对一款开发板进行uboot移植,首先在board目录下新建一个以开发板名字命名的目录(例如:
smdk2410 这样一个目录);之后在include/configs目录下建立一个以开发板名字命名的头文件(例如:
smdk2410.h),里面存放的是开发板的配置信息。
1.总体结构
平台依赖:board、cpu、lib_arm主要实现arm平台通用的函数
通用:common通用的多功能函数实现,如环境、命令、控制台相关的函数实现;include头文件和开发板配置文件,所有开发板的头文件都在configs目录下;lib_generic通用库函数的实现;net网络协议、drivers include/config.mk内容 ARCH = arm CPU = arm920t BOARD = smdk2410
SOC = s3c24x0
include/config.mk文件定义了ARCH、CPU、BOARD、SOC这些变量。这样硬件平台依赖的目录文件可以根据这些定义来确定。SMDK2410平台相关目录如下 • board/smdk2410/ • cpu/arm920t/
• cpu/arm920t/s3c24x0/ • lib_arm/ • include/asm-arm/
• include/configs/smdk2410.h
include/config.h内容
#include \"config/smdk2410.h\" 2.主要涉及的目录:
cpu/arm920t/start.o
board/smdk2410/libsmdk2410.a cpu/arm920t/libarm920t.a cpu/arm920t/s3c24x0/lib$(SOC).a lib_arm/board.c
include/config/smdk2410.h目标板的配置头文件,主要定义两类变量。
include/s3c24x0.h 定义s3x24x0芯片的各个特殊功能寄存器(SFR)的地址。
cpu/arm920t/start.s 在flash中执行的引导代码,也就是bootloader中的stage1,负责初始化硬件环境,把u-boot从flash加载到RAM中去,然后跳到lib_arm/board.c中的start_armboot中去执行。
lib_arm/board.c u-boot的初始化流程,尤其是u-boot用到的全局数据结构gd,bd的初始化,以及设备和控制台的初始化。 board/smdk2410/flash.c
3.对一个开发板进行uboot移植首先要了解的是: 内存地址,flash型号,外围芯片
4.UBOOT启动流程主要在两个文件中完成 第一阶段:cpu/arm920t/start.s 第二阶段:lib_arm/board.c
5.board/smdk2410/boot.lds
重点看include/configs/smdk2410.h ,cpu/arm920t/start.s这两个文件
*********************************************************************************************************************** 1.顶层Makefile
1.)首先定义HOSTARCH、HOSTOS两个变量并输出,HOSTARCH为主机架构类型如i386\\arm等,HOSTOS为主机当前操作系统。export HSOTARCH HOSTOS
2.)接下来定义uboot.bin的输出路径,目标文件存放目录BUILD_DIR可以通过make O=dir指定,如果没有指定则设定为源码顶层目录。export TOPDIR SRCTREE OBJTREE 最终这三个变量都指向了CURDIR。
3.)定义MKCONFIG变量并指向顶层目录中的mkconfig脚本配置文件,首先涉及到mkconfig文件。并输出变量export MKCONFIG。
./mkconfig文件为指定的板子配置uboot,主要有3个作用:a.生成链接指向特定架构的头文件。b.生成/include/config.mk/配置文件。c.生成、包含头文件/include/config.h
4.)包含头文件/include/config.h,加载ARCH CPU BOARD VENDOR SOC变量并输出 export ARCH
CPU BOARD VENDOR SOC。 指定交叉编译器: ifeq ($(ARCH),arm)
CROSS_COMPILE = arm-linux-
5.)加载其他设置,包含顶层目录下的config.mk脚本文件,这个文件主要有3个作用: a. 定义了交叉编译器
b.定义了编译选项,并通过/board/smdk2410/u-boot.lds文件定义了链接时,各个目标文件是如何组织的 ,并定义了起始地址TEXT_BASE(TEXT_BASE的具体值在/board/smdk2410/config.mk文件中) c.定义了编译规则 6.)uboot目标书写顺序
start.o必须放在目标文件的第一位,因为uboot执行的第一段代码就是start.S 7.) 编译uboot需要的库文件
根据所生成的include/config.mk文件定义的几个变量ARCH, CPU, BOARD, SOC,我们可以确定硬件平 台依赖的目录文件。
8.) 最终要生成的各种镜像文件u-boot.hex、u-boot.srec、u-boot.bin、System.map、u-boot.img 9.) 查看unconfig, 很明显,它所做的工作就是清除上次生成的include/config.h和include/config.mk,
以及开发板目录下的一些临时配置文件。
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \\ $(obj)board*/config.tmp \\
$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep 10.)在顶层Makefile中添加开发的配置选项,如:
xxx2410_config: unconfig
@./mkconfig $(@:_config=) arm arm920t xxx2410 null s3c2410
执行 make xxx2410_config命令,首先执行unconfig这个动作,之后调用顶层目录下的mkconfig配置脚本文件,传递给它6个参数在include目录下生成config.mk和config.h文件。 最后总结,顶层Makefile主要任务组织整个u-boot工程的编译,概况分为以下几个步骤: a.首先通过执行make xxx2410_config传入 $(@:_config=), ARCH, CPU, BOARD, VENDOR, SOC参数给
mkconfig脚本文件。
b. mkconfig脚本接收到传递过来的参数后,将include头文件夹相应的头文件连接好,生成config.mk、config.h
c. 然后执行make分别调用各个子目录的makefile文件,以生成所有的obj文件 (包括start.o)和obj库文件*.a
d. 最后通过连接器把所有的目标文件链接起来生成uboot镜像。不同的镜像都是调用相应的工具经由elf镜像间接 或者直接生成的。
*******************************************************************************************************
2.通过调用顶层mkconfig脚本文件生成的include目录下的config.mk、config.h文件内容 ./include/config.mk内容如下: ARCH = arm CPU = arm920t BOARD = xxx2410 SOC = s3c24x0
./include/config.h内容如下:
#include ********************************************************************************************************************* 3.通过调用顶层config.mk a. 定义了交叉编译器
b.定义了编译选项,并通过/board/smdk2410/u-boot.lds文件定义了链接时,各个目标文件是如何组织的 ,并定义了起始地址TEXT_BASE(TEXT_BASE的具体值在/board/smdk2410/config.mk文件中) c.定义了编译规则
********************************************************************************************************************* 4.start.S分析
在分析start.S之前,得先研究uboot的链接脚本u-boot.lds。位于./board/xxx2410/u-boot.lds。
OUTPUT_FORMAT(\"elf32-littlearm\
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS {
. = 0x00000000;
. = ALIGN(4); .text : {
cpu/arm920t/start.o (.text) *(.text) }
. = ALIGN(4);
.rodata : { *(.rodata) }
. = ALIGN(4); .data : { *(.data) }
. = ALIGN(4); .got : { *(.got) }
. = .;
__u_boot_cmd_start = .; .u_boot_cmd : { *(.u_boot_cmd) } __u_boot_cmd_end = .;
. = ALIGN(4); __bss_start = .; .bss : { *(.bss) }
_end = .; }
*******************分析start.S*******************************
#include #include #include .globl _start
_start: b start_code //复位向量,此时会跳转到reset处执行程序
ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq
_undefined_instruction: .word undefined_instruction _software_interrupt: .word software_interrupt _prefetch_abort: .word prefetch_abort _data_abort: .word data_abort _not_used: .word not_used _irq: .word irq _fiq: .word fiq
.balignl 16,0xdeadbeef
// .align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。.balign的作用同.align。
// .align {alignment} {,fill} {,max} // 其中:alignment用于指定对齐方式,可能的取值为2的次幂,缺省为4。fill是填充内容,缺省用0填充。max是填充字节 数最大值,假如填充字节数超过max, // 就不进行对齐,例如: // .align 4
// TEXT_BASE在开发板相关的目录中的config.mk中定义, 他定义了 // 代码在运行时所在的地址, 用_TEXT_BASE保存这个地址,代码如下: _TEXT_BASE:
.word TEXT_BASE
// 声明 _armboot_start 并用 _start 来进行初始化,在board/u-boot.lds中定义。 .globl _armboot_start _armboot_start: .word _start
.globl _bss_start _bss_start:
.word __bss_start
.globl _bss_end _bss_end:
.word _end
#ifdef CONFIG_USE_IRQ //如果定义了CONFIG_USE_IRQ就执行下面的代码
.globl IRQ_STACK_START IRQ_STACK_START:
.word 0x0badc0de
.globl FIQ_STACK_START FIQ_STACK_START: .word 0x0badc0de #endif
**********************
start_code:
mrs r0,cpsr //把当前程序状态寄存器中的数据拷贝给r0
bic r0,r0,#0x1f // r0和0x1f (00011111)的反码进行位与,目的是给r0的后5位清零
orr r0,r0,#0xd3 // r0和0xd3 (11010011)的反码进行位或,目的是设置r0的后5位
msr cpsr,r0 //把当前r0中保存的CPU的状态拷贝给cps
bl coloured_LED_init bl red_LED_on
**********************