ubootソースコード解析のゼロ距離初期体験 (S5PV210ベース)

1. S5PV210 公式の uboot 構成コンパイルの練習

1. 公式 (SOC/開発ボード メーカー) が移植した uboot を見つける

(1) uboot公式サイトからソースのソースコードをダウンロードします。ダウンロードしたソース コードには、現在使用している開発ボードのポーティングが含まれていない場合や、現在の開発ボードで使用されている SoC に対応するポーティング バージョンが含まれていない場合があります。

(2) SoC メーカーが SoC をローンチした後、メーカーのエンジニアは uboot の公式 Web サイトにアクセスして uboot をダウンロードし、自社の SoC に基づいて移植の第 1 段階を実行します。メーカー。(たとえば、Samsung の S5PV210 チップ メーカーが製造した開発ボードは SMDKV210 と呼ばれます) したがって、Samsung のエンジニアによって移植された uboot は、独自の SMDKV210 開発ボードに基づいています。

(3) 特定の開発ボード サプライヤ (X210 の製造元である深セン Jiuding Technology など) は、最初に Samsung の SMDKV210 開発ボードを購入し、それを切り取ります (不要なインターフェイス機能をいくつか切り取り、構成を減らし、いくつかの構成を交換します)。 . ハードウェアの交換と切断後に生成された新しい開発ボード (X210 など) は、Samsung の公式の SMDKV210 とは異なるため、uboot も異なります。しかしSoCが同じなので、類似度は60%以上です。したがって、特定の開発ボード サプライヤは、Samsung SMDKV210 に移植された uboot を設計図として使用して、独自の開発ボードの uboot 移植を取得します。

まとめ: uboot の入手方法は、uboot 公式、SoC 公式、特定開発ボード公式の 3 通りあります。

2. ubuntu での設定とコンパイル

(1) BSP はボード サポート パッケージ (ボード レベルのサポート パッケージ、通常は開発ボード サプライヤによって提供される) であり、開発ボードの関連するすべてのソース コード、ドキュメント、チュートリアルなどが含まれます。

(2) BSP パッケージ ファイル全体を Linux のソース ディレクトリに取得して解凍し、解析します。Windows の共有フォルダには解凍しないでください。(コードが Windows でのみ解析され、コンパイルされていない場合を除き、プロジェクトをコンパイルする場合は、Windows 共有フォルダーに配置しないでください。そうしないと、エラーが発生します)

(3)tar -jxvf qt_x210v3_130807.tar.bz2

(4) Linux (ubuntu) での uboot と windows での uboot を維持していますが、作業を開始する前に、これら 2 つの uboot の内容は同じです。これは、Linux でコンパイルし、Windows でコードを分析および表示する目的で行います。(windwos には SourceInsight などの非常に優れたツールがあり、コードの表示と編集を支援します。Linux でのコードのコンパイルと表示は非常に面倒です...)

(5)構成

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

(6) コンパイルして uboot.bin を取得

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

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

二、ubootソースコードディレクトリ分析

1. 開発ボードメーカー提供のubootとSamsung独自のubootの比較

(1) 開発ボードのメーカーが提供する uboot から学び、Samsung の公式のものと比較しました。

(2) uboot の異なるバージョン、または別の人によって移植された同じバージョンの uboot は、ディレクトリ構造とファイルの内容が異なる場合があります。将来的には、それを理解した上で、必要に応じてディレクトリ構造を追加/削除/変更することもできます。

(3) 開発ボードの製造元が Samsung の uboot を移植の原材料として使用する場合、Samsung の uboot の多くの不要なフォルダーとファイルが削除される可能性があります。この削除により、まったく使用されていない多くのファイルが消去され、ファイル全体の数が減り、作業が容易になります。
ここに画像の説明を挿入
ここに画像の説明を挿入

2. 各ファイルの紹介 (開発ボードメーカー Jiuding Technology の uboot を例にとります)

(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使用的规则,本身非常重要,但是我们
不去分析他,不去看他。

  概要: 上記のファイルの中で、より重要で注意深く読む必要があるファイルが 2 つあります。mkconfigと Makefile です。1 つは uboot の構成を担当し、もう 1 つはコンパイルを担当します

3. 各フォルダの紹介

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

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

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

質問 1: ボードの下に非常に多くのフォルダーがあります。どのフォルダーを使用するかを決定する方法は?
  構成段階で、uboot には、ボード ディレクトリの下のどのフォルダーを使用するかを決定するのに役立ついくつかの手段があります。(直接コンパイルできない理由を考えて、最初に構成します)

質問 2: ますます多くの開発ボードがあり、ボード ディレクトリにはますます多くのフォルダーがあり、管理と制御が不便です.それを解決する方法

  そのため、uboot は新しいメカニズムを追加しました。これは、ボード ディレクトリの下に開発ボード ディレクトリを直接配置することはできませんが、メーカー ディレクトリ (特定のチップ メーカーにちなんで名付けられたベンダー ディレクトリ) をボードの下に配置し、このすべてのチップを配置します。 IC メーカー 開発ボードは vendor ディレクトリの下に投げられます。

  X210 に対応する開発ボードのディレクトリは、board/samsung/x210 です。このレベルのディレクトリを追加すると、構成段階に影響を与えます. In the uboot configuration stage, pay at the associated path depth during configuration and actual storage. そうしないと、構成後のコンパイル中にファイルが見つからず、コンパイルが失敗します. 歴史的な理由による互換性の問題である詳細に注意してください。当初はボードディレクトリに開発ボードの名前がありましたが、後にメーカー名に変更されました。ただし、上位互換性のため、同じメーカーの元の開発ボードはメーカーのディレクトリに移動されませんでした。これにより、後の人々はストーリー全体を知らないため、非常に奇妙で混乱したように感じます。

  注: 強調するために、uboot の構成フェーズ (実際にはルート ディレクトリの下の mkconfig スクリプトと Makefile の構成関連部分) は、主に移植性の分野の問題を解決し、特定のフォルダーのパスを決定するのに役立ちます。正常にコンパイルするために、必要なファイルを見つけることができます。したがって、ボードディレクトリの違いが構成の違いになります。移植の際に注意しないと、確実に失敗します。

(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。

要約: フォルダーはより重要であり、後で分析します: board、common、cpu、drivers、include、lib_arm、lib_generic、sd_fusing

三、ubootメインのMakefile解析

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

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

1. uboot のバージョンを確認します (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 のバージョン番号です。

(4) 検証方法: メイン Makefile のバージョン関連の変数をいくつか自分で変更し、uboot を再コンパイルしてから SD カードに焼き付け、SD カードから開始し、起動時に uboot によって出力されるバージョン情報を確認します。変化はあなた自身の分析と一致していますか?

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 と HOSTOS

(1) ubuntuコマンドライン(シェル)でuname -mを直接実行してi686を取得すると、実際には現在このコマンドを実行しているコンピュータのCPUのバージョン番号が取得されます。

(2) シェルの「|」をパイプラインと呼びます.パイプラインの機能は、パイプラインの前の計算式の出力を次のパイプラインの入力として処理することであり、最終的な出力は出力です.私たちの式全体の。

(3) 名称 HOSTARCH: HOST はホスト、つまり現在開発に使用しているコンピュータをホストと呼び、ARCH はアーキテクチャ (architecture) の略で、CPU のアーキテクチャを意味します。したがって、HOSTARCH はホストの CPU アーキテクチャを表します。

(4) これら 2 つの環境変数は、ホストのオペレーティング システムとホストの CPU アーキテクチャであり、取得後に後で使用するために保存されます。

3. サイレント コンパイル (50 ~ 54 行目)

(1) 通常、デフォルトでは、コマンド ラインはコンパイル時に多くのコンパイル情報を出力します。しかし、これらのコンパイル情報を見たくない場合もあります。バックグラウンドでコンパイルするだけです。これをサイレントコンパイルと呼びます。

(2) 使用方法は、コンパイル時に make -s であり、-s は MAKEFLAGS として Makefile に渡され、XECHO 変数は 50 ~ 54 行のこのコードのアクションの下で空になります (デフォルトは echo に等しい)。ので、サイレントコンパイルが実現します。

4. 2 つのコンパイル方法 (インプレース コンパイルと別の出力フォルダーでのコンパイル)

(1) 複雑なプロジェクトをコンパイルするために、Makefile は 2 つのコンパイル管理方法を提供します。デフォルトでは、現在のフォルダーの .c ファイルであり、コンパイルされた .o ファイルは同じフォルダーに配置されます。この方法は、インプレース コンパイルと呼ばれます。インプレース コンパイルの利点は、扱いが簡単なことです

(2) インプレース コンパイルにはいくつかの欠点があります。まず、ソース ファイル ディレクトリが汚染されます。2 つ目の欠点は、ソース コードのセットは 1 つの構成およびコンパイル方法に従ってのみ処理でき、2 つ以上の構成およびコンパイル方法を同時に維持できないことです。

(3) 上記の 2 つの欠点を解決するために、uboot は別の出力フォルダーのコンパイルをサポートします(Linux カーネルもサポートしており、uboot のこの技術は Linux カーネルから学習されています)。基本的な考え方は、コンパイル時に追加の出力ディレクトリを指定し、将来、コンパイルによって生成されたすべての .o ファイルまたはその他のファイルをその出力ディレクトリにスローすることです。ソース コード ディレクトリは汚染を行わないため、出力ディレクトリには、この構成コンパイルのすべての結果が含まれます

(4) 特定の使用法: デフォルトはその場でコンパイルすることです。コンパイルのために特定の出力ディレクトリを指定する必要がある場合、出力ディレクトリを指定する方法は 2 つあります。(詳しくは Makefile の 56 ~ 76 行目のコメントを参照してください)

#########################################################################
#
# 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) 2 つのコンパイルの実装コードは、Makefile の 78 ~ 123 行にあります。

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: コンパイルされた .o ファイルが格納されるディレクトリのルート ディレクトリ。デフォルトのコンパイルでは、OBJTREE は現在のディレクトリに等しく、make O=xx コンパイルでは、OBJTREE は設定した出力ディレクトリに等しくなります。

(2) SRCTREE: ソース コード ディレクトリは、実際にはソース コードのルート ディレクトリであり、現在のディレクトリです。

要約: デフォルトのコンパイルでは、OBJTREE と SRCTREE は等しくなりますが、O=xx コンパイルでは、OBJTREE と SRCTREE は等しくありません。Makefile でのこれら 2 つの変数の定義は、実際には、コンパイルされた .o ファイルをどこに置くかを記録し、O=xx のコンパイル方法を実現するためのものです。

(3) Makefile で定義された変数 (ここで定義され、後で使用されます)。その値は、ソース コードのルート ディレクトリにある mkconfig です。この mkconfig はスクリプトであり、このスクリプトは uboot 構成フェーズの構成スクリプトです。

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 はソース コードに含まれておらず (コンパイルされていないソース コード ディレクトリにはこのファイルはありません)、このファイルは構成プロセス (make x210_sd_config) 中に生成されます。したがって、このファイルの値は構成プロセスに関連しており、構成に従って構成プロセスによって自動的に生成されます。

(2) iNand の場合、私が使用している X210 開発ボードを構成して生成された config.mk の内容は次のとおりです。

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

(3) 次の行 (134 行目) で、これら 5 つの変数を環境変数としてエクスポートします。したがって、2 行を追加すると、実際には現在のメイクファイルに対して 5 つの環境変数が定義されます。これら 5 つの環境変数の値が直接与えられていない理由は、これら 5 つの値が人々によって簡単かつ一元的に設定されることを望んでいるためです。

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

(4) ここでの構成値は、Makefile の 2589 行目の構成項目から取得されます。ここで特定の構成値を変更する場合は、2589 行に移動して、MKCONFIG スクリプトのパラメーターを呼び出してパラメーターを渡す必要があります。

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) 次に、非常に重要な環境変数が 2 つあります。1 つは上でエクスポートされた ARCH で、値は構成プロセスから取得され、その値は後続の CROSS_COMPILE 環境変数の値に影響します。ARCH の意味は、現在コンパイルされているターゲット CPU のアーキテクチャを定義することです。

(2) CROSS_COMPILE は、クロスこれらのプレフィックスは、後で使用するために定義されます (コンパイル プロセスで使用されるさまざまなツールチェーンでツールを定義するには、プレフィックスとサフィックスを使用します)。

  接頭辞と接尾辞を分けるもう 1 つの理由は、異なる CPU アーキテクチャ上のクロス コンパイル ツールチェーンですが、接頭辞は異なり、接尾辞は同じです。したがって、定義時にプレフィックスとサフィックスを分離し、プレフィックスを定義するときにさまざまなアーキテクチャを区別するだけで移植性を実現できます。

(3) CROSS_COMPILE は 136 ~ 182 行で決定されます。ARCH=arm が構成されている限り、CROSS_COMPILE は ARCH によって決定され、ARM のブランチでのみ CROSS_COMPILE の値を設定できます。この設定値でクロスコンパイルツールチェーンを確実に見つけられるのであれば、必ずしもフルパスである必要はなく、相対パスでもかまいません。(ツールチェーンが環境変数にエクスポートされ、シンボリック リンクが設定されている場合、CROSS_COMPILE = arm-linux- で十分です)

(4) 実際の使用では、Makefile の CROSS_COMPILE の値を変更するか、make CROSS_COMPILE=xxxx を使用してコンパイル時に設定し、コンパイル時にパラメーターを渡す方法で Makefile の設定を上書きすることができます。

8. $(TOPDIR)/config.mk (メイン Makefile の 185 行目)

(1)コンパイルツールの定義(config.mk 94~107行)

#
# 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) 開発ボード構成プロジェクトが含まれています (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的关键所在。

(3)リンクスクリプト(config.mk 142~149行)

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) 自動的にルールを推測 (config.mk 239-256 行)

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

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. すべてを対象にする

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) 行 291 は、メインの Makefile の最初のターゲット all を示しています (つまり、デフォルトのターゲットです。uboot のルート ディレクトリで直接作成するのは、実際には make all と同じで、これは make のターゲットと同じです)

(2) いくつかの目標はより重要です。例: u-boot は、最終的なコンパイル リンクによって生成された elf 形式の実行可能ファイルです。

(3) unconfig は文字通り、未構成を意味します (メイン Makefile の 473 行目)。このシンボルは、さまざまな開発ボード構成ターゲットの依存関係として使用されます。目標は、開発ボードを既に構成したときに再度構成することです。

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) 開発ボードを構成するときは、make x210_sd_config を使用します。そのため、x210_sd_config の解析は、メインの Makefile (行 2589) のターゲットにする必要があります。

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

4. uboot 構成プロセスの詳細な説明: 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) mkconfigスクリプトの6つのパラメータ

$(@:_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) 23 行目: 実際には、BOARD_NAME 変数に値があるかどうかを確認します. 値がある場合は変更されず、値がない場合は $1 の値が割り当てられます. 実際の分析結果: BOARD_NAME=x210_sd

(3) 25 行目: $# が 4 未満の場合、1 を終了します (mkconfig スクリプトは 1 を返し、プログラム実行エラー)

(4) 行 26: $# が 6 より大きい場合、1 も返されます。
したがって、mkconfig スクリプトによって渡されるパラメーターの量は、6 より大きいか 4 より小さい場合、4、5、6 のみです。 、 うまくいかないだろう。

(5) 33行目から118行目でシンボリックリンクを作成しています。シンボリックリンクはなぜ作成されるのですか?

  これらのシンボリック リンク ファイルの存在は、構成プロセス全体の中核をなし、これらのシンボリック リンク ファイル (フォルダー) の主な機能は、ヘッダー ファイルのインクルードなどのプロセスに方向性のある接続を提供することです。基本的な目的は、uboot を移植可能にすることです。

  uboot 移植性の実現原理: uboot には多くの並列コードがあり、それぞれが独自の異なるアーキテクチャ/CPU/開発ボードに属しています. 開発ボードをコンパイルするときに、シンボリック リンクによって特定の名前を提供します. コンパイル用のフォルダー. このようにして、構成プロセス中にさまざまな構成でさまざまなファイルを使用でき、正しいファイルを正しく含めることができます。

(6) 作成されたシンボリックリンク:

第一个:在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行)

概要: 合計 4 つのシンボリック リンクが作成されました。これら 4 つのシンボリック リンクは、将来コードを記述するプロセスにヘッダー ファイルが含まれる場合に非常に役立ちます。たとえば、ヘッダー ファイルには次のものが含まれる場合があります。 #include <asm/xx.h>

(7) include/config.mk ファイルを作成します (mkconfig ファイルの 123 ~ 129 行目) include/config.mk ファイルは、133 行目でメインの Makefile をインクルードするために作成されます。これらのスクリプトを理解するときは、現在進行中のパスに常に注意してください。

  include/config.h ファイル (mkconfig ファイルの 134 ~ 141 行目) を作成 (デフォルト)/追加 (make -a 時に追加) します。

  このファイルの内容は #include <configs/x210_sd.h> の 1 行だけです。このヘッダー ファイルは、x210 開発ボードを移植する際の開発ボード用のマクロ定義構成ファイルです。このファイルは、x210 を移植する際に最も重要なファイルです。

  x210_sd.h ファイルを使用して autoconfig.mk ファイルを生成します。このファイルは、メインの Makefile によって導入され、コンパイル プロセス全体をガイドします。ここでのこれらのマクロ定義は、uboot のほとんどの .c ファイルでいくつかの条件付きコンパイルの選択に影響します。したがって、究極の携帯性を実現します。

: uboot の構成プロセス全体では、多くのファイルが関連しています (このファイルがそのファイルに作成される場合もあれば、このファイルがそのファイルに含まれる場合もあります。また、このファイルが生成された決定の内容によってこのファイルが作成される場合もあります)。

: uboot での構成およびコンパイル プロセス中、すべてのファイルまたはグローバル変数は文字列の形式になります (C 言語文字列の概念ではなく、文字のシーケンス)。これは、uboot 設定プロセス全体が文字列マッチングであることを意味するため、詳細に注意を払い、大文字と小文字に注意を払い、間違った文字を入力しないように注意する必要があります。これは、uboot 移植の過程で初心者にとって最も難しい部分です。

五、ubootリンクスクリプト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)は、プログラム全体のエントリアドレスを指定するために使用します。いわゆるエントリアドレスは、プログラム全体の最初の命令と見なすことができるプログラム全体の開始アドレスです。C 言語の main に少し似ています。

(2) プログラムのリンクアドレスの指定方法は、Makefile の ld の flags に -Ttext 0x20000000 で指定する方法と、リンクの SECTIONS の先頭に .=0x20000000 で指定する方法の 2 通りがあります。脚本。どちらも同じ効果を得ることができます。実際、これら 2 つの手法は一緒に使用できます。つまり、リンク スクリプトで指定し、ld フラグで -Ttext を使用します。両方が指定された後は、-Ttext で指定された方が優先されます。

(3) uboot の最終リンク開始アドレスは Makefile の -Ttext で指定します。Makfile の TEXT_BASE の値に注意してください。Makefile の構成に対応するコマンドで xxx_config を作成すると、最終的なソースが取得されます。

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

(4) コード部分のファイルの並び順に注意してください。フロント部分に配置する必要があるファイルを、フロントに配置する必要があるファイルであると指定し、いくつかの重要なものを最初に保存します。

(5) リンク スクリプトの .text .data .rodata .bss セクションに加えて、コンパイル ツールを使用してセクションをカスタマイズすることもできます。たとえば、uboot の .u_boot_cmd セクション (コマンド実装メカニズムに関連) はカスタム セクションです。カスタム セグメントは重要です。

注: この情報のほとんどは、Zhu 氏の Internet of Things Lecture のコース ノートから編集され、Baidu Encyclopedia、他の人のブログ コンテンツを引用し、彼自身の実際の開発経験と組み合わせています。レベルに制限があります。間違いがあれば、コメント欄でお知らせください。

おすすめ

転載: blog.csdn.net/weixin_45842280/article/details/126696613