首先介绍一下bootloader
在嵌入式操作系统中,BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。
在arm处理器中各软件部分的分布:
(从0x00000000开始)bootloader --> boot parameters(传给内核的参数) ----> kernel ------->图形用户界面(可选) --------> root filesystem
通用bootloader的启动的两个阶段:
第一阶段:
硬件初始化:关看门狗、关中断、设置时钟、RAM初始化
为二阶段准备RAM空间
复制二阶段代码到RAM
设置好堆栈
跳到二阶段C入口处
第二阶段:
初始化需要的硬件:串口 ......
检测内存映射
将内核映像、根文件系统映像从FLASH上读到RAM中(可能需解压)
设置内核启动参数
调用内核:调用内核前的条件
(1)cpu寄存器的设置
R0 = 0
R1 = 机器类型ID
R2 = 启动参数列表在RAM中的基址
(2)cpu工作模式
禁止IRQ FIQ
CPU为SUV模式
(3)cache mmu的设置
MMU关闭
指令cache可开可关
数据cache必须关闭
下面进入常见的uboot分析
先看uboot源码目录层次结构
lib_generic common include ————————>通用函数
post net fs disk _______________驱动
nand_spl rtc drivers
board cpu lib_xxx —————————底板 平台
例如:通用函数(common/cmd_nand.c) 调用的是驱动层(drivers/nand/nand_base.c),再调用底板或平台层(cpu/xxx board/xxx)
uboot的编译: 根据配置修改好文件如在顶层makefile中添加开发板目标,在include/configs/下创建board_name.h,然后执行如下命令
#make makefile中目标名(开发板名_config) ; 对应的板子做文件配置
#make all ; 对源程序进行编译
对编译步骤的具体分析:
第一步make board_name_config
所有的编译都是从顶层makefile
决定的
在makefile中查找 board_name_config 目标(下面以smdk2410为分析对象)
MKCONFIG := $(SRCTREE)/mkconfig
export MKCONFIG
......
smdk2410_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0
MKCONFIG就是根目录下的mkconfig文件, $(@:_config=)是将目标中的_config去掉,所以实际上是执行如下命令
./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0
执行上边这命令就会去执行mkconfig脚本文件,所以下面分析mkconfig文件内容
6 # Parameters: Target Architecture CPU Board [VENDOR] [SOC] ;给出了mkconfig的使用方法
;下面确定开发板的名称
23 [ "${BOARD_NAME}" ] || BOARD_NAME="$1"
;下面是创建到平台/开发板的相关头文件的链接
46 cd ./include
47 rm -f asm
48 ln -s asm-$2 asm
51 rm -f asm-$2/arch
56 ln -s ${LNPREFIX}arch-$6 asm-$2/arch ;LNPREFIX为空
60 rm -f asm-$2/proc
61 ln -s ${LNPREFIX}proc-armv asm-$2/proc
;下面是创建顶层makefile包含的文件incude/config.mk
#
# Create include file for Make
#
67 echo "ARCH = $2" > config.mk
68 echo "CPU = $3" >> config.mk
69 echo "BOARD = $4" >> config.mk
71 [ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
73 [ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
;下面是创建开发板相关的头文件
#
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file ;APPEND为 no
then
echo >> config.h
else
> config.h # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h
;所以创建了config.h文件,内容如下:
"/* Automatically generated - do not edit */" >>config.h
"#include <configs/$1.h>" >>config.h ;此处包含了incude/configs/board_name.h
至此make board_name_config命令执行完
下面看一下如何通过incude/configs/board_name.h配置文件来裁剪 uboot
这个头文件中主要定义了两类宏
一类是选项,前缀是CONFIG_,用来选择处理器、设备接口、命令、属性等,主要用来 决定是否编译某些文件或者函数。
另一类是参数,前缀是CFG_,用来定义总线频率、串口波特率、Flash地址等参数。这些常数参量主要用来支持通用目录中的代码,定义板子资源参数。
这两类宏定义对u-boot的移植性非常关键,比如drive/CS8900.c,对cs8900而言,很多操作都是通用的,但不是所有的板子上面都有这个芯片,即使有它在内存中映射的基地址也是平台相关的。所以对于smdk2410板,在
smdk2410.h中定义了
#define CONFIG_DRIVER_CS8900 1 /* we have a CS8900 on-board */
#define CS8900_BASE 0x19000300 /*IO mode base address*/
CONFIG_DRIVER_CS8900的定义使得cs8900.c可以被编译(当然还得定义CFG_CMD_NET才行),因为cs8900.c中在函数定义的前面就有编译条件判断:#ifdef CONFIG_DRIVER_CS8900 如果这个选项没有定义,整 cs8900.c就
不会被编译了。
而常数参量CS8900_BASE则用在cs8900.h头文件中定义各个功能寄存器的地址。u-boot的CS8900工作在IO模式下,只要给定IO寄存器在内存中映射的基地址,其余代码就与平台无关了。
u-boot的命令也是通过目标板的配置头文件来配置的,比如要添加ping命令,就必须添加CFG_CMD_NET和CFG_CMD_PING才行。不然common/cmd_net.c就不会被编译了。
第二个命令make all
117 include $(OBJTREE)/include/config.mk ;包含文件,确定CPU,ARCH,BOARD,SOC等参数
164 include $(TOPDIR)/config.mk ;包含顶层config.mk
看看顶层config.mk中有用的信息
88 BOARDDIR = $(BOARD)
91 sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk # include board specific rules
在board/$(BOARDDIR)/config.mk 中有TEXT_BASE的定义
;下面指定变量的值
169 OBJS = cpu/$(CPU)/start.o
LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a
endif
LIBS += lib_$(ARCH)/lib$(ARCH).a
LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a \
fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
LIBS += net/libnet.a
LIBS += disk/libdisk.a
LIBS += rtc/librtc.a
LIBS += dtt/libdtt.a
LIBS += drivers/libdrivers.a
LIBS += drivers/nand/libnand.a
LIBS += drivers/nand_legacy/libnand_legacy.a
ifeq ($(CPU),mpc83xx)
LIBS += drivers/qe/qe.a
endif
LIBS += drivers/sk98lin/libsk98lin.a
LIBS += post/libpost.a post/cpu/libcpu.a
LIBS += common/libcommon.a
LIBS += $(BOARDLIBS)
;下面指定要编译的内容
268 $(OBJS):
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
271 $(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
;下面是链接的规则
262 $(obj)u-boot: depend version $(SUBDIRS) $(OBJS) $(LIBS) $(LDSCRIPT)
UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e 's/.*\(__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
--start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
-Map u-boot.map -o u-boot
参考文档:http://blog.csdn.net/liukun321/article/details/5680504
《嵌入式linux应用完全手册 韦东山》