您的位置:首页 > 其它

U-BOOT-2016.07移植 (第一篇) 初步分析

2017-04-14 20:59 232 查看


U-BOOT-2016.07移植 (第一篇) 初步分析


U-BOOT-2016.07移植 (第二篇) 添加单板


U-BOOT-2016.07移植 (第三篇) 代码重定位


U-BOOT-2016.07移植 (第四篇) 修改代码,从NOR启动


目录

U-BOOT-201607移植 第一篇 初步分析
U-BOOT-201607移植 第二篇 添加单板
U-BOOT-201607移植 第三篇 代码重定位
U-BOOT-201607移植 第四篇 修改代码从NOR启动
目录
编译和移植环境
更新交叉编译工具
1 下载arm-linux-gcc 443
2 安装arm-linux-gcc 443 安装环境Ubuntu 910

下载u-boot-201607并解压
分析顶层Makefile
1 找出目标依赖关系
2 总结

初次编译u-boot
1 配置
2 编译

分析u-boot启动流程
1 分析startS
2 分析crt0S
3 总结


1. 编译和移植环境

编译环境:Ubuntu9.10
交叉编译工具:arm-linux-gcc 4.4.3
u-boot版本号:2016.07

移植目标单板信息: JZ2440v2
CPU: S3C2440
NAND: K9F2G08U0C
NOR:  MX29LV160DBTI
网卡:DM9000A


2. 更新交叉编译工具


1.1 下载arm-linux-gcc 4.4.3

下载地址:arm-linux-gcc-4.4.3-20100728.tar.gz (这是博主自己上传的) 

  


1.2 安装arm-linux-gcc 4.4.3 (安装环境:Ubuntu 9.10)

(1) 先创建临时目录tmp

mkdir tmp


(2) 将下载好的压缩包解压到tmp中

tar xzf arm-Linux-gcc-4.4.3-20100728.tar.gz
-C tmp/


解压完成后可以发现交叉编译工具在 tmp/opt/FriendlyARM/toolschain/4.4.3/bin 目录中

(3) 安装到/usr/local/中

cd /usr/local
mkdir arm
chmod 777 arm
sudo cp -a tmp/opt/FriendlyARM/toolschain/4.4.3/ /usr/local/arm/
1
2
3
4
1
2
3
4

(4) 修改环境变量

方法一:立即生效

echo $PATH


得到当前PATH值,如: 
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/gcc_old_path


复制当前PATH环境变量,将老的交叉编译工具路径给删除,然后添加新的路径: 
/usr/local/arm/4.4.3/bin


然后export 

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/arm/4.4.3/bin

方法二:如果不想每次都手动修改PATH,可以编辑/etc/environment 这个方法需要重启后生效 
sudo vi /etc/environment


将老路径去掉,加上新路径
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/4.4.3/bin"
:wq     //保存退出
1
2
1
2

(5) 查看版本信息

arm-linux-gcc -v


若输出版本号是4.4.3则表示安装成功


3. 下载u-boot-2016.07并解压

(1)下载 

u-boot源码下载地址:ftp://ftp.denx.de/pub/u-boot/ 

选择u-boot-2016.07下载

(2)在虚拟机上解压 
tar xjf u-boot-2016.07.tar.bz2



4. 分析顶层Makefile


4.1 找出目标依赖关系

(1)all
Top Makefile:

803: all: $(ALL-y)             //<----------------------

732: ALL-y += u-boot.srec u-boot.bin u-boot.sym System.map u-boot.cfg binary_size_check
765: ALL-y += u-boot-tegra.bin u-boot-nodtb-tegra.bin
771: ALL-y += $(CONFIG_BUILD_TARGET:"%"=%)
1
2
3
4
5
6
7
1
2
3
4
5
6
7

可见执行make会生成u-boot.bin
(2)u-boot.bin
Top Makefile:

821:ifeq ($(CONFIG_OF_SEPARATE),y)
822:u-boot-dtb.bin: u-boot-nodtb.bin dts/dt.dtb FORCE
823:    $(call if_changed,cat)
824:
825:u-boot.bin: u-boot-dtb.bin FORCE
826:    $(call if_changed,copy)
827:else                        //由于没有定义CONFIG_OF_SEPARATE选项,所以我们关心下面这条依赖关系
828:u-boot.bin: u-boot-nodtb.bin FORCE //<----------------------
829:    $(call if_changed,copy)        //if_changed函数检测依赖文件是否有更新或目标文件是否不存在,
//然后echo打印传入的参数,最后执行传入的命令copy,
//下面贴出 scripts/Kbuild.include文件中的部分内容,大家可以自行分析
830:endif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1
2
3
4
5
6
7
8
9
10
11
12
13
14

展开后: (若无目标或依赖文件更新)
u-boot.bin: u-boot-nodtb.bin FORCE
echo COPY    $@; cp $<  $@      //输出 COPY   u-boot.bin, 然后执行cp u-boot-nodtb.bin u-boot.bin
1
2
1
2
(3)u-boot-nodtb.bin
Top Makefile

-> 862:u-boot-nodtb.bin: u-boot FORCE
863:    $(call if_changed,objcopy)      //objcopy
864:    $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))
865:    $(BOARD_SIZE_CHECK)
1
2
3
4
5
6
1
2
3
4
5
6
(4)u-boot
1173:quiet_cmd_u-boot__ ?= LD      $@
1174:      cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o $@ \
1175:      -T u-boot.lds $(u-boot-init)                             \
1176:      --start-group $(u-boot-main) --end-group                 \
1177:      $(PLATFORM_LIBS) -Map u-boot.map

-> 1186:u-boot: $(u-boot-init) $(u-boot-main) u-boot.lds FORCE
1187:    $(call if_changed,u-boot__)            //将u-boot-init、u-boot-main按照u-boot.lds进行链接
1188:ifeq ($(CONFIG_KALLSYMS),y)
1189:    $(call cmd,smap)
1190:    $(call cmd,u-boot__) common/system_map.o
1191:endif
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
(5)u-boot-init,u-boot-main
-> 679:u-boot-init := $(head-y)
-> 680:u-boot-main := $(libs-y)
1
2
1
2

(6)head-y 

在linux上搜索head-y这个目标: 
grep "head-y" * -nR


得到下面这个结果: 
arch/arm/Makefile:74:head-y := arch/arm/cpu/$(CPU)/start.o


所以head-y指的是start.S

(7)libs-y 

在顶层目录Makefile中搜索libs-y可以发现其包含许多目录 

比如: 
631:libs-y += drivers/mtd/


另: 
667:libs-y := $(patsubst %/, %/built-in.o, $(libs-y))
 

这条规则使libs-y中每个条目的最后一个斜杠替换成 /built-in.o,比如 drivers/mtd/ 会变为 drivers/mtd/built-in.o

可见libs-y最后指向各个文件夹的built-in.o 

而这些built-in.o则由 Kbuild Makefile 将obj-y所包含的各个文件编译而成, 

具体可研究 scripts/Kbuild.include 和 scripts/Makefile.build

(8)%config 

一般我们在执行make之前都需要配置一下开发板参数,比如make smdk2410_config,在顶层目录Makefile有:

396:scripts_basic:
397:    $(Q)$(MAKE) $(build)=scripts/basic  //build 在 scripts/Kbuild.include:181:
//build := -f $(srctree)/scripts/Makefile.build obj,
//展开来就是:@make -f scripts/Makefile.build obj=scripts/basic
398:    $(Q)rm -f .tmp_quiet_recordmcount

-> 476:%config: scripts_basic outputmakefile FORCE
477:$(Q)$(MAKE) $(build)=scripts/kconfig $@         //展开来就是:
//@make -f scripts/Makefile.build obj=scripts/kconfig %config
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9
scripts/Makefile.build中:

12: prefix := spl
13: src := $(patsubst $(prefix)/%,%,$(obj))         //obj=scripts/kconfig, src := scripts/kconfig

57: kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src))
//kbuild-dir := $(srctree)/scripts/kconfig

58: kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile)
//由于没有scripts/kconfig/Kbuild这个文件,所以 kbuild-file := $(srctree)/scripts/kconfig/Makefile

59: include $(kbuild-file)  //在这里将scripts/kconfig/Makefile 添加进来了
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
%config这个目标的生成规则在scripts/kconfig/Makefile中:

15: SRCARCH := ..

113:%_defconfig: $(obj)/conf
114:    $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig)
//执行:@scripts/kconfig/conf --defconfig=arch/../configs/%_defconfig Kconfig      (没有进入arch目录)
//即:  @scripts/kconfig/conf --defconfig=configs/%_defconfig Kconfig
115:
116:# Added for U-Boot (backward compatibility)
-> 117:%_config: %_defconfig
118:    @:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12

分析到这里,我们可以看出配置单板相关的参数是在 scripts/kconfig/conf 中进行的, 

传入的参数是 
--defconfig=configs/%_defconfig Kconfig


可以推测conf会从configs目录下读取对应的defconfig文件进行解析然后保存参数,但我看了一下scripts/kconfig/conf.c 的代码,发现实在是过于复杂,恕博主不继续深入分析,如果以后有时间会再继续研究。
(*)分析if_changed规则:
scripts/Kbuild.include:
7:squote  := '

30:escsq = $(subst $(squote),'\$(squote)',$1)

217:echo-cmd = $(if $($(quiet)cmd_$(1)),\
218:echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)

234:ifneq ($(KBUILD_NOCMDDEP),1)
235:# Check if both arguments has same arguments. Result is empty string if equal.
236:# User may override this check using make KBUILD_NOCMDDEP=1
237:arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
238:                    $(filter-out $(cmd_$@),   $(cmd_$(1))) )
239:else
240:arg-check = $(if $(strip $(cmd_$@)),,1)
241:endif

249:make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1)))))

253:any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)

-> 257:if_changed = $(if $(strip $(any-prereq) $(arg-check)),              \
258:    @set -e;                                                            \
259:    $(echo-cmd) $(cmd_$(1));                                            \
260:    printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

314:echo-why = $(call escsq, $(strip $(why)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

这里简单分析一下if_changed规则:

首先
any-prereq, arg-check
目标是检测目标和依赖是否存在或有更新

set -e
 发生错误后立即停止,此处是为了不让错误像滚雪球一样越来越多。

echo-cmd
 由于是”安静模式”下进行编译的,所以这个参数会被展开成: 
echo
' quiet_cmd_cmd(1) ';
此处忽略why, 编译的时候也没出现why信息, 估计是被屏蔽了(KBUILD_VERBOSE不等于2)

所以259行可以展开成: 
echo ' quiet_cmd_cmd(1) '; $(cmd_$(1));
 即先打印信息,然后执行命令 

大家分析命令的时候可以搜索 quiet_cmd_xxx, 还有cmd_xxx, “xxx”是调用call函数时传入的命令参数


3.2 总结:

依赖关系如下:
all -> u-boot.bin -> u-boot-nodtb.bin -> u-boot |-> u-boot-init -> head-y (start.o)    -> start.S
|-> u-boot-main -> libs-y (built-in.o) -> obj-y ...
1
2
1
2


4. 初次编译u-boot


4.1 配置:

首先大家需要配置交叉编译选项,编辑顶层目录Makefile: 
vi Makefile


查找一下
CROSS_COMPILE
这个参数, 然后直接在下面添加:
ARCH = arm
CROSS_COMPILE = arm-linux-
1
2
1
2

博主使用的开发板是s3c2440,但是configs目录下没有smdk2440_defconfig这个文件,只有smdk2410_defconfig: 

执行:
make smdk2410_config


如果大家更新了交叉编译工具,应该能配置成功,当然现在u-boot也支持menuconfig了,所以大家可以直接执行: 
make menuconfig


然后在menuconfig中进行配置


4.2 编译:

配置完之后就可以进行编译了,执行: 
make


编译成功后会生成一个u-boot.bin,可以烧写到开发板上,不过一般是用不起来的,需要进一步修改


5. 分析u-boot启动流程

想要分析启动流程,第一步就是分析链接文件,弄清楚程序入口是哪里。在第三步分析Makefile中,u-boot的依赖中可以看到链接脚本文件是u-boot.lds,这个文件是通过编译生成的,为了方便,我们就不分析生成规则了,编译成功后在顶层目录就可以看到u-boot.lds 

打开u-boot.lds:
6:  . = 0x00000000;
7:  . = ALIGN(4);
8:  .text :
9:  {
10:   *(.__image_copy_start)
11:   *(.vectors)
12:   arch/arm/cpu/arm920t/start.o (.text*)
13:   *(.text*)
14:  }
1
2
3
4
5
6
7
8
9
1
2
3
4
5
6
7
8
9

很明显,程序的第一条指令在arch/arm/cpu/arm920t/start.S中,当然这是我配置smdk2410过后得到的u-boot.lds文件,不能一概而论


5.1 分析start.S

arch/arm/cpu/arm920t/start.S:
/*
*  armboot - Startup Code for ARM920 CPU-core
*
*  Copyright (c) 2001  Marius Gröger <mag@sysgo.de>
*  Copyright (c) 2002  Alex Züpke <azu@sysgo.de>
*  Copyright (c) 2002  Gary Jennejohn <garyj@denx.de>
*
* SPDX-License-Identifier: GPL-2.0+
*/

#include <asm-offsets.h>
#include <common.h>
#include <config.h>

/*
*************************************************************************
*
* Startup Code (called from the ARM reset exception vector)
*
* do important init only if we don't start from memory!
* relocate armboot to ram
* setup stack
* jump to second stage
*
*************************************************************************
*/

.globl  reset

reset:
/*
* set the cpu to SVC32 mode    1. 设置为SVC模式
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0

#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
/*
* relocate exception table
*/
ldr r0, =_start
ldr r1, =0x0
mov r2, #16
copyex:
subs    r2, r2, #1
ldr r3, [r0], #4
str r3, [r1], #4
bne copyex
#endif

#ifdef CONFIG_S3C24X0
/* turn off the watchdog */

# if defined(CONFIG_S3C2400)
#  define pWTCON    0x15300000
#  define INTMSK    0x14400008  /* Interrupt-Controller base addresses */
#  define CLKDIVN   0x14800014  /* clock divisor register */
#else
#  define pWTCON    0x53000000  /* 看门狗控制寄存器地址 */
#  define INTMSK    0x4A000008  /* Interrupt-Controller base addresses */
#  define INTSUBMSK 0x4A00001C
#  define CLKDIVN   0x4C000014  /* clock divisor register */
# endif

ldr r0, =pWTCON        //2. 关看门狗
mov r1, #0x0
str r1, [r0]

/*
* mask all IRQs by setting all bits in the INTMR - default
*/
mov r1, #0xffffffff    //3. 屏蔽中断
ldr r0, =INTMSK
str r1, [r0]
# if defined(CONFIG_S3C2410)
ldr r1, =0x3ff
ldr r0, =INTSUBMSK
str r1, [r0]
# endif

/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0, =CLKDIVN      //4. 设置分频系数,未设置时钟频率
mov r1, #3
str r1, [r0]
#endif  /* CONFIG_S3C24X0 */

/*
* we do sys-critical inits only at reboot,
* not when booting from ram!
*/
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl  cpu_init_crit    //5. 跳到cpu_init_crit函数
#endif

bl  _main           //6. 进入arch/arm/lib/crt0.S的_main函数,进行其他初始化

/*------------------------------------------------------------------------------*/

.globl  c_runtime_cpu_setup
c_runtime_cpu_setup:

mov pc, lr

/*
*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************
*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches      [1]. 清除cache
*/
mov r0, #0
mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */

/*
* disable MMU stuff and caches  [2]. 禁止MMU
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit 1 (A) Align
orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
mcr p15, 0, r0, c1, c0, 0

#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
/*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr

bl  lowlevel_init          //[3]. 进入board/samsung/smdk2410/lowlevel_init.S执行,
//     设置内存控制寄存器时序参数
mov lr, ip
#endif
mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152


5.2 分析crt0.S

arch/arm/lib/crt0.S:(对部分注释进行了翻译)
/*
*  crt0 - C-runtime startup Code for ARM U-Boot
*
*  Copyright (c) 2012  Albert ARIBAUD <albert.u.boot@aribaud.net>
*
* SPDX-License-Identifier: GPL-2.0+
*/

#include <config.h>
#include <asm-offsets.h>
#include <linux/linkage.h>
#ifdef CONFIG_CPU_V7M
#include <asm/armv7m.h>
#endif

/*
* This file handles the target-independent stages of the U-Boot
* start-up where a C runtime environment is needed. Its entry point
* is _main and is branched into from the target's start.S file.
*
* _main execution sequence is:
*
* 1. Set up initial environment for calling board_init_f().
*    This environment only provides a stack and a place to store
*    the GD ('global data') structure, both located in some readily
*    available RAM (SRAM, locked cache...). In this context, VARIABLE
*    global data, initialized or not (BSS), are UNAVAILABLE; only
*    CONSTANT initialized data are available. GD should be zeroed
*    before board_init_f() is called.
*
* 1. _main函数首先设置栈,然后预留一定的内存空间给gd_t结构体并清零,用来存放全局参数,
*    然后调用board_init_f();
*
* 2. Call board_init_f(). This function prepares the hardware for
*    execution from system RAM (DRAM, DDR...) As system RAM may not
*    be available yet, , board_init_f() must use the current GD to
*    store any data which must be passed on to later stages. These
*    data include the relocation destination, the future stack, and
*    the future GD location.
*
* 2. board_init_f()这个函数调用一系列函数来初始化硬件以使程序能够在SDRAM中执行,
*    且这个函数需要使用1.中设置好的gd_t结构体来存放初始化中的各个参数以备后用
*    比如:重定位地址,重定位后的栈地址、gd_t的地址
*
* 3. Set up intermediate environment where the stack and GD are the
*    ones allocated by board_init_f() in system RAM, but BSS and
*    initialized non-const data are still not available.
*
* 3. 由于BSS段还没初始化,board_init_f()设置gd_t时不能使用全局变量、静态变量等,
*    所以设置的环境参数不是最终的
*
* 4a.For U-Boot proper (not SPL), call relocate_code(). This function
*    relocates U-Boot from its current location into the relocation
*    destination computed by board_init_f().
*
* 4b.For SPL, board_init_f() just returns (to crt0). There is no
*    code relocation in SPL.
*
* 4. smdk_2410没有定义SPL,所以会在_main()函数中根据board_init_f设置的重定位参数进行代码重定位。
*
* 5. Set up final environment for calling board_init_r(). This
*    environment has BSS (initialized to 0), initialized non-const
*    data (initialized to their intended value), and stack in system
*    RAM (for SPL moving the stack and GD into RAM is optional - see
*    CONFIG_SPL_STACK_R). GD has retained values set by board_init_f().
*
* 5. 重定位后,BSS和non-const data都被初始化了,在进入board_init_r函数之前应先设置最终的环境参数
*
* 6. For U-Boot proper (not SPL), some CPUs have some work left to do
*    at this point regarding memory, so call c_runtime_cpu_setup.
*
* 7. Branch to board_init_r().
*
* For more information see 'Board Initialisation Flow in README.
*/

/*
* entry point of crt0 sequence
*/

ENTRY(_main)

/*
* Set up initial C runtime environment and call board_init_f(0).
*/

#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)    //1. 设置栈
#endif
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
#endif
mov r0, sp
bl  board_init_f_alloc_reserve    //2. 为gd_t结构体保留空间
mov sp, r0
/* set up gd here, outside any C code */
mov r9, r0
bl  board_init_f_init_reserve    //3. 初始化gd_t(清零)
//gd_t的地址存在r9寄存器中,结构体中存放的是全局参数

mov r0, #0
bl  board_init_f           //4. 进入board_init_f进行各种初始化,分配SDRAM内存空间,填充进gd_t结构体中

#if ! defined(CONFIG_SPL_BUILD)

/*
* Set up intermediate environment (new sp and gd) and call
* relocate_code(addr_moni). Trick here is that we'll return
* 'here' but relocated.
*/

ldr sp, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp */
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination */
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7  /* 8-byte alignment for ABI compliance */
#endif
ldr r9, [r9, #GD_BD]        /* r9 = gd->bd */
sub r9, r9, #GD_SIZE        /* new GD is below bd */
//5. 将重定位后的GD地址放入r9中
adr lr, here
ldr r0, [r9, #GD_RELOC_OFF]     /* r0 = gd->reloc_off */
add lr, lr, r0
#if defined(CONFIG_CPU_V7M)
orr lr, #1              /* As required by Thumb-only */
#endif
ldr r0, [r9, #GD_RELOCADDR]     /* r0 = gd->relocaddr */
b   relocate_code       //6. 重定位代码,地址是gd->relocaddr
here:                       //7. 在SDRAM中运行
/*
* now relocate vectors
*/

bl  relocate_vectors    //重定位中断向量表

/* Set up final (full) environment */

bl  c_runtime_cpu_setup /* we still call old routine here */
#endif
#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_FRAMEWORK)
# ifdef CONFIG_SPL_BUILD
/* Use a DRAM stack for the rest of SPL, if requested */
bl  spl_relocate_stack_gd
cmp r0, #0
movne   sp, r0
movne   r9, r0
# endif
ldr r0, =__bss_start    /* this is auto-relocated! */
//8. 清BSS
#ifdef CONFIG_USE_ARCH_MEMSET
ldr r3, =__bss_end      /* this is auto-relocated! */
mov r1, #0x00000000     /* prepare zero to clear BSS */

subs    r2, r3, r0      /* r2 = memset len */
bl  memset
#else
ldr r1, =__bss_end      /* this is auto-relocated! */
mov r2, #0x00000000     /* prepare zero to clear BSS */

clbss_l:cmp r0, r1          /* while not at end of BSS */
#if defined(CONFIG_CPU_V7M)
itt lo
#endif
strlo   r2, [r0]        /* clear 32-bit BSS word */
addlo   r0, r0, #4      /* move to next */
blo clbss_l
#endif

#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
#endif
/* call board_init_r(gd_t *id, ulong dest_addr) */
mov     r0, r9                  /* gd_t */
ldr r1, [r9, #GD_RELOCADDR] /* dest_addr */
/* call board_init_r */
#if defined(CONFIG_SYS_THUMB_BUILD)
ldr lr, =board_init_r   /* this is auto-relocated! */
bx  lr
#else
ldr pc, =board_init_r   /* this is auto-relocated! */     //9. 调用board_init_r
#endif
/* we should not return here. */
#endif

ENDPROC(_main)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195


5.3 总结

5.3.1 start.S中: 

(1) 将CPU设为SVC模式 

(2) 关看门狗 

(3) 屏蔽中断 

(4) 设置分频系数,未设置时钟频率 

(5) 
bl cpu_init_crit
 

  [1]清除caches 

  [2] 禁止 MMU cache 

  [3] 
bl lowlevel_init
  在重定位之前,需要设置好内存管理器的各时序参数,这个函数的源文件在对应的单板目录中。对于smdk2410, 在board/samsung/smdk2410/lowlever_init.S 中定义了这个函数

(6) 
bl _main
 在arch/arm/lib/crt0.S中定义

5.3.2 crt0.S中: 

(1) 设置栈,使程序可以在运行C代码 

(2) 
bl board_init_f_alloc_reserve
 给gd_t预留空间,gd_t是global_data结构体,里面存放了各种硬件相关参数,一般将gd_t的地址存放在r9中 

(3) 
bl board_init_f_init_reserve
 初始化gd_t(清零) 

(4) 
bl board_init_f
 在这里面进行各种初始化,分配内存空间,填充gd_t结构体 

(5) 在代码重定位前,将重定位后的GD地址放入r9中 

(6) 重定位代码,地址是gd->relocaddr 

(7) 进入SDRAM中运行 

(8) 清bss段 

(9) 进入board_init_r()进行其他初始化(不返回)

至此,我们的初步分析就到这里结束,下面将开始分析如何添加单板,以及如何修改启动代码使串口有输出

转载至:http://blog.csdn.net/funkunho/article/details/52458148
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: