关键词:
U-BOOT-2016.07移植 (第一篇) 初步分析
目录
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 [email protected]; cp $< [email protected] //输出 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,$<,[email protected],$(CONFIG_SYS_TEXT_BASE))
865: $(BOARD_SIZE_CHECK)
- (4)u-boot
1173:quiet_cmd_u-boot__ ?= LD [email protected]
1174: cmd_u-boot__ ?= $(LD) $(LDFLAGS) $(LDFLAGS_u-boot) -o [email protected]
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 [email protected] //展开来就是:
//@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/[email protected] $(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)), $([email protected])) 238: $(filter-out $([email protected]), $(cmd_$(1))) )
239:else
240:arg-check = $(if $(strip $([email protected])),,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
‘ ‘[email protected] := $(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 <[email protected]>
* Copyright (c) 2002 Alex Züpke <[email protected]>
* Copyright (c) 2002 Gary Jennejohn <[email protected]>
*
* 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 */
5.2 分析crt0.S
arch/arm/lib/crt0.S:(对部分注释进行了翻译)
/*
* crt0 - C-runtime startup Code for ARM U-Boot
*
* Copyright (c) 2012 Albert ARIBAUD <[email protected]>
*
* 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)
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()进行其他初始化(不返回)
至此,我们的初步分析就到这里结束,下面将开始分析如何添加单板,以及如何修改启动代码使串口有输出
对volley的初步分析第一篇
进入android世界已经快要两年了,放眼望去,在这两年的android世界里,自己多少也成长了点,一路上磕磕碰碰,即使现在的我还是android学术界里最垫底的那一位,但还是阻挡不了我对未来android世界的探索的脚步,自从上次我坚... 查看详情
ubuntu14.0464bit编译u-boot-2016.07提示yourdtcistooold,pleaseupgradetodtc1.4ornewer
Author:AP0904225版权声明:本文为博主原创文章,转载请标明出处。Ubuntu14.0464bit环境下编译u-boot-2016.07提示如下错误:CHKinclude/config/uboot.releaseCHKinclude/generated/version_autogenerated.hCHKinclude/generated/timestamp_autogenerated 查看详情
matrix源码分析之第一篇(代码片段)
Matrix源码分析之第一篇概述前几天腾讯将一款Android应用性能监控的框架matrix开源了,源码地址在https://github.com/Tencent/matrix,作者是微信终端团队。matrix到底是什么?据官方说法如下:Matrix是一款微信研发并日常使用的APM(Applicat... 查看详情
初步了解jvm第一篇(代码片段)
大家都知道,Java中JVM的重要性,学习了JVM你对Java的运行机制、编译过程和如何对Java程序进行调优相信都会有一个很好的认知。废话不多说,直接带大家来初步认识一下JVM。什么是JVM?JVM(JavaVirtualMachine)是一个抽象的计算机,和... 查看详情
开发版速达扩展功能-增值业务报表之分析交叉表第一篇
开发版速达目前已经推出了比较多的增值报表,之后还会陆续新增比较有用的增值报表,今天我们就来讲讲只有开发版才有的报表:分析交叉表1.首先我们打开增值报表=>销售业务报表=>销售货品类别金额表,进行日期查询得... 查看详情
初步尝试添加四象限分析法分析项目可课程进展
...或者独特的价值但是对于各个产品,不能平均投资,要在第一象限投入足够的力量。第一象限(解决用户的刚需,同时又是自身的杀手功能)建议采取“ 查看详情
u-boot的移植与分析(第一阶段硬件初始化)(代码片段)
1.UBOOT运行的第一个文件是:cpu/arm920t/start.S(从程序的链接脚本中知道)1.globl_start //.globl定义一个全局符号"_start"2_start:breset //系统复位设置3ldrpc,_undefined_instructio... 查看详情
r数据分析第一篇:温习概率论
概率论是人们在长期实践中发现的理论,是客观存在的。自然界和社会上发生的现象是多种多样的,有一类现象,在一定条件下必然发生,称作确定性现象,而概率论研究的现象是不确定性现象,嗯嗯,醒醒,概率论研究的对象... 查看详情
第一篇数据分析项目实战:用户消费行为分析
...ID,购买日期,购买数量,购买金额四个字段。分析步骤第一部分:数据类型的处理—字段的清洗缺失值的处理、数据类型的转化第二部分:按月数据分析每月的消费总金额、每月的消费次数、每月的产品购买量、每月的消费人... 查看详情
centos7搭建kafka集群-第一篇
Kafka初识1、Kafka使用背景 在我们大量使用分布式数据库、分布式计算集群的时候,是否会遇到这样的一些问题:我们想分析下用户行为(pageviews),以便我们设计出更好的广告位我想对用户的搜索关键词进行统计,分析出当... 查看详情
python从入门到数据分析第一篇—python简介-python介绍与初探(代码片段)
一直以来以分享Python、数据分析、数据科学为主,即使有了大受好评的程序入门系列,但考虑到多数文章使用分析工具都以Python为主,决定撰写这一系列文章帮助刚看完程序,对于Python数据分析感到好奇的朋友入... 查看详情
python从入门到数据分析第一篇—python简介-python介绍与初探(代码片段)
一直以来以分享Python、数据分析、数据科学为主,即使有了大受好评的程序入门系列,但考虑到多数文章使用分析工具都以Python为主,决定撰写这一系列文章帮助刚看完程序,对于Python数据分析感到好奇的朋友入... 查看详情
第一篇:gpu编程技术的发展历程及现状
前言 本文通过介绍GPU编程技术的发展历程,让大家初步地了解GPU编程,走进GPU编程的世界。冯诺依曼计算机架构的瓶颈 曾经,几乎所有的处理器都是以冯诺依曼计算机架... 查看详情
实现手机扫描二维码页面登录,类似web微信-第一篇,业务分析
转自:http://www.cnblogs.com/fengyun99/p/3541249.html关于XMPP组件的文章,先休息两天,好歹已经完整的写了一份。这两天,先实现一套关于web微信扫描二维码页面登录的试验,因为这种模式在我们的很多业务场景里大有前途。首先介绍一... 查看详情
32163165(代码片段)
《2.uboot和系统移植-第17部分-2.17.内核的移植1-从三星官方内核开始移植》 欢迎访问《朱老师物联网大讲堂》官方网站 www.zhulaoshi.org 以获取本课程更多信息第一部分、章节目录2.17.1.内核移植初体验2.17.2.初步移植以看到启动... 查看详情
第一篇:查阅数据
前言 本文讲解如何使用R语言对数据集进行总体上的了解。 在进行数据挖掘之前,我们有必要对挖掘的数据集对象有一个总体的了解。本文采用具体实例讲解的方式,详细演示对一个数据集的... 查看详情
第一篇:什么是docker,可以在那些场景使用?
...,可以轻松而又快速的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、baremetal、OpenStack集群和其他的基础应用平台。Docker系... 查看详情
测开之数据类型・第一篇《python数据类型元祖和列表的性能分析》(代码片段)
前言通常在入门初期我们的目标主要是实现需求为主,但是随着项目的数据量越来越大,我们就需要考虑到程序的性能问题,那么平时我们常用的数据类型,元祖和列表,哪个性能会更好呢?下面我们来通... 查看详情