u-boot分析之编译体验
初识uboot
uboot是BootLoader的一种,用以启动内核。
uboot打补丁、配置与编译
uboot官方是有提供源程序的,我们在上面进行修改或者添加代码的话需要打补丁,步骤如下:
1 解压缩uboot
tar xjf u-boot-1.1.6.tar.bz2
2 进入解压后的文件夹
cd u-boot-1.1.6/
3 打补丁
patch -p1 <…/u-boot-1.1.6_jz2440.patch
4 配置
make 100ask24x0_config
5.编译
make
diff -urN u-boot-1.1.6/board/100ask24x0/100ask24x0.c u-boot-1.1.6_jz2440/board/100ask24x0/100ask24x0.c
--- u-boot-1.1.6/board/100ask24x0/100ask24x0.c 1970-01-01 07:00:00.000000000 +0700
+++ u-boot-1.1.6_jz2440/board/100ask24x0/100ask24x0.c 2010-11-26 12:54:37.034090906 +0800
—代表要打的位置,我们当前已经在u-boot-1.1.6文件夹下了,所以需要忽略第一个参数,用参数-p?进行忽略。
如:-p1表示忽略第一个“/”前的参数。
.patch文件的讲解
“-”表示修改前的代码,“+”表示修改后的代码,如下列代码所示。
diff -urN u-boot-1.1.6/common/cmd_load.c u-boot-1.1.6_jz2440/common/cmd_load.c
--- u-boot-1.1.6/common/cmd_load.c 2006-11-02 22:15:01.000000000 +0800
+++ u-boot-1.1.6_jz2440/common/cmd_load.c 2010-11-26 12:54:38.142063808 +0800
@@ -34,6 +34,8 @@
DECLARE_GLOBAL_DATA_PTR;
#if (CONFIG_COMMANDS & CFG_CMD_LOADB)
+/* support xmodem, www.100ask.net */
+static ulong load_serial_xmodem (ulong offset);
static ulong load_serial_ymodem (ulong offset);
#endif
其中
@@ -34,6 +34,8 @@
表示修改前的代码中的34行,总共6行,修改后的代码中的34行,总共8行。
另外一个例子,下列代码中,-代表原本的代码,+代表之后的修改的代码。
int do_load_serial (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
- ulong offset = 0;
- ulong addr;
- int i;
- char *env_echo;
- int rcode = 0;
-#ifdef CFG_LOADS_BAUD_CHANGE
- int load_baudrate, current_baudrate;
+ ulong offset = 0;
+ ulong addr;
+ int i;
+ char *env_echo;
+ int rcode = 0;
+#ifdef CFG_LOADS_BAUD_CHANGE
+ int load_baudrate, current_baudrate;
- load_baudrate = current_baudrate = gd->baudrate;
+ load_baudrate = current_baudrate = gd->baudrate;
#endif
u-boot分析之Makefile结构分析
分为两部分讲解:配置分析、编译分析
make 100ask24x0_config配置分析
在uboot的Makefile文件中可以看到有这么一条语句:
100ask24x0_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm920t 100ask24x0 NULL s3c24x0
执行了make 100ask24x0_config之后想当于执行了上面的第二行语句。
我们再找到MKCONFIG的定义:
MKCONFIG := $(SRCTREE)/mkconfig
可知,MKCONFIG就是根目录下的mkconfig文件。$(@:_config=) 的结果就是将“100ask24x0_config”的“_config”去掉(因为后面是=“空格”,相当于替换了),结果为“100ask24x0”,所以“make 100ask24x0_config”实际上执行的就是如下命令:
mkconfig 100ask24x0 arm arm920t 100ask24x0 NULL s3c24x0
打开mkconfig文件进行分析:
#!/bin/sh -e
# Script to create header files and links to configure
# U-Boot for a specific board.
#
# Parameters: Target Architecture CPU Board [VENDOR] [SOC]
#
# (C) 2002-2006 DENX Software Engineering, Wolfgang Denk <wd@denx.de>
#
APPEND=no # Default: Create new config file
BOARD_NAME="" # Name to print in make output
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
echo "Configuring for ${BOARD_NAME} board..."
#
# Create link to architecture specific headers
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include
rm -f asm
ln -s asm-$2 asm
fi
rm -f asm-$2/arch
if [ -z "$6" -o "$6" = "NULL" ] ; then
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
#
# Create include file for Make
#
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
#
# Create board specific header file
#
if [ "$APPEND" = "yes" ] # Append to existing config file
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
exit 0
分析如下:
1.下列代码块是对传输的参数进行分析,有无“–”“-a”“-n”等
while [ $# -gt 0 ] ; do
case "$1" in
--) shift ; break ;;
-a) shift ; APPEND=yes ;;
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
*) break ;;
esac
done
2.“BOARD_NAME”是否定义,如果定义了,则BOARD_NAME="$1"不会执行。
[ "${BOARD_NAME}" ] || BOARD_NAME="$1"
$1表示第一个参数:
mkconfig | 100ask24x0 | … | s3c24x0 |
---|---|---|---|
$0 | $1 | $… | $6 |
执行完此句话后,BOARD_NAME = 100ask24x0
3.$#参数的个数,小于4个会退出,大于6个也会退出
[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1
4.打印这句话
echo "Configuring for ${BOARD_NAME} board..."
#
# Create link to architecture specific headers
#
if [ "$SRCTREE" != "$OBJTREE" ] ; then
mkdir -p ${OBJTREE}/include
mkdir -p ${OBJTREE}/include2
cd ${OBJTREE}/include2
rm -f asm
ln -s ${SRCTREE}/include/asm-$2 asm
LNPREFIX="../../include2/asm/"
cd ../include
rm -rf asm-$2
rm -f asm
mkdir asm-$2
ln -s asm-$2 asm
else
cd ./include
rm -f asm
ln -s asm-$2 asm
fi
“SRCTREE”会等于“OBJTREE”,因为在Makefile中有语句使其相等了。
OBJTREE := $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE := $(CURDIR)
TOPDIR := $(SRCTREE)
LNDIR := $(OBJTREE)
故而会执行下面的else
ln -s asm-$2 asm
相当于会建立一个链接文件,让asm指向asm-arm。此处目的是方便代码书写。例子:
#include <asm/type.h>
//可能会有#include <asm-i386/type.h>
//或者其他#include <asm-arm/type.h>
我们不想把代码改来改去,配置时临时生成,让asm指向某个架构
6.删除
rm -f asm-$2/arch
7.如果第六个参数为空或者等于null的话执行第一条,这里不满足,执行的是第二条。
if [ -z "$6" -o "$6" = "NULL" ] ; then
ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi
此句也是建立链接文件,LNPREFIX没有定义相当于空的,最后执行为:
ln -s arch-s3c24x0 asm-arm/arch
8.下一句同理。
if [ "$2" = "arm" ] ; then
rm -f asm-$2/proc
ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi
9.建立一个config.mk(>),并添加内容(>>)
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk
[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk
[]括起来的才是条件,后面的是执行的语句。
10.“APPEND”==NO,创建一个config.h文件,然后添加内容
if [ "$APPEND" = "yes" ] # Append to existing config file
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
exit 0
make编译分析
在makefile中有这边一段代码
OBJS = cpu/$(CPU)/start.o
...
...
LIBS = lib_generic/libgeneric.a
LIBS += board/$(BOARDDIR)/lib$(BOARD).a
LIBS += cpu/$(CPU)/lib$(CPU).a
...
...
LIBS 把所有涉及的文件编译好后打包成一个.a的库
在makefile中有这边一段代码
ALL = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O 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.dis: $(obj)u-boot
$(OBJDUMP) -d $< > $@
$(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
$(OBJS):
echo $(OBJS)
$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))
$(LIBS):
$(MAKE) -C $(dir $(subst $(obj),,$@))
...
...
我们执行make的时候,如果不指定目标,则会生成第一个目标。我们最终想生成u-boot.bin,u-boot.bin依赖于下面的这一句话$(obj)u-boot.bin: $(obj)u-boot
这里的$(obj)u-boot
是elf格式的。
$(obj)u-boot
依赖于下面的语句:
$(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
我们执行make之后查看打印的结果,如下图所示:
通过上面我们知道了以下知识:
1.第一个文件是 cpu/arm920t/start.S
2.链接地址由以下决定:board/100ask24x0/u-boot.lds和0x33F80000
0x33F80000要修改的话在config.mk中修改。