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) 先创建临时目录tmpmkdir 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)allTop 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:endif1
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.bin1
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:endif1
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 %config1
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
相关文章推荐
- U-BOOT-2016.07移植 (第一篇) 初步分析
- U-BOOT-2016.07移植 (第一篇) 初步分析
- TQ2440的学习——UBOOT移植(NAND FLASH的支持)——初步分析
- u-boot的NAND初始化分析,及cubieboard移植nand驱动初步分析
- u-boot的NAND初始化分析,及cubieboard移植nand驱动初步分析
- u-boot的NAND初始化分析,及cubieboard移植nand驱动初步分析
- U-Boot源码分析与移植
- U-Boot 在44B0X 开发板上的移植以及代码分析
- U-Boot 在44B0X 开发板上的移植以及代码分析
- U-Boot在GOLD44B0X开发板上的移植以及代码分析
- U-BOOT全线移植分析系列之三 U-BOOT在AT91RM9200上的移植
- U-BOOT源码分析及移植
- U-boot在AT91RM9200上的全线移植分析
- 移植U-BOOT到S3C2440板子上对读flash的device ID不对的分析
- u-boot启动过程分析——基于lpc2210的移植代码
- U-Boot在44B0X开发板上的移植以及代码分析
- U-BOOT源码分析及移植
- u-boot启动过程分析——基于lpc2210的移植代码[转]
- U-boot在AT91RM9200上的全线移植分析
- 【嵌入式Linux学习七步曲之第三篇 Linux系统bootlaoder移植】U-BOOT全线移植分析系列之二--U-boot基础