linux交叉互译环境的建立,UBOOT2016.07移植(第一篇)初步分析

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

目录

U-BOOT-201607移植 第一篇 初步分析 目录 编译和移植环境 更新交叉编译工具 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/

(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 //保存退出

(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:'%'=%)

可见执行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

展开后: (若无目标或依赖文件更新)

u-boot.bin: u-boot-nodtb.bin FORCE

echo COPY $@; cp $< $@ //输出 COPY u-boot.bin, 然后执行cp u-boot-nodtb.bin u-boot.bin

(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,$

865: $(BOARD_SIZE_CHECK)

(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

(5)u-boot-init,u-boot-main

-> 679:u-boot-init := $(head-y)

-> 680:u-boot-main := $(libs-y)

(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

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 添加进来了

%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: @:

分析到这里,我们可以看出配置单板相关的参数是在 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

' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)

314:echo-why = $(call escsq, $(strip $(why)))

这里简单分析一下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 ...

4. 初次编译u-boot

4.1 配置:

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

vi Makefile

查找一下CROSS_COMPILE这个参数, 然后直接在下面添加:

ARCH = arm

CROSS_COMPILE = arm-linux-

博主使用的开发板是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: }

很明显,程序的第一条指令在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

* Copyright (c) 2002 Alex Züpke

* Copyright (c) 2002 Gary Jennejohn

*

* SPDX-License-Identifier: GPL-2.0+

*/

#include

#include

#include

/*

*************************************************************************

*

* 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 */

5.2 分析crt0.S

arch/arm/lib/crt0.S:(对部分注释进行了翻译)

/*

* crt0 - C-runtime startup Code for ARM U-Boot

*

* Copyright (c) 2012 Albert ARIBAUD

*

* SPDX-License-Identifier: GPL-2.0+

*/

#include

#include

#include

#ifdef CONFIG_CPU_V7M

#include

#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)

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()进行其他初始化(不返回)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值