一、uboot 主Makefile分析1
1、uboot version 确定(Makefile 的 24-29 行)
(1) uboot 的版本号分 3 个级别:
VERSION:主板本号
PATCHLEVEL:次版本号
SUBLEVEL:再次版本号
EXTRAVERSION : 另外附加的版本信息
这4个用 .
分隔开,共同构成了最终的版本号。
(2) Makefile 中版本号最终生成了一个变量 U_BOOT_VERSION
,这个变量记录了 Makefile 中配置的版本号。
(3) include/version_autogenerated.h
文件是编译过程中自动生成的一个文件,所以源目录中没有,但是编译过后的 uboot 中就有了。它里面的内容是一个宏定义,宏定义的值内容就是我们在 Makefile 中配置的 uboot 的版本号。
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# cat include/version_autogenerated.h
#define U_BOOT_VERSION "U-Boot 1.3.4"
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot#
(4) 验证方法:自己修改主 Makefile 中几个 Version 有关的变量,然后重新编译 uboot,然后烧录到 SD 卡中,从 SD 卡启动,然后去看启动时 uboot 打印出来的版本信息,看看变化是不是和自己的分析一致。
2、HOSTARCH 和 HOSTOS
(1) 直接在 shell 中执行 uname -m
得到 i686,得到的值其实就是你当前执行这个命令的电脑的 CPU 的版本号。
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# uname -m
i686
于是,Makefile 会把 i686 替换为 i386。
(2) shell 中的 |
叫做管道,管道的作用就是把管道前面一个运算式的输出作为后面一个的输入再去做处理,最终的输出才是我们整个式子的输出。
(3) HOSTARCH
这个名字:HOST 是主机,就是当前在做开发用的这台电脑就叫主机;ARCH 是architecture (架构)的缩写,表示 CPU 的架构。所以 HOSTARCH
就表示主机的 CPU 的架构。
(4) 这两个环境变量是主机的操作系统和主机的CPU架构,得出后保存备用,后面自然会用到。
二、uboot 主Makefile分析2
1、静默编译(50-54行)
(1) 平时默认编译时,命令行会打印出来很多编译信息。但是有时候我们不希望看到这些编译信息,就后台编译即可。这就叫静默编译。
(2) 使用方法就是编译时 make -s
,-s
会作为 MAKEFLAGS 传给 Makefile,在 50-54 行这段代码作用下 XECHO 变量就会被变成空(默认等于 echo ),于是实现了静默编译。
ifeq (,$(findstring s,$(MAKEFLAGS)))
的理解:
,
前面为空,表示空字符串。$(findstring s,$(MAKEFLAGS))
查找 Makefile 的选项参数,如果没有s(表示 slient)
,则该语句$(findstring s,$(MAKEFLAGS))
结果为空字符串。
2、2 种编译方法(原地编译和单独输出文件夹编译)
(1) 编译复杂项目,Makefile 提供 2 种编译管理方法。默认情况下是当前文件夹中的 .c 文件,编译出来的 .o 文件会放在同一文件夹下。这种方式叫原地编译。原地编译的好处就是处理起来简单。
(2) 原地编译有一些坏处:第一,污染了源文件目录。第二的缺陷就是一套源代码只能按照一种配置和编译方法进行处理,无法同时维护 2 个或 2 个以上的配置编译方式。
(3) 为了解决以上 2 种缺陷,uboot 支持单独输出文件夹方式的编译(linux kernel 也支持,而且uboot 的这种技术就是从 linux kernel 学习来的)。基本思路就是在编译时另外指定一个输出目录,将来所有的编译生成的 .o 文件或生成的其他文件全部丢到那个输出目录下去。源代码目录不做任何污染,这样输出目录就承载了本次配置编译的所有结果。
(4) 具体用法:默认的就是原地编译。如果需要指定具体的输出目录编译则有 2 种方式来指定输出目录。(具体参考 Makefile 56-76 行注释内容)
第一种:make O=输出目录
make O=/tmp/build all
第二种:export BUILD_DIR=输出目录 然后再 make
export BUILD_DIR=/tmp/build
make
如果两个都指定了(既有 BUILD_DIR 环境变量存在,又有 O=xx),则 O=xx 具有更高优先级,听他的。
Command line 'O=' setting overrides BUILD_DIR environent variable.
(5) 两种编译的实现代码在 Makefile 的78-123 行。
3、编译方法实践
实践发现,九鼎官方移植的 uboot 貌似有一些错误。。。
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# cat mk
#!/bin/sh
make distclean
make x210_sd_config
make -j4
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make distclean
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make x210_sd_config O=/mytmp_output
Configuring for x210_sd board...
/bin/sh: 1: cannot create /mytmp_output/board/samsung/x210/config.mk: Directory nonexistent
make: *** [x210_sd_config] Error 2
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make O=mytmp_output distclean
rm -rf /home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/*
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make O=mytmp_output x210_sd_config
Configuring for x210_sd board...
/bin/sh: 1: cannot create /home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/board/samsung/x210/config.mk: Directory nonexistent
make: *** [x210_sd_config] Error 2
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# mkdir -p mytmp_output/board/samsung/x210
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot#
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make O=mytmp_output x210_sd_config
Generating /home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include/autoconf.mk.dep
Generating /home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include/autoconf.mk
Configuring for x210_sd board...
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot#
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# make O=mytmp_output -j8 -s
start.S:33: fatal error: regs.h: No such file or directory
compilation terminated.
nand_cp.c:44: fatal error: regs.h: No such file or directory
compilation terminated.
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include2/asm/hardware.h:16: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
usb_ohci.c:45: fatal error: regs.h: No such file or directory
compilation terminated.
interrupts.c:40: fatal error: regs.h: No such file or directory
compilation terminated.
cpu.c:36: fatal error: regs.h: No such file or directory
compilation terminated.
usbd-otg-hs.c:30: fatal error: regs.h: No such file or directory
compilation terminated.
start.S:33: fatal error: regs.h: No such file or directory
compilation terminated.
make[1]: *** [start.o] Error 1
make: *** [/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/cpu/s5pc11x/libs5pc11x.a] Error 2
make: *** Waiting for unfinished jobs....
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include2/asm/hardware.h:16: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
setup_hsmmc.c:2: fatal error: regs.h: No such file or directory
compilation terminated.
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include2/asm/hardware.h:16: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/include/fastboot.h:66: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
start.S:33: fatal error: regs.h: No such file or directory
compilation terminated.
make[1]: *** [/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/cpu/s5pc11x/start.o] Error 1
make: *** [/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/cpu/s5pc11x/start.o] Error 2
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include2/asm/hardware.h:16: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/include2/asm/hardware.h:16: fatal error: asm/arch/hardware.h: No such file or directory
compilation terminated.
make[1]: *** No rule to make target `.depend', needed by `all'. Stop.
make: *** [/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot/mytmp_output/cpu/s5pc11x/s5pc110/libs5pc110.a] Error 2
bmp_logo.c: In function ‘main’:
bmp_logo.c:71:8: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result [-Wunused-result]
fread (&data_offset, sizeof (uint16_t), 1, fp);
^
bmp_logo.c:73:8: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result [-Wunused-result]
fread (&b->width, sizeof (uint16_t), 1, fp);
^
bmp_logo.c:75:8: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result [-Wunused-result]
fread (&b->height, sizeof (uint16_t), 1, fp);
^
bmp_logo.c:77:8: warning: ignoring return value of ‘fread’, declared with attribute warn_unused_result [-Wunused-result]
fread (&n_colors, sizeof (uint16_t), 1, fp);
^
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot#
三、uboot 主Makefile分析3
1、OBJTREE、SRCTREE、TOPDIR
(1) OBJTREE:理解为:目标 Directory Tree。编译出的 .o 文件存放的目录的根目录。在默认编译下,OBJTREE 等于当前目录;在 O=xx 编译下,OBJTREE 就等于我们设置的那个输出目录。
(2) SRCTREE: 源码目录,其实就是源代码的根目录,也就是当前目录。
总结:在默认编译下,OBJTREE 和 SRCTREE 相等;在 O=xx 这种编译下,OBJTREE 和 SRCTREE 不相等。Makefile 中定义这两个变量,其实就是为了记录编译后的 .o 文件往哪里放,就是为了实现 O=xx 的这种编译方式的。
2、MKCONFIG(Makefile 的 101 行)
(1) Makefile 中定义的一个变量(在这里定义,在后面使用),它的值就是我们源码根目录下面的 mkconfig
。这个 mkconfig
是一个脚本,这个脚本就是 uboot 配置阶段的配置脚本。后面要用至少 3 节课详细讲这个配置脚本的工作。
3、include $(obj)include/config.mk(133 行)
(1) include/config.mk
不是源码自带的(你在没有编译过的源码目录下是找不到这个文件的),要在配置过程(make x210_sd_config
)中才会生成这个文件。因此这个文件的值和我们配置过程有关,是由配置过程根据我们的配置自动生成的。
(2) 我们 X210 在 iNand 情况下配置生成的 config.mk 内容为:
ARCH = arm
CPU = s5pc11x
BOARD = x210
VENDOR = samsung
SOC = s5pc110
(3) 我们在下一行(134行)export 导出了这 5 个变量作为环境变量。所以这两行加起来其实就是为当前 makefile 定义了 5 个环境变量而已。之所以不直接给出这 5 个环境变量的值,是因为我们希望这 5 个值是可以被人很容易的、集中的配置的。
(4) 这里的配置值来自于 2589 行那里的配置项。如果我们要更改这里的某个配置值要到 2589 行那里调用 MKCONFIG 脚本传参时的参数。
4、ARCH CROSS_COMPILE
(1) 接下来有 2 个很重要的环境变量。一个是 ARCH
,上面导出的,值来自于我们的配置过程,它的值会影响后面的 CROSS_COMPILE
环境变量的值。ARCH 的意义是定义当前编译的目标 CPU 的架构。
(2) CROSS_COMPILE
是定义交叉编译工具链的前缀的。定义这些前缀是为了在后面用(用前缀加上后缀来定义编译过程中用到的各种工具链中的工具)。我们把前缀和后缀分开还有一个原因就是:在不同 CPU 架构上的交叉编译工具链,只是前缀不一样,后缀都是一样的。因此定义时把前缀和后缀分开,只需要在定义前缀时区分各种架构即可实现可移植性。
(3) CROSS_COMPILE
在 136-182 行来确定。CROSS_COMPILE 是被 ARCH 所确定的,只要配置了ARCH=arm
,那么我们就只能在 ARM 的那个分支去设置 CROSS_COMPILE
的值。这个设置值只要能保证找到那个交叉编译工具链即可,不一定非得是全路径的,相对路径也可以。(如果已经将工具链导出到环境变量,并且设置了符号链接,这样 CROSS_COMPILE = arm-linux-
就可以)
(4)实际运用时,我们可以在 Makefile 中去更改设置 CROSS_COMPILE
的值,也可以在编译时用 make CROSS_COMPILE=xxxx
来设置,而且编译时传参的方法可以覆盖 Makefile 里面的设置。
四、uboot 主Makefile分析4
1、$(TOPDIR)/config.mk(主 Makefile 的 185 行)
2、编译工具定义(config.mk 94-107行)
3、包含开发板配置项目(config.mk, 112行)
(1) autoconfig.mk
文件不是源码提供的,是配置过程自动生成的。
(2) 这个文件的作用就是用来指导整个 uboot 的编译过程。这个文件的内容其实就是很多 CONFIG_
开头的宏(可以理解为变量),这些宏/变量会影响我们 uboot 编译过程的走向(原理就是条件编译)。在 uboot 代码中有很多地方使用条件编译进行编写,这个条件编译是用来实现可移植性的。(可以说 uboot 的源代码在很大程度来说是拼凑起来的,同一个代码包含了各种不同开发板的适用代码,用条件编译进行区别。)
(3) 这个文件不是凭空产生的,配置过程也是需要原材料来产生这个文件的。原材料在源码目录的 inlcude/configs/xxx.h
头文件。(X210 开发板中为 include/configs/x210_sd.h
)。这个 h 头文件里面全都是宏定义,这些宏定义就是我们对当前开发板的移植。每一个开发板的移植都对应这个目录下的一个头文件,这个头文件里每一个宏定义都很重要,这些配置的宏定义就是我们移植 uboot 的关键所在。
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# ls include/configs/
x210_nand.h x210_sd.h
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot# cat include/configs/x210_sd.h | more
/*
* (C) Copyright 2002
* Sysgo Real-Time Solutions, GmbH <www.elinos.com>
* Marius Groeger <mgroeger@sysgo.de>
* Gary Jennejohn <gj@denx.de>
* David Mueller <d.mueller@elsoft.ch>
*
* Configuation settings for the SAMSUNG SMDK6400(mDirac-III) board.
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#ifndef __CONFIG_H
#define __CONFIG_H
//#define FPGA_SMDKC110
//定义CONFIG_CHECK_X210CV3,则为工装检测模式,不定义,为正常启动模式
//#define CONFIG_CHECK_X210CV3
/*
* High Level Configuration Options
* (easy to change)
*/
#define CONFIG_MPAD 1 //lxg added
#define CONFIG_S5PC110 1 /* in a SAMSUNG S3C6410 SoC */
#define CONFIG_S5PC11X 1 /* in a SAMSUNG S3C64XX Family */
#define CONFIG_X210 1
#define CONFIG_MCP_SINGLE 1
#define CONFIG_EVT1 1 /* EVT1 */
//#define CONFIG_SMDKV210_REV02 1 /* Rev 0.2 and PMIC Type is MAX8998 */
#define CONFIG_FASTBOOT 1
//#define CONFIG_FUSED 1 /* Fused chip */
//#define CONFIG_SECURE_BOOT 1 /* secure booting */
#define CONFIG_SW_WORKAROUND 1 /* Software around */
#if defined(CONFIG_SW_WORKAROUND)
#define CONFIG_CHECK_MPLL_LOCK 1 /* Check MPLL is locked */
#endif
#if defined(CONFIG_SECURE_BOOT)
#define CONFIG_SECURE_KERNEL_BASE 0x20008000
#define CONFIG_SECURE_KERNEL_SIZE 0x00271000
#define CONFIG_SECURE_ROOTFS_BASE 0x30A00000
#define CONFIG_SECURE_ROOTFS_SIZE 0x0013D000
#endif
#define BOOT_ONENAND 0x1
#define BOOT_NAND 0x2
#define BOOT_MMCSD 0x3
#define BOOT_NOR 0x4
#define BOOT_SEC_DEV 0x5
#define AT070TN92 1
#define VGA_800X600 2
#define VGA_1024X768 3
#define TRULY043 4
#define VGA_1440X900 5
#define VGA_1280X1024 6
#define DISP_MODE AT070TN92
//#define DISP_MODE TRULY043
//#define DISP_MODE VGA_800X600
//#define DISP_MODE VGA_1024X768
//#define DISP_MODE VGA_1440X900
//#define DISP_MODE VGA_1280X1024
/* skip to load BL2 */
//#define FAST_BOOT 1
#define MEMORY_BASE_ADDRESS 0x30000000
//#define MEMORY_BASE_ADDRESS 0x20000000
#define MEMORY_BASE_ADDRESS2 0x40000000
/* input clock of PLL */
#define CONFIG_SYS_CLK_FREQ 24000000 /* the SMDK6400 has 24MHz input clock */
#define CONFIG_ENABLE_MMU
#ifdef CONFIG_ENABLE_MMU
#define virt_to_phys(x) virt_to_phy_smdkc110(x)
#else
#define virt_to_phys(x) (x)
#endif
#define CONFIG_MEMORY_UPPER_CODE
#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
#define CONFIG_INCLUDE_TEST
#define CONFIG_ZIMAGE_BOOT
#define CONFIG_IMAGE_BOOT
#define BOARD_LATE_INIT
#define CONFIG_SETUP_MEMORY_TAGS
#define CONFIG_CMDLINE_TAG
#define CONFIG_INITRD_TAG
/*
* Architecture magic and machine type
*/
#define MACH_TYPE 2456
#define UBOOT_MAGIC (0x43090000 | MACH_TYPE)
/* Power Management is enabled */
#define CONFIG_PM
#define CONFIG_DISPLAY_CPUINFO
#define CONFIG_DISPLAY_BOARDINFO
root@ubuntu:/home/aston/workspace/uboot_bsp/uboot_jiuding/uboot#
五、uboot 主Makefile分析5
1、链接脚本(config.mk 142-149 行)
(1) 如果定义了 CONFIG_NAND_U_BOOT
宏,则链接脚本叫 u-boot-nand.lds ,如果未定义这个宏则链接脚本叫 u-boot.lds
。
(2) 从字面意思分析,即可知:CONFIG_NAND_U_BOOT
是在 Nand 版本情况下才使用的,我们使用的 X210 都是 iNand 版本的,因此这个宏没有的。
(3) 实际在 board\samsung\x210
目录下有 u-boot.lds
,这个就是链接脚本。我们在分析 uboot 的编译链接过程时就要考虑这个链接脚本。
2、TEXT_BASE(config.mk 156-158行)
(1) Makefile 中在配置 X210 开发板时,在 board/samsung/x210
目录下生成了一个文件 config.mk
,其中的内容就是:TEXT_BASE = 0xc3e00000
相当于定义了一个变量。
(2) TEXT_BASE
是将来我们整个 uboot 链接时指定的链接地址。因为 uboot 中启用了虚拟地址映射,因此这个 C3E00000 地址就等于 0x23E00000
(也可能是 33E00000 具体地址要取决于 uboot 中做的虚拟地址映射关系)。
(3) 回顾裸机中讲的链接地址的问题,再想想 dnw 方式先下载 x210_usb.bin 然后再下载 uboot.bin 时为什么第二个地址是 23E00000 .
3、自动推导规则(config.mk 239-256行)
(1) 我们在讲 Makefile 时提到过自动推导规则,具体理解可以参考《跟我一起学Makefile》
六、uboot 主Makefile分析6
(1) 291 行出现了整个主 Makefile 中第一个目标 all(也就是默认目标,我们直接在 uboot 根目录下 make 其实就等于 make all,就等于 make 这个目标)
(2) 目标中有一些比较重要的。譬如:u-boot 是最终编译链接生成的 elf 格式的可执行文件。
(3) unconfig 字面意思来理解就是未配置。这个符号用来做为我们各个开发板配置目标的依赖。目标是当我们已经配置过一个开发板后再次去配置时还可以配置。
(4) 我们配置开发板时使用:make x210_sd_config
,因此分析 x210_sd_config 肯定是主 Makefile 中的一个目标。
源自朱有鹏老师.