Zero-distance initial experience of uboot source code analysis (based on S5PV210)

1. S5PV210 official uboot configuration compilation practice

1. Find the official (SOC/development board manufacturer) transplanted uboot

(1) The source code of the source is downloaded from the uboot official website. The downloaded source code may not have the porting of the development board you are currently using, or even the porting version corresponding to the SoC used by the current development board.

(2) After the SoC manufacturer launches a SoC, the manufacturer's engineers will go to the uboot official website to download a uboot, and perform the first step of transplantation based on their own SoC. The target of the transplantation is the development board launched by the manufacturer. (For example, the development board produced by Samsung's S5PV210 chip manufacturer is called SMDKV210). So the uboot transplanted by Samsung's engineers is based on their own SMDKV210 development board.

(3) Specific development board suppliers (such as Shenzhen Jiuding Technology, the manufacturer of X210) first purchase Samsung’s SMDKV210 development board, and then cut it out (cut out some useless interface functions, reduce the configuration, and some configurations will be replace). The new development board (such as X210) generated after hardware replacement and cutting is different from Samsung's official SMDKV210, so uboot is also different. But because the SoC is the same, the similarity is at least 60%. Therefore, the specific development board supplier will use the uboot transplanted in Samsung SMDKV210 as the blueprint to obtain a uboot transplantation of its own development board.

Summary: There are three ways to obtain uboot: uboot official, SoC official, and specific development board official.

2. Configure and compile under ubuntu

(1) BSP is the board support package (board-level support package, generally provided by the development board supplier), which contains all relevant source codes, documents, tutorials, etc. of the development board.

(2) Get the entire BSP package file to the source directory of linux to decompress and analyze, do not decompress it in the shared folder in windows. (Unless your code is only analyzed in windows and not compiled, if you want to compile the project, it must not be in the windows shared folder, otherwise an error will occur)

(3)tar -jxvf qt_x210v3_130807.tar.bz2

(4) We maintain a uboot under linux (ubuntu), and a uboot under windows. Before we start any work, the contents of these two uboots are the same. We do this for the purpose of compiling in linux and analyzing and viewing codes in windows. (There are very good tools such as SourceInsight under windwos to assist us in viewing and editing codes, compiling and viewing codes under linux is very troublesome...)

(5) Configuration

(1)uboot和linux kernel等复杂项目,都不能直接编译,都要先配置才能编译。
(2)uboot也要先配置,配置方法是(以我的开发板为例):首先cd进入uboot源码的根目录,
然后在根目录下执行:make x210_sd_config。执行配置命令后,如果出现:Configuring 
for x210_sd board...说明配置好了,如果不是这个是别的说明配置出错了

(6) Compile to get uboot.bin

(1)编译之前一定要注意检查arm-linux-gcc对不对,检查份2步:
	第一步:检查当前编译环境中有没有安装合适的arm-linux-gcc。我装的是arm-2009q3,
因为这个是三星官方、开发板厂商官方开发uboot时使用的。
	第二步:检查当前目录下(uboot根目录)的Makefile中编译器的设置是否正确。在工
程的总Makefile中会设置交叉编译工具链的路径和名字,必须确保这个路径和名字和我们自
己装的一致,否则编译会出错。

(2)确保了以上2点,即可进行编译。编译很简单,直接make即可。或者可以make -j4 (多线
程编译,主机如果是多核心电脑,可以尝试多线程编译,会快一些)

Two, uboot source code directory analysis

1. Comparison between the uboot provided by the development board manufacturer and Samsung's original uboot

(1) I learned from the uboot provided by the development board manufacturer, and compared it with Samsung's official one.

(2) Different versions of uboot or the same version of uboot transplanted by different people may have different directory structures and file contents. In the future, after you understand it, you can also add/delete/change the directory structure according to your needs.

(3) When the development board manufacturer uses Samsung's uboot as the raw material for transplantation, many unnecessary folders and files in the Samsung version of uboot may be deleted. This deletion clears out many files that are not used at all, reducing the overall number of files and making it easier to work.
insert image description here
insert image description here

2. Introduction to each file (take the uboot of the development board manufacturer Jiuding Technology as an example)

(1).gitignore,git工具的文件,git是一个版本管理工具(类似的还有个svn),这个文件
和git有关,和uboot本身无关的,不用去管。

(2)arm_config.mk,后缀是.mk,是一个Makefile文件,将来在某个Makefile中会去调用它。

(3)三个Changelog文件,修改记录文件,该文件记录了这个uboot项目的版本变迁以及每个
版本较上个版本修改的记录。正式的项目都有这些记录的。可以直接忽略,主要是给维护
uboot的人用的。

(4)config.mk,和arm_config.mk差不多性质。

(5)COPYING,版权声明,uboot本身是GPL许可证的。

(6)CREDITS,鸣谢,里面记录了对uboot有贡献的人,感谢目录。

(7)image_split,一个脚本,用来分割uboot.bin到BL1的。

(8)MAINTAINERS,维护者,就是当前在参与维护uboot源码的社区工作者。

(9)MAKEALL,一个脚本,应该是帮助编译uboot的。

(10)Makefile,这个很重要,是uboot源代码的主Makefile,将来整个uboot被编译时就是
用这个Makefile管理编译的。

(11)mk,快速编译的脚本,其实就是先清理然后配置然后编译而已。

(12)mkconfig,这个很重要,是uboot配置阶段的主要配置脚本。uboot的可移植性很大程度
就是靠这个配置脚本在维护的。

(13)mkmovi,一个脚本,和iNand/SD卡启动有关

(14)README,所有的软件都有README,一般拿到一个东西要先读README,这个东西其实就
是个简单的使用说明书。

(15)rules.mk,这个文件是我们uboot的Makefile使用的规则,本身非常重要,但是我们
不去分析他,不去看他。

  Summary: Among the above files, there are two that are more important to us and need to be carefully read: mkconfig and Makefile. One is responsible for the configuration of uboot, and the other is responsible for compiling .

3. Introduction to each folder

(1)api,硬件无关的功能函数的API。uboot移植时基本不用管,这些函数是uboot本身使用
的。

(2)api_examples,API相关的测试事例代码。

(3)board,board是板的意思,板就是开发板。board文件夹下每一个文件都代表一个开发板,这个文件夹下面放的文件就是用来描述这一个开发板的信息的。board目录下有多少个文件夹,
就表示当前这个uboot已经被移植到多少个开发板上了(当前的uboot支持多少个开发板)。

Question 1: There are so many folders under the board, how to determine which one to use?
  During the configuration phase, uboot will have some means to help us determine which folder under the board directory to use. (Think about why you can't compile directly but configure first)

Question 2: There are more and more development boards, and there are more and more folders in the board directory, which is inconvenient to manage and control. How to solve it

  So uboot has added a new mechanism, which can not directly put the development board directory under the board directory, but put the manufacturer directory (vendor directory, named after the specific chip manufacturer) under the board, and then put all the chips of this IC manufacturer The development boards are thrown under the vendor directory.

  The development board directory corresponding to X210 is board/samsung/x210. Adding this level of directory will affect the configuration stage. In the uboot configuration stage, pay attention to the corresponding path depth during configuration and actual storage. Otherwise, the file cannot be found during compilation after configuration, and the compilation will fail. Pay attention to a detail that is the compatibility trouble caused by historical reasons. At the beginning, the name of the development board was in the board directory, but it was changed to the name of the manufacturer later. However, due to forward compatibility, the same manufacturer's original development boards were not moved to the manufacturer's directory. This makes the later people feel very strange and confused because they don't know the whole story.

  Note: To emphasize, the configuration phase of uboot (actually the mkconfig script under the root directory and the configuration related parts in the Makefile) mainly solves the problem in the field of portability, which can help us determine the path of the specific folder, and then compile The files that should be found can be found in order to compile successfully. Therefore, the difference in the board directory will cause the difference in configuration. If you don't pay attention to this when transplanting, you will definitely fail.

(4)common。common是普遍的普通的,这个文件夹下放的是一些与具体硬件无关的普遍适用的一些代码。譬如控制台实现、crc校验的。但是更多的主要是两类:一类是cmd开头的,是用来实现uboot的命令系统的;另一类是env开头的,是用来实现环境变量的。

(5)cpu。这个目录是SoC相关的,里面存放的代码都是SoC相关初始化和控制代码(譬如CPU的、中断的、串口等SoC内部外设的,包括起始代码start.S也在这里)。里面很多子文件夹,每一个子文件夹就是一个SoC系列。

注意:这个问价是严格和硬件相关的,因此移植时也是要注意的。但是因为这个文件夹内都是SoC有关的,我们自己的开发板和三星的开发板虽然板子设计不同但是SoC都是同一个,因此实际移植时这个目录几乎不用动。

(6)disk。磁盘有关的,没研究过,没用过。

(7)doc。文档目录,里面存放了很多uboot相关文档,这些文档可以帮助我们理解uboot代码。但是因为是纯英文的,而且很杂乱,所以几乎没用。

(8)drivers。顾名思义,驱动。这里面放的就是从linux源代码中扣出来的原封不动的linux设备驱动,主要是开发板上必须用到的一些驱动,如网卡驱动、Inand/SD卡、NandFlash等的驱动。要知道:uboot中的驱动其实就是linux中的驱动,uboot在一定程度上移植了linux的驱动给自己用。但是linux是操作系统而uboot只是个裸机程序,因此这种移植会有不同,让我说:uboot中的驱动其实是linux中的驱动的一部分。

(9)examples。示例代码,没用过。

(10)fs。filesystem,文件系统。这个也是从linux源代码中移植过来的,用来管理Flash等资源。

(11)include。头文件目录。uboot和linux kernel在管理头文件时都采用了同一个思路,就是把所有的头文件全部集中存放在include目录下,而不是头文件跟着自己对应的c文件。所以在uboot中头文件包含时路径结构要在这里去找。

(12)lib_开头的一坨。(典型的lib_arm和lib_generic)架构相关的库文件。譬如lib_arm里面就是arm架构使用的一些库文件。lib_generic里是所有架构通用的库文件。这类文件夹中的内容移植时基本不用管。

(13)libfdt。设备树有关的。linux内核在3.4左右的版本的时候更改了启动传参的机制,改用设备树来进行启动传参,进行硬件信息的描述了。

(14)nand_spl。nand相关的,不讲。

(15)net。网络相关的代码,譬如uboot中的tftp nfs ping命令 都是在这里实现的。

(16)onenand开头的,是onenand相关的代码,是三星加的,标准uboot中应该是没有的。

(17)post。没关注过,不知道干嘛的。

(18)sd_fusing。这里面代码实现了烧录uboot镜像到SD卡的代码。后面要仔细研究的。

(19)tools。里面是一些工具类的代码。譬如mkimage。

Summary: The folders are more important, which will be analyzed later: board, common, cpu, drivers, include, lib_arm, lib_generic, sd_fusing

Three, uboot main Makefile analysis

分析Makefile比较大,故将链接放在这,务必下载后结合博客文章学习分析:

「Makefile」https://www.aliyundrive.com/s/fkNHpf17Ut8
点击链接保存,或者复制本段内容,打开「阿里云盘」APP ,无需下载极速在线查看,
视频原画倍速播放。

1. Confirm the uboot version (lines 24-29 of Makefile)

(1) The version number of uboot is divided into 3 levels:

VERSION:主板本号
PATCHLEVEL:次版本号
SUBLEVEL:再次版本号
EXTRAVERSION:另外附加的版本信息
这4个用.分隔开共同构成了最终的版本号。

(2) The version number in the Makefile finally generates a variable U_BOOT_VERSION, which records the version number configured in the Makefile.

(3) The include/version_autogenerated.h file is a file automatically generated during the compilation process, so it is not in the source directory, but it is in the compiled uboot. The content inside it is a macro definition, and the value content of the macro definition is the version number of uboot we configured in the Makefile.

(4) Verification method: Modify several Version-related variables in the main Makefile by yourself, then recompile uboot, then burn it into the SD card, start from the SD card, and then look at the version information printed by uboot during startup. Is the change consistent with your own analysis?

VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 4
EXTRAVERSION =
U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
VERSION_FILE = $(obj)include/version_autogenerated.h

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

HOSTOS := $(shell uname -s | tr '[:upper:]' '[:lower:]' | \
	    sed -e 's/\(cygwin\).*/cygwin/')

export	HOSTARCH HOSTOS

# Deal with colliding definitions from tcsh etc.
VENDOR=

#########################################################################
# Allow for silent builds
ifeq (,$(findstring s,$(MAKEFLAGS)))
XECHO = echo
else
XECHO = :
endif

2. HOSTARCH and HOSTOS

(1) Execute uname -m directly in the ubuntu command line (shell) to get i686. The obtained value is actually the version number of the CPU of the computer you are currently executing this command on.

(2) The "|" in the shell is called a pipeline. The function of the pipeline is to use the output of the previous calculation formula of the pipeline as the input of the next one for processing, and the final output is the output of our entire formula.

(3) The name HOSTARCH: HOST is the host, that is, the computer currently being used for development is called the host; ARCH is the abbreviation of architecture (architecture), which means the architecture of the CPU. So HOSTARCH represents the CPU architecture of the host.

(4) These two environment variables are the operating system of the host and the CPU architecture of the host, which are saved for later use after being obtained.

3. Compile silently (lines 50-54)

(1) Usually, the command line will print out a lot of compilation information when compiling by default. But sometimes we don't want to see these compilation information, just compile in the background. This is called silent compilation.

(2) The method of use is make -s when compiling, and -s will be passed to Makefile as MAKEFLAGS, and the XECHO variable will be empty under the action of this code in line 50-54 (default is equal to echo), so silent compilation is realized .

4. Two compilation methods (in-place compilation and compilation with separate output folder)

(1) To compile complex projects, Makefile provides two compilation management methods. By default, it is the .c file in the current folder, and the compiled .o file will be placed in the same folder. This method is called in-place compilation. The advantage of in-place compilation is that it is easy to handle .

(2) In-place compilation has some disadvantages: First, it pollutes the source file directory. The second defect is that a set of source code can only be processed according to one configuration and compilation method, and two or more configuration and compilation methods cannot be maintained at the same time.

(3) In order to solve the above two defects, uboot supports the compilation of a separate output folder (linux kernel also supports, and this technology of uboot is learned from linux kernel). The basic idea is to specify an additional output directory when compiling, and throw all the .o files or other files generated by compilation into that output directory in the future. The source code directory does not do any pollution, so the output directory carries all the results of this configuration compilation .

(4) Specific usage: The default is to compile in place. If you need to specify a specific output directory for compilation, there are 2 ways to specify the output directory. (For details, refer to the comments on lines 56-76 of Makefile)

#########################################################################
#
# U-boot build supports producing a object files to the separate external
# directory. Two use cases are supported:
#
# 1) Add O= to the make command line
# 'make O=/tmp/build all'
#
# 2) Set environement variable BUILD_DIR to point to the desired location
# 'export BUILD_DIR=/tmp/build'
# 'make'
#
# The second approach can also be used with a MAKEALL script
# 'export BUILD_DIR=/tmp/build'
# './MAKEALL'
#
# Command line 'O=' setting overrides BUILD_DIR environent variable.
#
# When none of the above methods is used the local build is performed and
# the object files are placed in the source directory.
#
第一种:make O=输出目录	
第二种:export BUILD_DIR=输出目录 然后再make
如果两个都指定了(既有BUILD_DIR环境变量存在,又有O=xx),则O=xx具有更高优先级,
听他的。

(5) The implementation codes of the two compilations are in lines 78-123 of Makefile.

ifdef O
ifeq ("$(origin O)", "command line")
BUILD_DIR := $(O)
endif
endif

ifneq ($(BUILD_DIR),)
saved-output := $(BUILD_DIR)

# Attempt to create a output directory.
$(shell [ -d ${
    
    BUILD_DIR} ] || mkdir -p ${
    
    BUILD_DIR})

# Verify if it was successful.
BUILD_DIR := $(shell cd $(BUILD_DIR) && /bin/pwd)
$(if $(BUILD_DIR),,$(error output directory "$(saved-output)" does not exist))
endif # ifneq ($(BUILD_DIR),)

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

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

ifneq ($(OBJTREE),$(SRCTREE))
REMOTE_BUILD	:= 1
export REMOTE_BUILD
endif

# $(obj) and (src) are defined in config.mk but here in main Makefile
# we also need them before config.mk is included which is the case for
# some targets like unconfig, clean, clobber, distclean, etc.
ifneq ($(OBJTREE),$(SRCTREE))
obj := $(OBJTREE)/
src := $(SRCTREE)/
else
obj :=
src :=
endif
export obj src

# Make sure CDPATH settings don't interfere
unexport CDPATH

5、OBJTREE、SRCTREE、TOPDIR、MKCONFIG

(1) OBJTREE: The root directory of the directory where the compiled .o files are stored. Under the default compilation, OBJTREE is equal to the current directory; under make O=xx compilation, OBJTREE is equal to the output directory we set.

(2) SRCTREE: The source code directory is actually the root directory of the source code, which is the current directory.

Summary: Under the default compilation, OBJTREE and SRCTREE are equal; under O=xx compilation, OBJTREE and SRCTREE are not equal. The definition of these two variables in the Makefile is actually to record where to put the compiled .o file, and to realize the compilation method of O=xx.

(3) A variable defined in the Makefile (defined here and used later), its value is mkconfig under the root directory of our source code. This mkconfig is a script, and this script is the configuration script in the uboot configuration phase.

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

MKCONFIG	:= $(SRCTREE)/mkconfig
export MKCONFIG

6、include $(obj)include/config.mk(133行)

(1) include/config.mk is not included in the source code (you will not find this file in the source code directory that has not been compiled), and this file will be generated during the configuration process (make x210_sd_config). Therefore, the value of this file is related to our configuration process, and is automatically generated by the configuration process according to our configuration.

(2) The content of the config.mk generated by configuring the X210 development board I use in the case of iNand is:

ARCH   = arm
CPU    = s5pc11x
BOARD  = x210
VENDOR = samsung
SOC    = s5pc110

(3) We export these 5 variables as environment variables in the next line (line 134). So the addition of the two lines actually defines 5 environment variables for the current makefile. The reason why the values ​​of these 5 environment variables are not given directly is because we hope that these 5 values ​​can be easily and centrally configured by people.

# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk #配置过程生成的
export	ARCH CPU BOARD VENDOR SOC

(4) The configuration value here comes from the configuration item on line 2589 of the Makefile. If we want to change a certain configuration value here, we need to go to line 2589 to call the parameters of the MKCONFIG script to pass parameters.

x210_sd_config :	unconfig
	@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
	@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

7、ARCH、CROSS_COMPILE

ifndef CROSS_COMPILE
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE =
else
ifeq ($(ARCH),ppc)
CROSS_COMPILE = ppc_8xx-
endif
ifeq ($(ARCH),arm)
#CROSS_COMPILE = arm-linux-
#CROSS_COMPILE = /usr/local/arm/4.4.1-eabi-cortex-a8/usr/bin/arm-linux-
#CROSS_COMPILE = /usr/local/arm/4.2.2-eabi/usr/bin/arm-linux-
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
endif
ifeq ($(ARCH),i386)
CROSS_COMPILE = i386-linux-
endif
ifeq ($(ARCH),mips)
CROSS_COMPILE = mips_4KC-
endif
ifeq ($(ARCH),nios)
CROSS_COMPILE = nios-elf-
endif
ifeq ($(ARCH),nios2)
CROSS_COMPILE = nios2-elf-
endif
ifeq ($(ARCH),m68k)
CROSS_COMPILE = m68k-elf-
endif
ifeq ($(ARCH),microblaze)
CROSS_COMPILE = mb-
endif
ifeq ($(ARCH),blackfin)
CROSS_COMPILE = bfin-uclinux-
endif
ifeq ($(ARCH),avr32)
CROSS_COMPILE = avr32-linux-
endif
ifeq ($(ARCH),sh)
CROSS_COMPILE = sh4-linux-
endif
ifeq ($(ARCH),sparc)
CROSS_COMPILE = sparc-elf-
endif	# sparc
endif	# HOSTARCH,ARCH
endif	# CROSS_COMPILE

export	CROSS_COMPILE

(1) Next, there are two very important environment variables. One is ARCH, exported above, the value comes from our configuration process, and its value will affect the value of the subsequent CROSS_COMPILE environment variable. The meaning of ARCH is to define the architecture of the currently compiled target CPU.

(2) CROSS_COMPILE defines the prefix of the cross- compilation toolchain . These prefixes are defined for later use (use prefixes and suffixes to define the tools in the various toolchains used in the compilation process).

  Another reason why we separate prefixes and suffixes is: cross-compilation toolchains on different CPU architectures, but the prefixes are different, and the suffixes are the same. Therefore, the prefix and suffix are separated when defining, and portability can be achieved only by distinguishing various architectures when defining the prefix.

(3) CROSS_COMPILE is determined on lines 136-182. CROSS_COMPILE is determined by ARCH, as long as ARCH=arm is configured, then we can only set the value of CROSS_COMPILE in the branch of ARM. As long as this setting value can ensure that the cross-compilation toolchain can be found, it does not necessarily have to be a full path, and a relative path is also fine. (If the toolchain has been exported to the environment variable, and the symbolic link is set, so that CROSS_COMPILE = arm-linux- will do)

(4) In actual use, we can change the value of CROSS_COMPILE in the Makefile, or use make CROSS_COMPILE=xxxx to set it during compilation, and the method of passing parameters during compilation can override the settings in the Makefile.

8. $(TOPDIR)/config.mk (line 185 of the main Makefile)

(1) Compilation tool definition (config.mk 94-107 lines)

#
# Include the make variables (CC, etc...)
#
AS	= $(CROSS_COMPILE)as
LD	= $(CROSS_COMPILE)ld
CC	= $(CROSS_COMPILE)gcc
CPP	= $(CC) -E
AR	= $(CROSS_COMPILE)ar
NM	= $(CROSS_COMPILE)nm
LDR	= $(CROSS_COMPILE)ldr
STRIP	= $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
RANLIB	= $(CROSS_COMPILE)RANLIB
#########################################################################

# Load generated board configuration
sinclude $(OBJTREE)/include/autoconf.mk

(2) Contains the development board configuration project (config.mk, line 112)

(1)autoconfig.mk文件不是源码提供的,是配置过程自动生成的。

(2)这个文件的作用就是用来指导整个uboot的编译过程。这个文件的内容其实就是很多
CONFIG_开头的宏(可以理解为变量),这些宏/变量会影响我们uboot编译过程的走向
(原理就是条件编译)。在uboot代码中有很多地方使用条件编译进行编写,这个条件
编译是用来实现可移植性的。(可以说uboot的源代码在很大程度来说是拼凑起来的,
同一个代码包含了各种不同开发板的适用代码,用条件编译进行区别。)

(3)这个文件不是凭空产生的,配置过程也是需要原材料来产生这个文件的。原材料在源码
目录的inlcude/configs/xxx.h头文件。(X210开发板中为include/configs/x210_sd.h)。
这个h头文件里面全都是宏定义,这些宏定义就是我们对当前开发板的移植。每一个开发板的
移植都对应这个目录下的一个头文件,这个头文件里每一个宏定义都很重要,这些配置的宏
定义就是我们移植uboot的关键所在。

(3) Link script (config.mk 142-149 lines)

ifndef LDSCRIPT
#LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds.debug
ifeq ($(CONFIG_NAND_U_BOOT),y)
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-nand.lds
else
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds
endif
endif

(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的编译链接过程时就要考虑这个链接脚本。

(4)TEXT_BASE(config.mk 156-158行)

ifneq ($(TEXT_BASE),)
CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE)
endif

(1)Makefile中在配置X210开发板时,在board/samsung/x210目录下生成了一个文件
config.mk,其中的内容就是:TEXT_BASE = 0xc3e00000相当于定义了一个变量。

(2)TEXT_BASE是将来我们整个uboot链接时指定的链接地址。因为uboot中启用了虚拟地址
映射,因此这个C3E00000地址就等于0x23E00000(也可能是33E00000具体地址要取决于
uboot中做的虚拟地址映射关系)

(5) Automatically deduce rules (config.mk 239-256 lines)

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

ifndef REMOTE_BUILD

%.s:	%.S
	$(CPP) $(AFLAGS) -o $@ $<
%.o:	%.S
	$(CC) $(AFLAGS) -c -o $@ $<
%.o:	%.c
	$(CC) $(CFLAGS) -c -o $@ $<

else

$(obj)%.s:	%.S
	$(CPP) $(AFLAGS) -o $@ $<
$(obj)%.o:	%.S
	$(CC) $(AFLAGS) -c -o $@ $<
$(obj)%.o:	%.c
	$(CC) $(CFLAGS) -c -o $@ $<
endif

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

9. Target all

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.ldr:	$(obj)u-boot
		$(LDR) -T $(CONFIG_BFIN_CPU) -f -c $@ $< $(LDR_FLAGS)

$(obj)u-boot.ldr.hex:	$(obj)u-boot.ldr
		$(OBJCOPY) ${
    
    OBJCFLAGS} -O ihex $< $@ -I binary

$(obj)u-boot.ldr.srec:	$(obj)u-boot.ldr
		$(OBJCOPY) ${
    
    OBJCFLAGS} -O srec $< $@ -I 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.sha1:	$(obj)u-boot.bin
		$(obj)tools/ubsha1 $(obj)u-boot.bin

$(obj)u-boot.dis:	$(obj)u-boot
		$(OBJDUMP) -d $< > $@

$(obj)u-boot:		depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT)
		UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
		sed  -n -e 's/.*\($(SYM_PREFIX)__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

(1) Line 291 shows the first target all in the main Makefile (that is, the default target, we directly make in the root directory of uboot is actually equal to make all, which is equal to the target of make)

(2) Some of the goals are more important. For example: u-boot is the executable file in elf format generated by the final compilation link,

(3) unconfig literally means unconfigured (line 473 of the main Makefile). This symbol is used as a dependency for our various development board configuration targets. The goal is to configure it again when we have already configured a development board.

unconfig:
	@rm -f $(obj)include/config.h $(obj)include/config.mk \
		$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
		$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
		$(obj)board/$(VENDOR)/$(BOARD)/config.mk

(4) When I configure the development board, I use: make x210_sd_config, so analyzing x210_sd_config must be a target in the main Makefile (line 2589).

x210_sd_config :	unconfig
	@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
	@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

4. Detailed explanation of uboot configuration process: 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 <[email protected]>
#

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

# create link for s3c24xx SoC
if [ "$3" = "s3c24xx" ] ; then
	rm -f regs.h
	ln -s $6.h regs.h
	rm -f asm-$2/arch
	ln -s arch-$3 asm-$2/arch
fi

# create link for s3c64xx SoC
if [ "$3" = "s3c64xx" ] ; then
	rm -f regs.h
	ln -s $6.h regs.h
	rm -f asm-$2/arch
	ln -s arch-$3 asm-$2/arch
fi

# create link for s5pc1xx SoC
if [ "$3" = "s5pc1xx" ] ; then
        rm -f regs.h
        ln -s $6.h regs.h
        rm -f asm-$2/arch
        ln -s arch-$3 asm-$2/arch
fi

# create link for s5pc11x SoC
if [ "$3" = "s5pc11x" ] ; then
        rm -f regs.h
        ln -s $6.h regs.h
        rm -f asm-$2/arch
        ln -s arch-$3 asm-$2/arch
fi

# create link for s5p64xx SoC
if [ "$3" = "s5p64xx" ] ; then
	rm -f regs.h
	ln -s $6.h regs.h
	rm -f asm-$2/arch
	ln -s arch-$3 asm-$2/arch
fi

# create link for s5p644x SoC
if [ "$3" = "s5p644x" ] ; then
	rm -f regs.h
	ln -s $6.h regs.h
	rm -f asm-$2/arch
	ln -s arch-$3 asm-$2/arch
fi

if [ "$2" = "arm" ] ; then
	rm -f asm-$2/proc
	ln -s ${
    
    LNPREFIX}proc-armv asm-$2/proc
fi

# create link for s3c64xx-mp SoC
if [ "$3" = "s3c64xx-mp" ] ; then
	rm -f regs.h
	ln -s $6.h regs.h
	rm -f asm-$2/arch
	ln -s arch-$3 asm-$2/arch
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) 6 parameters of the mkconfig script

$(@:_config=) arm s5pc11x x210 samsung s5pc110(Makefile 2593-2595行)

x210_sd_config里的_config部分用空替换,得到:x210_sd,这就是第一个参数,所以:
$1:	x210_sd
$2:	arm
$3: s5pc11x
$4:	x210
$5: samsumg
$6:	s5pc110
所以,$# = 6

(2) Line 23: In fact, it is to see whether the BOARD_NAME variable has a value. If it has a value, it will remain unchanged; if it has no value, it will be assigned a value of $1. The actual analysis result: BOARD_NAME=x210_sd

(3) Line 25: If $# is less than 4, then exit 1 (mkconfig script returns 1, program execution error)

(4) Line 26: If $# is greater than 6, it will also return 1.
Therefore: the amount of parameters passed by the mkconfig script can only be 4, 5, 6, if it is greater than 6 or less than 4, it will not work.

(5) From line 33 to line 118, symbolic links are being created. Why are symbolic links created?

  The existence of these symbolic link files is the core of the entire configuration process. The main function of these symbolic link files (folders) is to provide directional connections for processes such as header file inclusion. The fundamental purpose is to make uboot portable.

  The realization principle of uboot portability: There are many parallel codes in uboot, each of which belongs to its own different architecture/CPU/development board. We provide a specific name by symbolic link when compiling a development board. folder for compilation. In this way, different files can be used through different configurations during the configuration process, and the correct files can be included correctly.

(6) Symbolic link created:

第一个:在include目录下创建asm文件,指向asm-arm。(46-48行)
第二个:在inlcude/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc110(56行)
第三个:在include目录下创建regs.h文件,指向include/s5pc110.h
删除第二个。(84-87行)
第四个:在inlcude/asm-arm下创建一个arch文件,指向include/asm-arm/arch-s5pc11x(88行)
第五个:在include/asm-arm下创建一个proc文件,指向include/asm-arm/proc-armv(107-109行)

Summary: A total of 4 symbolic links were created. These 4 symbolic links will be very useful when header files are included in the process of writing code in the future. For example, a header file may include: #include <asm/xx.h>

(7) Create the include/config.mk file (lines 123-129 of the mkconfig file). The include/config.mk file is created for the main Makefile to include on line 133. When understanding these scripts, always pay attention to the path you are currently on.

  Create (by default)/append (append when make -a) the include/config.h file (lines 134-141 of the mkconfig file).

  The content of this file is just one line #include <configs/x210_sd.h>, this header file is the macro definition configuration file for the development board when we port the x210 development board. This file is the most important file when we port x210.

  The x210_sd.h file will be used to generate an autoconfig.mk file, which will be introduced by the main Makefile to guide the entire compilation process. These macro definitions here will affect our selection of some conditional compilations in most .c files in uboot. Thus achieving ultimate portability.

Note : In the entire configuration process of uboot, many files are related (sometimes this file is created in that file; sometimes this file is included in that file; sometimes this file is created by the content of that file generated decision)

Note : During the configuration and compilation process in uboot, all files or global variables are in the form of strings (not the concept of C language strings, but sequences of characters). This means that our entire uboot configuration process is string matching, so we must pay attention to details, pay attention to capitalization, and be careful not to enter wrong characters, because once the wrong one will end up with some inexplicable errors, it is difficult to troubleshoot. This is The most difficult part for novices in the process of uboot transplantation.

Five, uboot link script u-boot.lds

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)//  输出的架构是ARM
ENTRY(_start)   //指定整个程序的入口地址
SECTIONS
{
    
    
	. = 0x00000000;

	. = ALIGN(4);/*指示编译器将接下来的代码进行4字节对齐编译*/
	.text      :/*也就是在分配地址时,以4的整数倍分配*/
	{
    
    
	  cpu/s5pc11x/start.o	(.text)
	  cpu/s5pc11x/s5pc110/cpu_init.o	(.text)
	  board/samsung/x210/lowlevel_init.o	(.text)
          cpu/s5pc11x/onenand_cp.o      (.text)                 
          cpu/s5pc11x/nand_cp.o (.text)                     
          cpu/s5pc11x/movi.o (.text) 
          common/secure_boot.o (.text) 
	  common/ace_sha1.o (.text)
	  cpu/s5pc11x/pmic.o (.text)
	  *(.text)
	}

	. = ALIGN(4);
	.rodata : {
    
     *(.rodata) }

	. = ALIGN(4);
	.data : {
    
     *(.data) }

	. = ALIGN(4);
	.got : {
    
     *(.got) }

	__u_boot_cmd_start = .;//自定义的段,起始地址
	.u_boot_cmd : {
    
     *(.u_boot_cmd) }
	__u_boot_cmd_end = .;//结束地址

	. = ALIGN(4);
	.mmudata : {
    
     *(.mmudata) }

	. = ALIGN(4);
	__bss_start = .;
	.bss : {
    
     *(.bss) }
	_end = .;
}

(1) ENTRY (_start) is used to specify the entry address of the entire program. The so-called entry address is the beginning address of the entire program, which can be considered as the first instruction of the entire program. A bit like main in C language.

(2) There are two ways to specify the link address of the program: one is to specify with -Ttext 0x20000000 in the flags of ld in the Makefile; the second is to specify with .=0x20000000 at the beginning of SECTIONS of the link script. Both can achieve the same effect. In fact, these two techniques can be used together, that is to say, specify in the link script and use -Ttext in ld flags. After both are specified, the one specified by -Ttext shall prevail.

(3) The final link starting address of uboot is specified with -Ttext in the Makefile. Note the value of TEXT_BASE in the Makfile. The final source is obtained when making xxx_config in the command corresponding to the configuration in the Makefile.

x210_sd_config :	unconfig
	@$(MKCONFIG) $(@:_config=) arm s5pc11x x210 samsung s5pc110
	@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/x210/config.mk

(4) Pay attention to the order in which the files are arranged in the code segment. Specify those files that must be placed in the front part are those that must be arranged in the front, and store some important things first;

(5) In addition to the .text .data .rodata .bss sections in the link script, the compilation tool also allows us to customize the sections. For example, the .u_boot_cmd section of uboot (related to the command implementation mechanism) is a custom section. Custom segments are important.

Note: Most of this information is compiled from the course notes of Mr. Zhu's Internet of Things Lecture, citing Baidu Encyclopedia, some other people's blog content and combining with his own actual development experience. If there is any infringement, please contact to delete! The level is limited, if there are mistakes, welcome to communicate in the comment area.

Guess you like

Origin blog.csdn.net/weixin_45842280/article/details/126696613