[转]uboot中SPL作用
转:http://blog.csdn.net/voice_shen/article/details/17373671
这篇文章写的非常详细
[u-boot: 2014.01-rc1]
本文将使用sama5d3xek SPL实现做为例子,具体代码可查看:https://github.com/voiceshen/u-boot/tree/sama5d3xek_spl_spi_nand
u-boot SPL (second program loader), 对许多人来说也说很陌生。下面对此进行一个简单介绍。
1. ARM SoC的启动过程:
RomBoot --> SPL --> u-boot --> Linux kernel --> file system --> start application
(RomBoot是固化在SoC内部的。)
u-boot实现了一个新功能,能在编译u-boot的同时生成SPL二进制文件。
2. SPL运行代码go through
从u-boot-spl.lds链接文件可知,启动代码也是start.S。
(reset) <arch/arm/cpu/armv7/start.S> (b lowlevel_init: arch/arm/cpu/armv7/lowlevel_init.S) (b _main) --> <arch/arm/lib/crt0.S> (bl board_init_f) --> <arch/arm/lib/spl.c> (board_init_r) --> <common/spl/spl.c> (jump_to_image_no_args去启动u-boot) 到此SPL的生命周期结束。
简单来讲:SPL所做工作,一些硬件的初始化,然后读取u-boot,最后调转至u-boot。
3. 下面具体分析SPL的相关代码。
<arch/arm/cpu/armv7/start.S>
reset:
bl save_boot_params
/*
113 * disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
114 * except if in HYP mode already
115 */
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0 /*
125 * Setup vector:
126 * (OMAP4 spl TEXT_BASE is not 32 byte aligned.
127 * Continue to use ROM code vector only in OMAP4 spl)
128 */
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTRL register - for VBAR to point to vector */
mrc p15, , r0, c1, c0, @ Read CP15 SCTRL Register
bic r0, #CR_V @ V =
mcr p15, , r0, c1, c0, @ Write CP15 SCTRL Register /* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, , r0, c12, c0, @Set VBAR
#endif /* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
bl cpu_init_crit
#endif bl _main
111:如果没有重新定义save_boot_params,则使用<arch/arm/cpu/armv7/start.S>中的save_boot_params。其不做任何事情,直接返回。
116~138: 看注释即可明白。
141: 因为SPL主要是对SoC进行初始化,所以不会定义CONFIG_SKIP_LOWLEVE_INIT, 即142,143行得以执行。
142: cpu_init_cpu15, 主要作用invalidate L1 I/D cache, disable MMU. 检查是否需要workaround。
143: cpu_init_crit直接跳转到lowlevel_init
下面看看lowlevel_init的实现:
<arch/arm/cpu/armv7/lowlevel_init.S>
ENTRY(lowlevel_init)
/*
20 * Setup a temporary stack
21 */
ldr sp, =CONFIG_SYS_INIT_SP_ADDR
bic sp, sp, # /* 8-byte alignment for ABI compliance */
#ifdef CONFIG_SPL_BUILD
ldr r9, =gdata
#else
sub sp, #GD_SIZE
bic sp, sp, #
mov r9, sp
#endif
/*
32 * Save the old lr(passed in ip) and the current lr to stack
33 */
push {ip, lr} /*
37 * go setup pll, mux, memory
38 */
bl s_init
pop {ip, pc}
ENDPROC(lowlevel_init)
22: 对stack pointer赋值成CONFIG_SYS_INIT_SP_ADDR
23: 确保sp是8字节对齐。
25:将gdata的地址存入到r9寄存器中。
39:跳转到s_init。对Atmel sama5d3xek board, s_init定义在:<arch/arm/cpu/at91-common/spl.c> 此处暂时不分析。
然后返回到start.S处,接下来调用:bl _main到<arch/arm/lib/crt0.S>
ENTRY(_main) /*
61 * Set up initial C runtime environment and call board_init_f(0).
62 */ #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr sp, =(CONFIG_SPL_STACK)
#else
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
bic sp, sp, # /* 8-byte alignment for ABI compliance */
sub sp, #GD_SIZE /* allocate one GD above SP */
bic sp, sp, # /* 8-byte alignment for ABI compliance */
mov r9, sp /* GD is above SP */
mov r0, #
bl board_init_f
65: 重新对SP赋值
69: 确认sp是8字对齐
70:相当于保留一个global_data的大小。
71: 确认更新后的sp是8字对齐
72:r9指向global_data
73:r0赋值0
74:跳转到board_init_f中运行。
board_init_f在<arch/arm/lib/spl.c>定义:
/*
21 * In the context of SPL, board_init_f must ensure that any clocks/etc for
22 * DDR are enabled, ensure that the stack pointer is valid, clear the BSS
23 * and call board_init_f. We provide this version by default but mark it
24 * as __weak to allow for platforms to do this in their own way if needed.
25 */
void __weak board_init_f(ulong dummy)
{
/* Clear the BSS. */
memset(__bss_start, , __bss_end - __bss_start); /* Set global data pointer. */
gd = &gdata; board_init_r(NULL, );
}
26: board_init_f是一个弱函数,是可以被重新定义的。
29:对BSS段进行清零操作。
34: 跳转到board_init_r
board_init_r在<common/spl/spl.c>中定义:
void board_init_r(gd_t *dummy1, ulong dummy2)
{
u32 boot_device;
debug(">>spl:board_init_r()\n"); #ifdef CONFIG_SYS_SPL_MALLOC_START
mem_malloc_init(CONFIG_SYS_SPL_MALLOC_START,
CONFIG_SYS_SPL_MALLOC_SIZE);
#endif #ifndef CONFIG_PPC
/*
144 * timer_init() does not exist on PPC systems. The timer is initialized
145 * and enabled (decrementer) in interrupt_init() here.
146 */
timer_init();
#endif #ifdef CONFIG_SPL_BOARD_INIT
spl_board_init();
#endif
135: 输出debug信息:>>spl:board_init_r();
137~140: 如果定义了:CONFIG_SYS_SPL_MALLOC_START, 则进行memory的malloc池初始化。以后调用malloc就在这个池子里面分配内存。
142~148: 如果没有定义:CONFIG_PPC, 则进行timer的初始化:timer_init() <arm/arm/cpu/armv7/at91/time.c>
150~150: CONFIG_SPL_BOARD_INIT, 则调用spl_board_init(). 这是board相关的定义,<board/atmel/sama5d3xek/sama5d3xek.c>
一切就绪后,就要检查从什么设备来启动了。这里就贴出RAM,MMC, NAND相关代码
boot_device = spl_boot_device();
debug("boot device - %d\n", boot_device);
switch (boot_device) {
#ifdef CONFIG_SPL_RAM_DEVICE
case BOOT_DEVICE_RAM:
spl_ram_load_image();
break;
#endif
#ifdef CONFIG_SPL_MMC_SUPPORT
case BOOT_DEVICE_MMC1:
case BOOT_DEVICE_MMC2:
case BOOT_DEVICE_MMC2_2:
spl_mmc_load_image();
break;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
case BOOT_DEVICE_NAND:
spl_nand_load_image();
break;
#endif
154: 获取spl_boot_device,即从什么设备启动。
157~161:如果定义了CONFIG_SPL_RAM_DEVICE, 则执行spl_ram_load_image(),其就是将image下载到ram中。
162~168:如果定义了CONFIG_SPL_MMC_SUPPORT, 则执行spl_mmc_load_image(),其就是将image从mmc/sd里面读取到ram中。
169~173:如果定义了CONFIG_SPL_NAND_SUPPORT, 则执行spl_nand_load_image(), 其就是将image从nand flash中读取到ram中。
当要启动的image位于RAM中后,我们就可以启动之。
switch (spl_image.os) {
case IH_OS_U_BOOT:
debug("Jumping to U-Boot\n");
break;
#ifdef CONFIG_SPL_OS_BOOT
case IH_OS_LINUX:
debug("Jumping to Linux\n");
spl_board_prepare_for_linux();
jump_to_image_linux((void *)CONFIG_SYS_SPL_ARGS_ADDR);
#endif
default:
debug("Unsupported OS image.. Jumping nevertheless..\n");
}
jump_to_image_no_args(&spl_image);
}
213: 判断image的类型。
214:如果是u-boot,则直接到227去运行u-boot。
218:如果是Linux,则到221去启动Linux.
至此,SPL结束它的生命,控制权交于u-boot或Linux。
[转]uboot中SPL作用的更多相关文章
- U-boot中SPL功能和源码流程分析
在U-boot目录下,有个比较重要的目录就是SPL的,SPL到底是什么呢?为什么要用它呢? SPL(Secondary programloader)是uboot第一阶段执行的代码.主要负责搬移uboo ...
- u-boot中添加mtdparts支持以及Linux的分区设置
简介 作者:彭东林 邮箱:pengdonglin137@163.com u-boot版本:u-boot-2015.04 Linux版本:Linux-3.14 硬件平台:tq2440, 内存:64M ...
- u-boot中nandflash初始化流程分析(转)
u-boot中nandflash初始化流程分析(转) 原文地址http://zhuairlunjj.blog.163.com/blog/static/80050945201092011249136/ ...
- u-boot中分区和内核MTD分区关系
一.u-boot中环境变量与uImage中MTD的分区关系 分区只是内核的概念,就是说A-B地址放内核,C-D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等. 一般我们只需要分3-4 ...
- uboot中raise:Signal #8 caught的根本原因
在移植uboot时编译一切正常,但uboot启动中载入自己写的网卡驱动出现故障,一直在打印raise:Signal #8 caught google 百度了一番,也有非常多人遇到了这个问题,大家都说 ...
- 基于335X平台的UBOOT中交换芯片驱动移植
基于335X平台的UBOOT中交换芯片驱动移植 一.软硬件平台资料 1.开发板:创龙AM3359核心板,网口采用RMII形式. 2.UBOOT版本:U-Boot-2016.05,采用FDT和DM. 3 ...
- U-Boot中的filesize环境变量
U-Boot中的环境命令可以使用$(filesize)来确定刚下载(传输)得到的文件大小. 因为使用类似tftp命令传输文件后,会自动更新filesize环境变量.如:setenv updateroo ...
- 在u-boot中添加命令
转:http://www.embedu.org/Column/Column464.htm 作者:曾宏安,华清远见嵌入式学院讲师. u-boot是嵌入式系统中广泛使用的一种bootloader.它不仅支 ...
- Uboot中start.S源码的指令级的详尽解析【转】
本文转载自:http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/html/uboot_starts_analys ...
随机推荐
- Ubuntu 14.04中安装最新版Eclipse
Ubuntu 14.04中安装最新版Eclipse 来源:Linux社区 作者:Linux 1.安装OpenJDK Java 7 如果你的系统中没有安装Java,我们需要按照如下步骤事先安装好 ...
- jquery.easyui代码详解,和遇到的问题,提供大家在使用的时候少走弯路(一)
初次使用jquery.easyui这个东东,虽然简单,但还是很费力的去研究了一下使用,在使用过程中遇到的问题,下面代码会详细的注释到 引用的文件jquery.min.js j ...
- 第三个Sprint冲刺第八天
讨论地点:宿舍 讨论成员:邵家文.李新.朱浩龙.陈俊金 讨论问题:做最后的工作
- powerdesigner 生成mysql PDM 的COMMENT注释
1powerdesigner 生成mysql PDM 的COMMENT注释 默认的pd没有生成注释,针对mysql5.0可以如下修改.在Database-->edit Current DBMS. ...
- EF里一对一、一对多、多对多关系的配置
EF关系规则 参考文章:http://www.cnblogs.com/feigao/p/4617442.html Entity Framework 实体间的关系,一对一,一对多,多对多,根据方向性来说 ...
- 105 董婷婷 第一次Sprint总结
总结: 经过一个多星期,第一次Sprint在今天结束了,在这次Sprint中我们的工作主要做的是对项目的构建及各种界面的设计和完善,一些比较具体的功能还没有实现.在这次Sprint中因为有上学期合作的 ...
- 转战网站后台与python
这么长时间了,迷茫的大雾也逐渐散去,正如标题所写的一样,转战网站后台开发.这段时间没怎么写博客,主要还是太忙,忙着期末考试的预习,以及服务器的搭建,python的学习,还有各种各样杂七杂八的小事,就像 ...
- 初学JAVA的 感想 尹鑫磊
开始学习任何一门课(包括java),兴趣最重要.一直觉得自己在学计算机编程语言,学习了很多,但每门语言都停留在知识边缘地带,都没深入到它们的精华部分,对它们的精华部分知之甚少,于是趁学校开设这门课,并 ...
- [转]delete 多表删除的使用
1.从数据表t1中把那些id值在数据表t2里有匹配的记录全删除掉 DELETE t1 FROM t1,t2 WHERE t1.id=t2.id 或 DELETE FROM t1 USING t1,t ...
- PHP开发工具
“工欲善其事,必先利其器”,进行PHP开发,选择一个合适的开发工具是必要的. 1.Zend Studio 如果对PHP开发工具进行一个排名,Zend Studio一定是当之无愧的第一名.它来自Zend ...