关注分享主机优惠活动
国内外VPS云服务器

基于ARM处理器的U-BOOT详细移植概述(arm uboot)

摘要:该函数是将标准输入中的所有大写字母转换为其对应的小写字母。 移植的源代码被编译到源代码目录中,因此源代码目录和目标文件目录是相等的,如果不满足条件,则会执行分支代码。

在嵌入式产品的开发阶段,必须不断地将Bootloader下载到内存中。 如果你的内存使用 NAND 闪存,它一开始里面没有任何东西,所以你只能根据你的启动指令从处理器启动。 还有其他启动方式,比如从SD卡或内存启动,然后使用USB或网络接口先下载u-boot.bin到内存,然后将内存内容写入nand,但是对于前4页,只能写入每页的前2KB数据(对于OK6410开发板,处理器采用S3C6410处理器,NAND每页使用4KB内存)从NAND启动时,处理器自动复制每页的前2KB四页 NAND 到芯片上的 8KB SRAM。 这是由处理器硬件决定的,因此在前 4 个页面之后,这里仅存储每个页面的前 2KB。 页数 每一页都已完整书写。

在开发u-boot时,需要不断地调试u-boot,因为。此时nand我们已经有了u-boot,我们可以从nand内存启动,并且可以根据开发的下载模式菜单选项将u-boot重新下载到nand。

u-boot开发时,从nand启动时,只要一打开电源,处理器硬件 NAND 闪存的前四页每页的前 2KB 会自动复制到片上 SRAM 中进行操作。在SRAM中运行的代码将NAND中0到240KB(这个大小可以更改)的代码复制到内存中,然后跳转到内存中并执行。 在内存中执行时,会应用更多空间。 (除了它占用的内存空间外,还包括12个字节用于abort异常、堆栈空间、malloc内存池空间、环境参数空间和一些全局变量空间),总共2MB,详情见(3.2).1) u[ k4]启动内存分布图。

当嵌入式产品出厂时,u-boot、内核和文件系统都已经在 NAND 内存中,并且可以实现相应的功能(如果使用 NAND 内存编译的话)。 image为nand,操作在内存中进行,先在8KB的片内SRAM中,然后跳转到内存DDR。]执行boot时,将nand中的内核镜像复制到内存中,并执行内核。

1. U-Boot-1.1.6 顶层Makefile分析

(顶级内容级makefile为黑色,其他文件的内容为蓝色,移植期间更改的代码为红色)

根据uboot根目录下的Readme文件,如果要使用u-boot,必须先配置即运行 make orlinx_nand_ram256_config 命令,运行并配置(添加) 将 forlinx_nand_ram256_config 目标和其他选项添加到顶级目录 Makefile 中,并运行 make all 生成以下三个文件:4]Boot.bin、U-Boot ELF格式文件、U-Boot.srec。

U-启动配置流程

(一)版本说明

VERSION = 1PATCHLEVEL = 1SUBLEVEL = 6EXTRAVERSION =U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)VERSION_FILE = $(obj)include/version_auto generated.h

(2)定义主机系统架构

HOSTARCH := $(shell uname -m | /sed -e s/i.86/i386/ / - es/ sun4u/sparc64/ / -es/arm.*/arm/ / -es s/sa110/arm/ / -es/powerpc/ppc/ / -es/macppc/ppc/)

"sed -e" 表示一系列命令脚本后跟表达式“s/abc/ def/”查找内容 'abc ' 在标准输入上并将其替换为 'def'。 '.' 可以用在 'abc' 表达式中。 作为通配符。 命令“uname -m”将打印主机 CPU 的体系结构类型。 如果您的计算机使用 Intel Core2 系列 CPU,请使用 uname –m”将输出“i686”,它与命令“sed -e s/i.86/i386/”中的“i.86”匹配,因此当Makefile在机器上运行时,HOSTARCH被设置。

(3) 定义主机操作系统类型

HOSTOS := $ (shell uname [ k4]s | tr "[:upper:]" "[: lower:]" | / sed -e "s//(cygwin/).*/cygwin/")exportHOSTARCH HOSTOS# 处理 tcsh 等供应商的定义冲突。 =

"uname -s" 是主机内核名称,开发主机使用Linux发行版fedora-12。 “uname -s”的结果是“Linux”。 "tr "[:upper:]" "[: lower:]"" 的作用是将标准输入中的所有大写字母转换为对应的小写字母,因此结果为 。 将 HOSTOS 设置为“linux”。

(4) 定义一个shell来运行shell脚本(这不包括在内)(在源代码中) 。 部分)

# 如果可能的话,将 shell 设置为 bash,否则回退到 shSHELL := $(shell if [ -x "$$BASH" ]; then echo $ $BASH; /else if[ -x /bin/bash ]; 然后回显 /bin/bash。 /else echo sh; fi; fi)

"$$BASH" 本质上与字符串 "$BASH" 一起使用第一个 $ 符号的含义是指示第二个 $ 是常规字符。) 如果运行当前Makefile的shell中定义了环境变量“$BASH”,并且文件“$BASH”是可执行文件,则SHELL的值为“$BASH”。 否则,如果“/bin/bash”是可执行文件,则 SHELL 值为“/bin/bash”。 如果以上两者都不适用,则将“sh”分配给 SHELL 变量。 如果计算机安装了 bash shell,并且 shell 的默认环境变量中定义了“$BASH”,则 SHELL 将设置为 $BASH。

(5)设置编译输出目录

ifdef O ifeq("$(origin O) ", "命令行")BUILD_DIR := $(O)endifendif

函数输出结果 $(origin, variable) 字符这是一排。 输出结果由变量的定义方式决定。 如果变量是在命令行上定义的,则 origin 函数返回“命令行”。 如果在命令行执行“export BUILD_DIR=/tmp/build”命令,则“$(origin O)”的值为“命令行”和BUILD_DIR 设置为“/tmp/build”。

以下内容表示如果${BUILD_DIR}代表的目录没有定义,则创建的目录:

ifneq ($(BUILD_DIR),)saved-output := $(BUILD_DIR)# 尝试创建输出目录。 $(shell [ -d ${BUILD_DIR} ] || mkdir [ k4]p ${ BUILD_DIR})

下一步的内容表示如果$(BUILD_DIR)为空则赋值给它。 当前目录路径(源代码目录)。 检查 $(BUILD_DIR) 目录是否存在。

# 检查是否成功。 BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)$(if $(BUILD_DIR),,$(错误输出目录“$(saved-output)”不存在))endif # ifneq ( $(BUILD_DIR),)

在下面的内容中,CURDIR变量表示Make当前的工作目录。 目前Make正在运行U-Boot的顶级目录下的Makefile,所以此时CURDIR就是U-Boot的顶级目录。 当您运行以下代码时,SRCTREE 和 src 变量变为 U-启动代码的顶层目录,以及OBJTREE,obj变量是输出目录。 如果没有定义BUILD_DIR环境变量,则SRCTREE、src变量和OBJTREE、obj变量都将是U-Boot源代码目录。 MKCONFIG 代表 U-Boot 根目录中的 mkconfig 脚本。 OBJTREE:= $(if $(BUILD_DIR),$(BUILD_DIR),$(CURDIR))SRCTREE:= $(CURDIR)TOPDIR:= $(SRCTREE)LNDIR:= $(OBJTREE)exportTOPDIR SRCTREE OBJTREEMKCONFIG: = $(SRCTREE)/mkconfigexport MKCONFIGifneq ($(OBJTREE),$(SRCTREE))REMOTE_BUILD := 1export REMOTE_BUILDendif# $(obj) 和 (src) 在 config.mk 中定义,但在主 Makefile 中# 你还需要提前将它们包含在 config.mk 中。 对于某些目标(例如 unconfig、clean、clobber 和 distclean)来说确实如此。 ifneq ($(OBJTREE),$(SRCTREE))obj := $(OBJTREE)/src := $(SRCTREE) )/elseobj :=src :=endifexport obj src

上述内容中,MKCONFIG := $(SRCTREE)/mkconfig 是位于根目录中的 mkconfig 文件。

(6) 使 forlinx_nand_ram256_config 进程运行

分析此过程将帮助您了解在 U-Boot 移植过程中需要更改哪些文件。 运行该命令的前提是在移植 U-Boot 时,在根目录下的 Makefile 中添加如下内容:

forlinx_nand_ram256_config : unconfig@$(MKCONFIG ) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 依赖NAND ram256 的“unconfig”定义如下(Makefile 的第 330-350 行左右): unconfig:@rm -f $(obj)include /config.h $(obj)include/config.mk / $ (obj)board /*/config.tmp $(obj)board/*/*/config.tmp

不是运行此命令时显示在 shell 中。 “obj”变量是编译输出的目录,因此“unconfig”函数会清除上次运行 make *_config 命令生成的配置文件(include/config.h、include/config.h 等)是要做的。 MK等)。

$(MKCONFIG) 在上面(5)中指定为“$(SRCTREE)/mkconfig”,是位于根目录的mkconfig 文件。 如果有 $(@:_config=) ,则 $(@: _config=) 将所有传递的参数中的 _config 替换为空('@'指的是规则的目标文件名,这里为“forlinx_nand_ram256_config” $(text: patternA=patternB),该语法的意思是用patternB替换text变量每个元素末尾的patternA的文本并输出 =) 功能是去掉forlinx_nand_ram256_config中的_config,得到forlinx_nand_ram256和U[k4移植到OK6410]。 BOOT没有$(@:_config=)项

根据上面的分析,运行make forlinx_nand_ram256_config后,实际上运行以下命令:

./mkconfig smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256

因此,当您运行 make forlinx_nand_ram256_config 时,您会得到“smdk6410 arm s3c64xx smdk6410 samsung”。s3c6410 NAND ram256”作为参数传递给当前目录下运行的mkconfig脚本。这些参数的实际含义是:

smdk6410:目标(目标板型号)

arm:架构(CPU架构目标板)

s3c64xx:CPU(使用的具体CPU型号)

smdk6410:主板

三星:供应商(制造商名称)

s3c6410:SOC

NAND:

ram256:

mkconfig 文件执行以下操作:

确定开发板名称 BOARD_NAMEAP。PEND=no # no 表示创建新的配置文件,yes 表示附加到配置文件 BOARD_NAME="" # 要输出的名称 make outputTARGETS=""while [ $# - gt 0 ] ; k4]-) 转移 ;;-a) 追加=是 ;;-n) BOARD_NAME="${1%%_config} " ;转移 ;`echo $1 | sed "s:_: :g"` ${TARGETS}" ; 转移 ;;*) 中断 ;;esacdone[ "${BOARD_NAME} " ] || BOARD_NAME ="$1"

命令 ./mkconfig smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256 有“[ k4 ]-”“[k4 ]a” "-n" "-t" "*" 由于符号的原因,while 循环中什么也没有发生。 前两行的两个值仍然保持原来的值,但是最后一行执行后,BOARD_NAME的值等于第一个参数,smdk6410(传递的参数是 mkconfig )文件,$0 = mkconfig, $1 = smdk6410,$2=arm,$3=s3c64xx,$4=smdk6410,$5=三星,$6=s3c6410,$7=NAND,$8=ram256)。

注意:

U-Boot1.1.6- ]for- OK6410 源代码中,BOARD_NAME=""行后面有SETMMU="no"行,表示使用mmu来启动NAND,但首先将该值设置为no。 margin-left:.0001pt;text-align:justify;">[ $# -lt 4 ] && exit 1

[ $# -gt 9 ] && 退出 1

echo “配置 ${BOARD_NAME} 板从 $7 $8 $9 启动...”

以上功能代码是检查参数的数量以及是否正确,如果参数的数量小于4或者大于9,则认为是不正确的。这里的命令有9个参数,$#是9来设置从${BOARD_NAME}板开始,是运行make forlinx_nand_ram256_config命令后在平台/开发板上创建的信息。到相关的头文件。链接到特定于体系结构的标头 if [ "$SRCTREE" != "$OBJTREE" ] ; thenmkdir -p ${OBJTREE}/includemkdir -p ${OBJTREE}/include2cd ${OBJTREE}/include2rm [k4 ] f asmln -s ${SRCTREE}/include/asm-$2 asmLNPREFIX= "../../include2/asm/"cd ../includerm -rf asm-$2rm [k4 ] f asmmkdir asm-$2ln -s asm-$2 asmelsecd ./ includerm -f asmln -s asm-$2 asm # 符号链接,或软链接 fi

第一行代码判断源代码目录和目标文件目录是否相同。 您可以通过选择将 U-BOOT 编译到另一个目录来保留源代码。 它很干净,可以同时使用不同的配置进行编译。 用OK6410的U-BOOT移植的源代码被编译到源代码目录中,因此源代码目录和目标文件目录是相等的,如果不满足条件,则会执行else分支中的代码。

else 分支中的代码首先进入 include 目录并删除 asm 文件(这是在前面使用设置(你创建的链接文件)再次创建asm文件,并将其链接到asm-$2目录,也就是asm-arm目录,这是源代码中经常调用的东西。需要针对不同的架构进行修改。修改“asm-XXX架构”,首先建立一个从asm到asm-arm的符号链接,并在包含头文件时直接包含它。 1: rm -f asm-$2 /arch2: if [ -z "$6" -o "$6" = "NULL" ] ; then3: ln -s ${ LNPREFIX}arch-$3 asm-$2/arch4:else5:ln[ k4]s ${LNPREFIX}arch-$6 asm-$2/arch6:fi7: if [ "$2" = "arm" ] ; then8:rm -f asm-$2/proc9:ln [ k4]s ${LNPREFIX}proc-armv asm-$2/proc10:fi

第 1 行删除 /asm-arm/arch 目录的包含内容。 命令./mkconfig smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256,$6是S3C6410,不为空,不为空NULL,所以不满足第二行条件,执行else分支。 第 5 行,LNPREFIX 为空(未在顶层 Makefile 中定义),因此将执行 ln –s Arch-s3c6410 asm-arm/arch(在 U-Boot1.1.6- 中) 。 -OK6410 的源代码 include/asm-arm/arch,后来链接到 include/asm-arm/arch-s3c64xx)。

Line 8-9 如果目标板是arm架构,上面的代码会建立一个符号链接include/asm-arm/proc并链接到目录include/asm- 建立的好处arm /proc-armv目录是编译U-Boot时可以直接进入链接文件指向的目录,而不必根据各种情况选择不同的目录

注意:

U-Boot1.1.6-for-OK6410 在源代码第 6 行和第 7 行添加以下 OK6410 代码。

# 为 s3c24xx SoC 创建链接

if [ "$3 " = "s3c24xx" ] ; 然后

rm [ k4]f regs.h

ln -s $6.h regs.h

rm -f asm-$2/arch

ln -s arch-$3 asm-$2/arch

fi

# 为 s3c64xx SoC 创建链接

p> p>

如果 [ "$3" = "s3c64xx" ] ; 则

rm -f regs.h

ln -s $6.h regs.h

rm -f asm [ k4] $2/arch

ln -s arch -$3 asm-$2/arch

fi

因此,如果“$3”=“s3c64xx”,则删除 include/regs.h,将 regs.h 链接到 include/s3c6410.h,并写入 S3C6410。 这个头文件。 寄存器定义。 然后删除include/asm-arm/arch目录并重新创建include/asm-arm/arch目录并将其链接到include/asm-arm/arch-S3C64xx目录。

在第 9 行和第 10 行之间添加以下代码。

fi

# s3c64xx-mp 为 SoC 创建链接

if [ "$3 " = "s3c64xx- mp" ] ; 然后

rm -f regs.h

ln -s $6.h regs.h

rm -f asm-$2/arch

ln -s Arch-$3 asm-$2 /arch

由于 $3=s3c64xx,上述代码中的条件不成立,换句话说,上述代码不包含文件 include/config。 mk 顶级 Makfile.

# 为 Makeecho 创建包含文件 "ARCH = $2" > config.mk echo "CPU = $3" >> config.mkecho "BOARD = $4" >> config.mk[ "$5" ] && [ "$5" != " NULL" ] && echo "VENDOR = $5" >> config.mk[ "$6" ] && [ "$6" != "NULL" ] && echo " 当我运行 SOC = $6" >> config .mk

. /mkconfig smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256”命令,上面这行代码创建的 include/config.mk 文件有以下内容: 没错。 ARCH=armCPU=s3c64xxBOARD=smdk6410VENDOR=samsungSOC=s3c6410指定开发板代码。目录

(可选。如果您要移植的 U-Boot 源代码中已存在这些目录,请选择否,以下代码不需要)如三星官方提供的U-Boot源码(必填)

# 将board目录赋值给BOARDIR变量 if [ -z "$5" - o " $5" = "NULL" ] ; thenBOARDDIR=$4elseBOARDDIR=$5/$4fi

上面代码指定了board下的目录板自己的代码目录。 开发板目录。 如果 $5 (VENDOR) 为空,则 BOARDDIR 设置为 $4 (BOARD),否则设置为 $5/$4 (VENDOR/BOARD,即 samsung/smdk6410)。 这里,$5不为空,因此BOARDDIR设置为samsung/smdk6410。

创建开发板相关头文件 include/config.hif [ "$APPEND" = "yes" ]# 追加到现有配置文件 2: then3: echo >> config.h4: else5 :> config.h# 创建新配置文件 6: fi7: echo "/* 自动生成 - 请勿编辑 */" >>config.h8: echo "#include " >>config.h9: exit 0 " >" 和 ">>" Linux命令, > config.h 表示重新创建config.h文件, echo "#include " >>config.h 表示将#include 添加到config.h 文件中。 APPEND 保持其原始值“no”,因此重新创建 config.h 并添加以下内容: /* 自动生成- 请勿编辑 */#include 此时,include/config.h 文件包含: 内容同上。 注意:在 U-Boot1.1.6-for-OK6410 源代码的第 7 行和第 8 行之间为 OK6410 添加了以下代码: case $7 inSD)echo "# Define FORLINX_BOOT_SD" >> config。 h SETMMU="no";;NAND)echo "#define FORLINX_BOOT_NAND" >> config.h SETMMU="yes";;*);;esaccase $8 inram128)echo "#define FORLINX_BOOT_RAM128" >> config.. /board/samsung/smdk6410/config.mk # 清除文件上下文 echo "ifndef TEXT_BASE" >> ../board/samsung/smdk6410/config.mk if [ ${SETMMU} = "yes" ] then echo "TEXT_BASE = 0xC7E00000 " >> ../board/samsung/smdk6410/config.mk else echo "TEXT_BASE = 0x57E00000" >> ../board/samsung/smdk6410/config.mk fi echo "endif" >> ../board/samsung/smdk6410/config.mk;;ram256)echo "#define FORLINX_BOOT_RAM256" >> config.h > ../board/samsung/smdk6410/config .mk # 清除文件上下文 echo "ifndef TEXT_BASE" >> ../board/samsung/smdk6410/config.mk if [ ${SETMMU} = "yes" ] then echo "TEXT_BASE = 0xCFE00000" >> .. /board/ samsung/smdk6410/config.mk else echo "TEXT_BASE = 0x5FE00000" >> ../board/samsung/smdk6410/config.mk fi echo "endif" >> ../board/samsung/smdk6410/config.mk ;;* );;esacif [ "$9" = "hdmi" ] ; thenecho "#define FORLINX_LCDOUT_HDMI" >> config.hfi 对于 OK6410,$7=NAND,因此在 include/config.h 文件中添加 #define FORLINX_BOOT_NAND 。 SETMMU 值设置为 yes(将 SETMMU 值设置为 no)。 如果用nand启动,则需要使用mmu,所以这里设置为yes)。 对于OK6410,$8=ram256,所以在include/config.h文件和位于上层目录(开发板代码所在目录)的/board/samsung/smdk6410/config.mk文件中添加#define FORLINX_BOOT_RAM256。 包含内容被清除(运行“">../board/samsung/smdk6410/config.mk #clear file context”以一行清除)。 清除后,添加ifndef TEXT_BASE。 由于SETMMU的值为yes,所以TEXT_BASE = 0xCFE00000(该地址是映射地址,使用mmu后,该内存地址将被映射。对于128内存,除非超过虚拟内存,否则该值将是0XC7E00000(对应的地址) DMC1物理地址的最大范围0x6FFFFFF),并在末尾添加endif。 对于 OK6410,#define FORLINX_LCDOUT_HDMI 未添加到 /include/config.h 文件中,因为未传递 $9。

一般情况下,运行 make forlinx_nand_ram256_config 命令后,上面第 (6) 点的所有步骤都会在 mkconfig 脚本中执行。 。 。 从这些操作可以看出,需要在 board 目录下新建一个开发板 目录,并在 include/configs 目录下新建一个 .h 文件,用于存储开发板 。

U-Boot没有像Linux那样的可视化配置界面(make menuconf使用等)g)、要剪切和设置U-Boot,必须手动修改配置头文件/include/configs/smdk6410.h。 该配置头文件中有两种类型的宏:

一类是以“CONFIG_”为前缀的选项,用于选择CPU、SOC、开发板类型、设置系统时钟、选择设备。 司机等 示例:

#define CONFIG_S3C6410 1 /* 在 SAMSUNG S3C6410 SoC 中 */

#define CONFIG_S3C64XX 1 1 /* 在 SAMSUNG S3C64XX 系列中 */

#define CONFIG_SMDK6410 1 /* On SAMSUNG SMDK6410 board */

另一种类型是前缀为“CFG_”的参数(配置),用于:Masu。 配置malloc缓冲池大小、U-BOOT提示、U-BOOT下载文件时默认加载地址、flash起始地址等。 示例:

#define CFG_MALLOC_LEN (CFG_ENV_SIZE+128*1024)

#define CFG_PROMPT

#define CFG_LOAD_ADDR 0x50000000

下面的编译链接过程你可以看到U-Boot中的几乎所有文件都被编译和链接了,但文件是否包含有效代码是通过宏开关来设置的,例如对于/dm9000x.c,其格式为:# #include #include #ifdef CONFIG_DRIVER_DM9000#include "dm9000x.h"/*实际代码*/…#endif/* CONFIG_DRIVER_DM9000 */

如果 /include/configs/smdk6410.h 中定义了宏 CONFIG_DRIVER_DM9000,则该文件包含有效代码。否则该文件将被注释为空。

"CONFIG_" 除了设置一些参数之外,被认为主要用于配置 U-Boot 的功能以及选择使用文件的哪一部分; 另一方面,“CFG_”用于设置更详细的参数。

2.U-引导编译和链接过程(后面是Makefile分析目录)

(1)分析顶层Config.mk文件中的其余代码和顶层代码-级Makefile文件

设置完成后,运行make all进行编译。 如果直接运行“make all”命令而不运行“make forlinx_nand_ram256_config”命令,您将收到一条错误消息,显示“系统未配置-请参阅自述文件”。

然后停止编译。

当您运行“make forlinx_nand_ram256_config”命令时,会在 include 目录中创建一个 config.mk 文件,所以 。 U-Boot判断该文件是否存在,并判断用户是否运行了“make forlinx_nand_ram256_config”命令。 请注意,1 号出口又回来了。 相关代码是: 114: ifeq ($(OBJTREE)/include/config.mk,$(通配符 $(OBJTREE)/include/config.mk))…241: 全部:…249: $ (obj)u- boot.bin:$(obj)u-boot250: $(OBJCOPY ) ${OBJCFLAGS} -O 二进制 $&2328: @exit 1329: endif 在顶层 Makefile 中,继续分析以下代码: # Load ARCH、BOARD 和 CPU 配置 下面是 ARM 相关部分 117.e $(OBJTREE)/include/config.mk118:exportARCH CPU 板供应商 SOC…127:ifeq ($(ARCH),arm)128:CROSS_COMPILE = arm-linux-129:endif…162:exportCROSS_COMPILE164:#加载其他配置 165: include $(TOPDIR)/config.mk

上述代码的第 127-129 行使用arm-linux 编译器 (ARCH=arm) 如果 ARCH 和目标机器架构相同。

注意:

U-Boot1.1.6-for-OK6410 源码中,在第162行之前添加了如下代码:

CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux[k4 ] 这意味着无论您上面如何决定,交叉编译器将始终使用位于 /usr/local/arm/4.3.2/bin 目录中的arm-linux-编译器。

在第 117 行和第 165 行,执行以下操作:包含config.mk文件,第117行包含make forlinx_nand_ram256_config命令生成的include/config.mk,即配置过程中生成的include/config.mk文件。 这定义了 ARCH/CPU/BOARD 的值。 /VENDOR/SOC 分别为arm、s3c64xx、smdk6410、samsung、s3c6410。 第 165 行包含位于 U-Boot 顶层目录中的 config.mk 文件。 该文件包含一些编译设置。 基于 ARCH/CPU/BOARD/VENDOR/。 SOC变量的值决定了编译器、编译选项等。

顶层config.mk文件分析:

Ø配置obj和srcifneq ( $(OBJTREE ), $(SRCTREE))ifeq ($(CURDIR),$(SRCTREE))dir :=elsedir := $(subst $(SRCTREE)/,,$(CURDIR))endifobj := $(if $(dir) ,$ (OBJTREE)/$(dir)/,$(OBJTREE)/)src := $( if $(dir),$(SRCTREE)/$(dir)/,$(SRCTREE)/)$ (shell mkdir [k4 ]p $(obj))elseobj :=src :=endif 目标是 运行上述代码后,src 和 obj 的源代码目录将为空。 Ø设置编译选项 PLATFORM_RELFLAGS =PLATFORM_CPPFLAGS = #Compile Options PLATFORM_ = #Connection Options 使用这三个变量来表示交叉编译器的编译选项。 然后 Make 检查交叉编译器支持的编译选项。选择该项目并为这三个变量添加适当的选项。 包含开发板相关的配置文件(跳过第54行到第74行,这是在NetBSD上使用交叉编译器时需要的定义) ifdef ARCHsinclude $(TOPDIR)/$(ARCH)_config.mk# include 架构相关的值规则endif$(ARCH )是“arm”,所以包含了顶层目录下的“arm_config.mk”,对顶层目录下的arm_config.mk文件基本没有任何作用,只有一行代码用来设置PLATFORM_CPPFLAGS编译选项(相关)。武装处理器)。 ifdefCPUsinclude $(TOPDIR)/cpu/$(CPU)/config.mk# 包含特定于 CPU 的规则 endif$(CPU) 的值为“s3c64xx”,因此包含“cpu/s3c64xx/config.mk”。 该脚本主要设置与s3c64xx处理器相关的编译选项(与arm相关的PLATFORM_CPPFLAGS编译选项)。 ifdefSOCsinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk# include SoC Specific Rulesendif$(SOC) 由于值为 s3c6410,因此 Make 程序应包含 cpu/s3c64xx/s3c6410/config.mk这么说吧。 ,这个文件不存在,但是使用了“sinclude”命令,所以没有报错。 ifdef VENDORBOARDDIR = $(VENDOR)/$(BOARD)elseBOARDDIR = $(BOARD)endif $(BOARD) 的值为 smdk6410,VENDOR 的值为 samsung,因此 BOARDDIR 的值为 samsung/smdk64。10. BOARDDIR 变量表示开发板特定代码所在的目录。 ifdef BOARDsinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk# 包含板特定规则 endif 顶层目录中的 config.mk 文件包含“board/samsung/smdk6410/config.mk”我是。 脚本内容如下: ifndef TEXT_BASETEXT_BASE = 0xCFE00000endifU- Boot编译时,TEXT_BASE用作代码段连接的起始地址(该地址由MMU映射)。 Ø其他代码1(第95行---第115行) CONFIG_SHELL:= $(shell if [ -x "$$BASH" ]; then echo $$BASH; / else if [ [ k4 ] ]x /bin/bash ]; 然后 echo /bin/bash; / else echo fi ; fi)ifeq ($(HOSTOS)-$(HOSTARCH),darwin-ppc)HOSTCC= ccelseHOSTCC= gccendifHOSTCFLAGS = [ k4]Wall -Wstrict-原型 -O2 -fomit-frame-pointerHOSTSTRIP=stripcc-option = $(shell if $(CC) $(CFLAGS) $( 1 ) -S -o /dev/null -xc /dev/null /> /dev/null 2>&1; 然后 echo "$(1)";) 上面代码中的最后 2 个线,变量 CC 和 CFLA在下面的代码中 GS 被定义为惰性变量。 CC 是arm-linux-gcc。 函数 cc-option 用于检查编译器 CC 是否支持某个选项。 将两个选项作为参数传递给 cc-option 函数。 该函数调用CC编译器检查是否支持参数1。 如果支持,则函数返回参数1;如果不支持,则返回参数2(因此CC编译器必须支持参数1或参数1.2;如果两者都不支持,则会出现编译错误)。 您可以通过调用 cc-option 函数将支持的选项添加到 FLAGS,如下所示: FLAGS +=$(call cc-option,option1,option2)Ø指定交叉编译工具 AS= $(CROSS_COMPILE)asLD = $(CROSS_COMPILE)ldCC= $(CROSS_COMPILE)gccCPP= $(CC) [k4 ]EAR = $(CROSS_COMPILE)arNM= $(CROSS_COMPILE)nmSTRIP= $(CROSS_COMPILE)stripOBJCOPY = $(CROSS_COMPILE)objcopyOBJDUMP = $(CROSS_COMPILE) objdumpRANLIB= $(CROSS_COMPILE)RANLIB

对于arm架构处理器,CROSS_COMPILE在顶级makefile中定义。

CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux[k4 ](第161行左右)

所以上面的代码会被Specify。 ]linux- gcc、arm-linux-ld等

其他代码2(130行---217行)

这部分代码的第 143 行 (LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds) 这里是 189 /board/Samsung/smdk6410/u-boot.lds 目录中的代码行(:= 表示替换以前的值):

LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE ) $(PLATFORM_LDFLAGS)

因此,根据第189行,添加“-Bstatic - T /board/Samsung/smdk6410/u-boot.lds”和单词“-Ttext 0xCFE00000”(+=表示添加)

是隐式编译指定规则

。 代码的最后一部分(第218-246行),指定隐式编译规则。 例如,如上面所定义的,具有相同名称且后缀为“.S”的源文件将根据第一条规则生成以“.s”结尾的目标文件。 如果缺少“.S” 根据最后一条规则,由“.c”同名文件生成一个以“.c”结尾的同名文件。

上面是顶层目录下config.mk文件的内容,下面是其余部分顶层目录下的Makefile就是这个内容。 166:################################################ # ######################167: # U- 启动对象....顺序很重要(即启动是第一个)168: 169: OBJS = cpu/$(CPU)/start.o170: ifeq ($(CPU),i386)171: OBJS += cpu/$(CPU)/start16.o172: OBJS += cpu /$(CPU)/reset.o173 :endif174:ifeq ($(CPU),ppc4xx)175:OBJS += cpu/$(CPU)/resetvec.o176:endif177:ifeq ($(CPU),mpc83xx)178: OBJS += cpu/$(CPU) /resetvec.o179:endif180:ifeq ($(CPU),mpc85xx)181:OBJS += cpu/$(CPU)/resetvec.o182:endif183:ifeq ($(CPU),mpc86xx) 184:OBJS += cpu/ $(CPU)/resetvec.o185: endif186: ifeq ($(CPU),bf533)187: OBJS += cpu/$(CPU)/start1.ocpu/$(CPU)/interrupt.ocpu/$(CPU)/cache.o188: OBJS += cpu/$(CPU)/cplbhdlr.ocpu/$(CPU)/cplbmgr.ocpu/$(CPU)/ flash.o189: endif190:191: OBJS := $(addprefix $(obj),$(OBJS))192:193: LIBS = lib_generic/libgeneric.a194: LIBS += board/$(BOARDDIR)/lib$(BOARD ).a195: LIBS += cpu/$(CPU)/lib$(CPU).a196: ifdef SOC197: LIBS += cpu/$(CPU)/$(SOC)/lib$(SOC).a198: endif199: LIBS += lib_$(ARCH)/lib$(ARCH).a200: LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a /201 : fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a202: LIBS += net/libnet.a203: LIBS += disk/libdisk.a204: LIBS += rtc/librtc.a205: LIBS += dtt/libdtt。 a206: LIBS += drivers/libdrivers.a207: LIBS += drivers/nand/libnand.a208: LIBS += drivers/nand_legacy/libnand_legacy.a209: LIBS += drivers/sk98lin/libsk98lin.a210: LIBS += post/libpost 。后/cpu/libcpu.a211: LIBS += common/libcommon.a212: LIBS += $(BOARDLIBS)213: 214: LIBS := $(addprefix $(obj),$(LIBS))215: .PHONY: $ (LIBS)216:217:# 添加 GCC lib218:PLATFORM_LIBS += -L $(Shell 目录名称 `$(CC) $(CFLAGS) -print-libgcc-File- ]name ` ) - lgcc219:220: # 早期需要“工具”,所以把它放在前面 221: # 不要包含 $(LIBS) 中已经完成的任何内容 222: SUBDIRS= tools /223: 示例 /224: post /225 : post/cpu226: .PHONY: $(SUBDIRS)227:228:ifeq ($(CONFIG_NAND_U_BOOT),y)229:NAND_SPL = nand_spl230:U_BOOT_NAND = $(obj)u[ k4]boot-nand.bin231 :endif232 :233:__OBJS := $(替换 $(obj),,$(OBJS))234:__LIBS := $(替换 $(obj),,$(LIBS)) 235:236:##### ################################################ ## # ############237:###################################### ####################################238:239: 全部 = $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND)240:241:全部:$(ALL)242:243:$(obj)u-boot.hex:$(obj)u-boot244:$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@245 :246:$(obj)u-boot.srec:$(obj)u-boot247:$(OBJCOPY) ${OBJCFLAGS} -O srec $< $@248:249:$(obj) u-boot.bin:$(obj)u-boot250:$(OBJCOPY) ${OBJCFLAGS} -O 二进制 $< $@251:252:$(obj)u-boot.img :$(obj)u-boot.bin253:./tools/mkimage -A $(ARCH) -T 固件 -C 无 /254:-a $(TEXT_BASE) - e 0 /255:-n $(shell sed -n -e "s/.*U_BOOT_VERSION//p" $(VERSION_FILE) | /256:sed -e "s/"[ ] *$$/ $(BOARD) 用于板“/”) /257:-d $< $@258:259:$(obj)u-boot.dis:$(obj)u- boot260 : $(OBJDUMP) -d $ $@261: 262: $(obj)u- 启动:版本相关 $(SUBDIRS) $(OBJS) $(LIBS) $(LDSC)RIPT)263: UNDEF_SYM=`$(OBJDUMP) -x $(LIBS) |sed -n -e "s/.*/(__u_boot_cmd_.*/)/-u/1/p "|sort|uniq`;/264: cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) /265: --start-group $(__LIBS) [ k4]-end-group $(PLATFORM_LIBS) /266:-Map u-boot.map -o u-boot267:268:$(OBJS):269:$(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir $@))270:271:$(LIBS):272:$(MAKE) -C $(dir $(subst $(obj),,$@))273:274:$(SUBDIRS):275:$(MAKE) -C $@ all276:277:$(NAND_SPL):version278:$(MAKE) [ k4]C nand_spl/board/$(BOARDDIR) all279:280:$(U_BOOT_NAND):$(NAND_SPL) $(obj)u-boot.bin281:cat $(obj)nand_spl/u-boot [k4 ]spl-16k.bin $(obj)u-boot.bin > $(obj)u-boot-nand.bin282:283:version:284:@echo -n "#定义 U_BOOT_VERSION /"U-Boot " > $(VERSION_FILE); /285:echo-n "$(U_BOOT_VERSION)" >> $(VERSION_FILE); /286: echo -n $(shell $(CONFIG_SHELL) $(TOPDIR)/tools/setlocalversion /287: $(TOPDIR)) >> $(VERSION_FILE); /288:echo "/"" >> $(VERSION_FILE)289:290:gdbtools:291:$(MAKE) -C 工具/gdb all || 退出 1292:293:updater:294: $(MAKE) [ k4] 所有 C 工具/更新程序 || End 1295:296:env:297: $(MAKE) - 所有 C 工具/环境 || 取决于 $(SUBDIRS) 目录 (MAKE) [ k4]C $$dir _depend ;done301:302:tags ctags:303:ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include /304:lib_generic board /$ (BOARDDIR) cpu /$(CPU) lib_$(ARCH) /305: fs/cramfs fs/fat fs/fdos fs/jffs2 /306: 网盘 rtc dtt 驱动 drivers/sk98lin common /307 :/( [k4 ]名称 CVS -修剪 /) -o /( -name "*.[ch]" -print /)`308:309:etags:310:etags- a -o $( OBJTREE)/etags `find $(SUBDIRS) include /311:lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) /312:fs/cramfs fs/fat fs/fdos fs/jffs2 /313:net 光盘 rtc dtt 驱动程序 drivers/sk98lin common /314: /( -name CVS -prune /) -o /( -name "*.[ch]" -print /)`315:316: $(obj)System.map:$(obj)u-boot317:@$(NM) $ $(obj)System.map320: 321 :################################################################################################## ##################322: else323: 所有 $(obj)u-boot. 十六进制 $(obj)u-boot. srec $(obj)u-boot.bin /324:$(obj)u-boot.img $(obj)u-boot.dis $(obj)u-boot /325:$ (SUBDIRS) 版本 gdbtools updater env dependent /326: dep 标签 ctags etags $(obj)System.map:327: @echo "系统未配置 - 请参阅自述文件" >&2328: @ exit 1329: endif330:331: .PHONY: CHANGELOG332: CHANGELOG:333: git log --no-合并 U-Boot-1_1_5.. | /334: 展开 -a | sed -e "s//s/s*$$//" > $@335:336:########################## # ############################################337: 338: 取消配置: 339: @rm -f $(obj)include/config.h $(obj)include/config.mk /340: $(obj)board/*/config.tmp $(obj)board/ */ * /config. tmp341:

在上述代码的第 169 行中,OBJS 的第一个值为“cpu/ $(CPU )/start. o”或“cpu/s3c64xx/start.o”。 根据上一行的注释,u-boot的OBJS(目标)非常重要,start.o应该放在第一位。 ,即先编译start.s。 上面代码中的第 170-191 行针对的是其他架构的 CPU,在这里没什么用处。

注意:

175-第 177 行代码不包含在 U-Boot1.1.6-for-OK6410 源代码中。 理论上?会有影响吗?

代码第193到218行中,LIBS变量为U-所需的库指定文件。 Boot包含平台/开发板相关目录以及通用目录中的相应库通过相应的子目录进行编译。 第 215 行定义了一个伪目标 (.PHONY: $(LIBS)),该目标预计存在于当前目录中。 如果LIBS变量(即U-Boot所需的库文件,.a文件)有相应的值,则不会显示“*.a is up-to-date”,此时将重新启动。你运行它。 编译生成对应的.a文件。

注意:第 208-209 行之间,U-Boot1.1.6- 为 [ k4] OK6410源代码中已添加以下代码:

# 添加支持onenand。 scsuhLIBS += drivers/onenand/libonend.aifeq ($(CPU),mpc83xx)LIBS += drivers/qe/qe .aendif 添加了对 onenand flash 的支持。

第 228-231 行是与平台无关的代码。 这是因为部分开发板(包括OK6410)支持u-boot。 用nand flash启动。 可以在这些开发板配置文件中定义 CONFIG_NAND_U_BOOT 宏,以确保第 239 行的 U_BOOT_NAND 依赖项永远不为空。 239行代码运行make all后生成u-boot.srec、u-boot.bin和Sys。温度图。 其中,u-boot.srec是Motorola S-Record格式文件,System.map是U-Boot符号表,u-boot.bin是最终的二进制可执行文件。一个文件。 烧入开发板。 文档。 如果U_BOOT_NAND不为空,还会生成u-boot-nand.bin文件。

OBJS 和 LIBS 表示的 .o 和 .a 文件是 U-boot 的组件。 268-272 通过line命令从相应的源文件(或相应子目录下的文件)编译而来。 第 268-269 行的规则表示通过进入 cpu/$(CPU) 目录(即 cpu/s3c64xx)来编译 OBJS 的每个成员。 对于smdk6410开发板,OBJS为cpu/s3c64xx/start.o,由cpu/s3c64xx/start.S编译而成。 第 271-272 行的规则表示进入相应的子目录并为 LIBS 的每个成员运行“make”命令。 这些子目录中的 Makefile 具有类似的结构。 编译 Makefile 中指定的文件并将它们链接到库文件。

一旦生成了 OBJS 和 LIBS 表示的所有 .o 和 .a 文件,我将最终连接。 上述代码的第243行到第267行。 首先利用第262-行和第266行的规则链接得到ELF格式的U-BOOT,最后将其转换为二进制格式的u-boot.bin和S-我会的。 U-Boot.srec(即243-261行)用于记录格式等 下面介绍ELF格式的U-Boot的依赖关系。/p> 依赖目标 dependent

行为取决于目标依赖规则。 关于第300行$(SUBDIRS),如果进入该目录并运行“make _depend”,将为每个子目录生成一个.depend文件。 .depend 列出每个目标文件的依赖文件。

依赖SUBDIRS

我们不引入版本依赖,即U-Boot的版本。 单击此处了解更多信息。 274-275 的行为取决于 SUBDIRS 的规则。 因为定义了SUBDIRS 222-226的值,所以会执行tools、example、post、post/cpu目录下的Makefile。

对 OBJS 和 LIBS 的依赖

上面解释了这两个依赖关系。

依赖于 LDSCRIPT

此依赖关系由顶级 config.mk 文件和 LDSCRIPT 的值决定。它在顶级目录 /board/Samsung/smdk6410/u-boot.lds 中定义。

U-BOOT规则命令第264-266行将实际连接LDFLAGS设置为Show 。 如何连接,我检查了LDFLAGS中的“/board/Samsung/smdk6410/u-boot.lds”和“-Ttext 0xCFE00000”字样(根据顶级c)onfig.mk 文件),这些字指定程序的布局和地址(其中连接起始地址是连接脚本内的偏移地址0+0xCFE00000)。 因此 $(LDFLAGS) 使用 u-boot.lds 链接脚本和 -Ttext 0xCFE00000。 实际执行连接命令时,start.o中生成的库文件和各个子目录makefile按照LDFLAGS进行连接,得到ELF文件u-boot和连接内存分配映射文件u-boot.map将被生成。

注意:上述代码的第 250 行和第 251 行之间, U-Boot1 .1.6[k4 ] for-OK6410 在源代码中添加了一行代码:$(OBJDUMP) -d $ $

未经允许不得转载:主机频道 » 基于ARM处理器的U-BOOT详细移植概述(arm uboot)

评论 抢沙发

评论前必须登录!