学习笔记--- U-BOOT 的配置与编译分析

首先进入uboot  根目录,首先配置,然后才能进行编译。

所以先执行make smdk2410_config进行配置:

在makefile里面可以找到这条指令对应执行的内容为:

smdk2410_config	:	unconfig
	@$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 NULL s3c24x0

这个分为7个部分,第一个部分是执行的shell脚本文件, 其他的都是需要传入这个脚本文件的参数。
那么执行的脚本文件是什么?在makefile里面查看MKCONFIG变量:

OBJTREE		:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))
SRCTREE		:= $(CURDIR)
TOPDIR		:= $(SRCTREE)
LNDIR		:= $(OBJTREE)
export	TOPDIR SRCTREE OBJTREE

MKCONFIG	:= $(SRCTREE)/mkconfig
这个变量就是根目录里面的mkconfig脚本文件。

然后这个脚本文件的第一个参数是

$(@:_config=)

表示过滤smdk2410_config的_config部分,所以参数为 smdk2410

所以执行make smdk2410_config实际上就是执行了下面的这条指令:

mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

后面的参数在脚本文件里面的表示方法是:

mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

   $0             $1         $2    $3         $4          $5       $6

也就是说$1-$6分别表示第一个到第六个参数

再来看下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

14行while循环,这一句判断 $1 ,case 条件是判断$1 是不是-a -n ,所以都不符合,循环无效,往下走;

23行[ "${BOARD_NAME}" ] || BOARD_NAME="$1"  表示如果BOARD_NAME有值那么就是本身,如果不是就执行BOARD_NAME="$1" ,也就表示BOARD_NAME=“smdk2410”;

25行:

[ $# -lt 4 ] && exit 1
[ $# -gt 6 ] && exit 1

其中$# 表示参数个数,这里表示如果参数个数小于4个退出,大于6个也退出。这里我们是6个参数,不会退出,继续执行;

然后在终端打印一行这个信息:

echo "Configuring for ${BOARD_NAME} board..." 实际上是 "Configuring for smdk2410 board..."

33行if [ "$SRCTREE" != "$OBJTREE" ] ; then   这一行条件不满足,两个变量的值在makefile前面就定义了。这里执行到46行:

cd ./include            
rm -f asm
ln -s asm-$2 asm

        rm -f asm-$2/arch

进入include目录,删除之前建立的旧asm,再建立一个新的链接文件asm,链接到asm-$2 也就是asm-arm,然后删除asm-arm里面的arch;

53行如果$6为空或者=NULL的话就执行ln -s ${LNPREFIX}arch-$3 asm-$2/arch,这里显然条件不满足,所以执行ln -s ${LNPREFIX}arch-$6 asm-$2/arch创建一个新的arch文件,LNPREFIX未定义,所以为空,所以这句话相当于执行:ln -s arch-s3c24x0 asm-arm/arch 创建的arch链接到arch-s3c24x0文件夹;

59行if [ "$2" = "arm" ] ; 成立,执行:

rm -f asm-$2/proc   
ln -s ${LNPREFIX}proc-armv asm-$2/proc

删除asm-arm/proc链接文件,创建新的proc文件链接到proc-armv文件夹;

上面创建了三个链接文件,创建的目的就是为了统一头文件在源代码里面的名称都为同一个名称,和具体平台和架构的名称无关,这样代码里面类似#include "arch-s3c24x0/memory" 这样的语句就可以用 #include "arch/memory" 来表示了。变换平台就不需要修改代码了。

67-69行:

echo "ARCH   = $2" >  config.mk        #>表示创建文件
echo "CPU    = $3" >> config.mk         #>>表示往文件里面写数据
echo "BOARD  = $4" >> config.mk

创建一个config.mk文件,并写入信息:

ARCH=arm  

CPU=arm920t  

BOARD=smdk2410  

71行

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk     #如果5参数存在而且不等于NULL 那么写入VENDOR = $5 到config.mk
[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC    = $6" >> config.mk       #如果6参数存在而且不等于NULL 那么写入SOC   = $6 到config.mk

所以SOC   = s3c24x0 也写入config.mk  ;

78行if [ "$APPEND" = "yes" ]   APPEND 变量在第11行定义为no,所以条件不成立,执行> config.h 创建config.h 文件;

最后将"/* Automatically generated - do not edit */" 与"#include <configs/$1.h>" 写入config.h文件,也就是"#include <configs/smdk2410.h>" 。

最后退出。

所以通过解读shell脚本,实际上运行的脚本如下:

APPEND=no	# Default: Create new config file
BOARD_NAME=""	# Name to print in make output

BOARD_NAME="smdk2410"
echo "Configuring for smdk2410 board..."

cd ./include
rm -f asm
ln -s asm-arm asm

rm -f asm-arm/arch
ln -s arch-s3c24x0 asm-arm/arch

rm -f asm-arm/proc
ln -s proc-armv asm-$2/proc

echo "ARCH   = arm" >  config.mk
echo "CPU    = arm920t" >> config.mk
echo "BOARD  = smdk2410" >> config.mk
echo "SOC    = s3c24x0" >> config.mk

> config.h		# Create new config file
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/smdk2410.h>" >>config.h

exit 0
这就是配置过程做的事情,再来看下makefile编译部分:

编译uboot直接用make命令进行编译;

在输入make的时候,实际上就是执行make all 

我们在makefile里面找到这个入口点:239行,前面都是些变量赋值等操作,这里是真正要执行的编译工作。

#########################################################################
#########################################################################

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):
		$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))

$(LIBS):
		$(MAKE) -C $(dir $(subst $(obj),,$@))

$(SUBDIRS):
		$(MAKE) -C $@ all

$(NAND_SPL):	version
		$(MAKE) -C nand_spl/board/$(BOARDDIR) all

$(U_BOOT_NAND):	$(NAND_SPL) $(obj)u-boot.bin
		cat $(obj)nand_spl/u-boot-spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin

version:
		@echo -n "#define U_BOOT_VERSION \"U-Boot " > $(VERSION_FILE); \
		echo -n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); \
		echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion \
			 $(TOPDIR)) >> $(VERSION_FILE); \
		echo "\"" >> $(VERSION_FILE)

gdbtools:
		$(MAKE) -C tools/gdb all || exit 1

updater:
		$(MAKE) -C tools/updater all || exit 1

env:
		$(MAKE) -C tools/env all || exit 1

depend dep:
		for dir in $(SUBDIRS) ; do $(MAKE) -C $$dir _depend ; done

tags ctags:
		ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
				lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
				fs/cramfs fs/fat fs/fdos fs/jffs2 \
				net disk rtc dtt drivers drivers/sk98lin common \
			\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`

etags:
		etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
				lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
				fs/cramfs fs/fat fs/fdos fs/jffs2 \
				net disk rtc dtt drivers drivers/sk98lin common \
			\( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`

$(obj)System.map:	$(obj)u-boot
		@$(NM) $< | \
		grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | \
		sort > $(obj)System.map
从代码可以为了产生最后我们想要的文件,有很多依赖关系,太复杂了,没时间分析了。只能通过在开发板上make一下uboot才能知道哦具体干了些什么事情;具体就不详述了,总之最后我们知道的信息有几点:

1 uboot代码的入口在哪里  ----  cpu/$(CPU)/start.S

2 uboot代码放在SDRAM的哪个地址开始运行  ---- 在链接的时候通过board/$(BOARD)/config.mk里面设置TEXT_BASE指定的,

   TEXT_BASE 表示board/$(BOARD)/u-boot.lds链接脚本里面的text段运行的地址,而cpu/$(CPU)/start.o放在text段的最开始,所以从TEXT_BASE开始运行。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: zynq-linux移植学习笔记应包含以下内容: 1. 对zynq架构和硬件资源的理解,包括PS和PL部分的特点。 2. 如何使用Xilinx SDK来编译配置u-boot和Linux内核。 3. 如何在硬件平台上运行和调试Linux系统。 4. 怎样在Linux系统中配置和使用各种硬件资源,如DMA、Ethernet、Flash等。 5. 如何在Linux系统中移植和运行应用程序,并与硬件资源进行交互。 6. 如何进行系统优化和资源管理,以提高系统性能和稳定性。 ### 回答2: Zynq是一款Xilinx公司开发的一种嵌入式系统芯片,其使用了双核Cortex-A9处理器和可编程逻辑器件(FPGA)的组合。移植Linux到Zynq芯片中,可以使其具备无限的扩展能力,极大地拓展了其应用领域,因此掌握Zynq-Linux移植技术是非常重要的。 Zynq-Linux移植分为四个主要步骤: 第一,准备工作 在移植前,需要确认硬件平台是否支持Linux运行,并且需要对硬件进行配置,最好使用Zynq开发板的官方配置; 第二,内核移植 内核移植是整个移植过程中最关键的一步。需要根据硬件平台的特性对内核进行选择和配置。可以从内核源代码库中获取内核代码,然后进行交叉编译。移植内核的过程中需要注意内核配置参数的设置,同时也要确保内核模块和驱动程序的编写。 第三,文件系统移植 在移植Linux的过程中,文件系统也是非常重要的。可以使用开发板官方Linux镜像,也可以自己编译镜像。移植文件系统还涉及到root文件系统的配置、挂载方式、网络配置和各种服务的配置等问题。 第四,驱动移植 驱动程序是连接硬件和软件的关键部分,需编写相应的驱动程序来实现对硬件的控制。移植驱动程序的过程中需要关注各种硬件接口和设备驱动API的使用,确保驱动程序与硬件配合良好。 总结来说,Zynq-Linux移植技术的掌握需要具备较强的Linux基础知识、驱动开发经验和交叉编译工具链的使用能力。同时,还需要有耐心和细心,对每个步骤进行仔细的分析和处理。 在学习中,需要结合实际开发项目,多进行实践操作才能更好地掌握Zynq-Linux移植技术,为后续项目的开发和应用提供更好的支持。 ### 回答3: Zynq-7000系列是一种由Xilinx开发的SoC(系统级芯片),它将双ARM Cortex-A9处理器和可编程逻辑(FPGA)集成在一起。这使得开发人员可以使用硬件加速加速器来加速运行在Linux上的各种应用。然而,实现这个目标需要进行移植。 在开始Zynq Linux移植学习笔记之前,需要一些基本的知识。首先,需要了解Linux内核的基本工作原理和Linux驱动程序的编写技术。然后,需要了解FPGA和SoC体系结构。 在开始移植之前,需要为SoC开发板选择正确的Linux发行版。这通常需要考虑处理器体系结构,内存大小和设备驱动程序的可用性。另外,还需要考虑是否需要自定义内核或驱动程序以满足应用程序的需求。 接下来,需要编写设备树文件(DT)来描述SoC架构。设备树文件是一种描述硬件配置信息的特殊语言。它会告诉内核有哪些设备可用以及如何访问这些设备。 接下来,需要配置Linux内核以支持Zynq-7000处理器。这可能包括启用适当的内核配置选项,编写设备驱动程序以及配置启动过程。 最后,需要启动Zynq板并验证Linux系统稳定运行。这些步骤包括在启动过程中将设备树文件加载到内存中,以及启动用户空间应用程序。 总之,移植Zynq Linux是一项复杂的任务,需要广泛的专业知识和技术。但是,它可以为开发人员提供强大的硬件加速支持,使他们能够加速处理一系列计算密集型应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值