基于tiny210的barebox分析(二)

代码分析

在上一篇文章中,我们已经对barebox的编译、烧写和运行有了一个大致的了解,

现在我们就要开始学习代码了。

arch/arm/cpu/start.c line126

void __naked __section(.text_entry) start(void)
{
	barebox_arm_head();
}

一般的bootloader都会以一个汇编文件作为起始,但是barebox没有这样。

这个c函数作为了整个iamge的入口,关键是__section(.text_entry)和lds文件起了作用。

lds文件是arch/arm/lib/barebox.lds.S,它会被编译成barebox.lds并最终参与链接。

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(start)
SECTIONS
{
 . = 0x23e00000;

 . = ALIGN(4);
 .text :
 {
  _stext = .;
  _text = .;
  *(.text_entry*)
  __bare_init_start = .;
  *(.text_bare_init*)
  __bare_init_end = .;
  __exceptions_start = .;
  KEEP(*(.text_exceptions*))
  __exceptions_stop = .;
  *(.text*)
 }

*(.text_entry*)就相当于把start函数关联进了lds文件,然后ENTRY(start)又指定整个image的入口,于是start函数就成了整个image的入口。

而0x23e00000则是dram中的地址,后面barebox会把自己拷贝到这个地址并跳转过去。

我们继续来看代码,

arch/arm/include/asm/barebox-arm-head.h line54

static inline void barebox_arm_head(void)
{
	__barebox_arm_head();
	__asm__ __volatile__ (
		"b barebox_arm_reset_vector\n"
	);
}
arch/arm/include/asm/barebox-arm-head.h line20

static inline void __barebox_arm_head(void)
{
	__asm__ __volatile__ (
#ifdef CONFIG_THUMB2_BAREBOX
		".arm\n"
		"adr r9, 1f + 1\n"
		"bx r9\n"
		".thumb\n"
		"1:\n"
		"bl 2f\n"
		".rept 10\n"
		"1: b 1b\n"
		".endr\n"
#else
		"b 2f\n"
		"1: b 1b\n"
		"1: b 1b\n"
		"1: b 1b\n"
		"1: b 1b\n"
		"1: b 1b\n"
		"1: b 1b\n"
		"1: b 1b\n"
#endif
		".asciz \"barebox\"\n"
		".word _text\n"				/* text base. If copied there,
							 * barebox can skip relocation
							 */
		".word _barebox_image_size\n"		/* image size to copy */
		".rept 8\n"
		".word 0x55555555\n"
		".endr\n"
		"2:\n"
	);
}

这两个函数都是inline函数,所以代码都会被内嵌到start函数中去。

于是c函数start其实就变成了一个汇编函数。

我们可以看到,在汇编代码的最前端,连续的8个跳转,其实是模仿arm的8个异常向量。

但在这里其实并没有什么作用,只是简单的做了下跳转到2,并在中间留了一些空间保存了一些数据。

先是一个8个字节大小的字符串barebox,然后是两个4字节变量,一个保存的是barebox的链接地址,还有个是barebox的大小,最后则是连续8个0x55555555。

从我们之前dump的barebox.bin可以看出,这和我们想的完全一致。

0000000 0012 ea00 fffe eaff fffe eaff fffe eaff
0000010 fffe eaff fffe eaff fffe eaff fffe eaff
0000020 6162 6572 6f62 0078 0000 23e0 3fe8 0001
0000030 5555 5555 5555 5555 5555 5555 5555 5555
*
0000050 0013 ea00 e000 e04e f00e e1a0 c03c e59f

这里链接地址是0x23e00000,大小是0x13fe8。

接下来,程序就会调用arch/arm/boards/friendlyarm-tiny210/lowlevel.c中的barebox_arm_reset_vector函数。

void __bare_init barebox_arm_reset_vector(void)
{
	arm_cpu_lowlevel_init();

#ifdef CONFIG_S3C_PLL_INIT
	s5p_init_pll();
#endif

	debug_led(0, 1);

	if (get_pc() < IRAM_CODE_BASE) /* Are we running from iRAM? */
		/* No, we don't. */
		goto boot;

	s5p_init_dram_bank_ddr2(S5P_DMC0_BASE, 0x20E00323, 0, 0);

	debug_led(1, 1);

	if (! load_stage2((void*)(ld_var(_text) - 16),
				ld_var(_barebox_image_size) + 16)) {
		debug_led(3, 1);
		while (1) { } /* hang */
	}

	debug_led(2, 1);

	jump_sdram(IRAM_CODE_BASE - ld_var(_text));

	debug_led(1, 0);

boot:
	barebox_arm_entry(S3C_SDRAM_BASE, SZ_256M, 0);
}

arm_cpu_lowlevel_init只是预留了一个接口,暂时并没有实现什么功能。

所以第一步做的事情是配置pll。

然后判断当前代码的运行位置。

#define IRAM_CODE_BASE		0xD0020010

假设程序是通过rom code加载到sram运行的话,其pc值必定是从0xD0020000起,外加16个字节的校验,所以就是0xD0020010了。

如果已经是在dram中的话,那就没有必要再初始化dram以及把barebox加载到dram了。

当然,在我们这种正常启动情况下,代码会顺序往下走,进行dram的初始化配置。

dram配置完毕后,就把整个barebox从sd卡读取到dram中去。

static __bare_init bool load_stage2(void *dest, size_t size)
{
	/* TODO add other ways to boot */
	return s5p_irom_load_mmc(dest, 1, (size+ 511) / 512);
}
#define ADDR_V210_SDMMC_BASE	0xD0037488
#define ADDR_CopySDMMCtoMem	0xD0037F98

int __bare_init s5p_irom_load_mmc(void *dest, uint32_t start_block, uint16_t block_count)
{
	typedef uint32_t (*func_t) (int32_t, uint32_t, uint16_t, uint32_t*, int8_t);
	uint32_t chbase = readl(ADDR_V210_SDMMC_BASE);
	func_t func = (func_t)readl(ADDR_CopySDMMCtoMem);
	int chan = (chbase - 0xEB000000) >> 20;
	if (chan != 0 && chan != 2)
		return 0;
	return func(chan, start_block, block_count, (uint32_t*)dest, 0) ? 1 : 0;
}

这里又要用到s5pv210的一个特殊功能,它的rom code提供了从sd卡读取数据的函数

所以只要直接调用这个地址就可以实现barebox的加载了。

最后一步就是通过jump_sdram跳转到dram中去,这之后运行的barebox_arm_entry函数,就是运行在dram中的了。

static __bare_init __naked void jump_sdram(unsigned long offset)
{
	__asm__ __volatile__ (
			"sub lr, lr, %0;"
			"mov pc, lr;" : : "r"(offset)
			);
}

这里还有一点需要注意,我们可以发现,在跳转到dram之前运行的函数都是有__bare_init的

#define __bare_init          __section(.text_bare_init.text)

在lds文件中是紧随*(.text_entry*)之后的。

估计是因为barebox的链接地址是dram中的地址,所以刚开始在sram中运行时被调用的函数都需要靠近以保证跳转时使用的是相对偏移而不是绝对地址。

有尝试过去掉某一函数的__bare_init修饰符,会直接导致barebox无法正常运行。

基于tiny210的barebox分析(二),布布扣,bubuko.com

时间: 2024-08-06 03:21:45

基于tiny210的barebox分析(二)的相关文章

基于tiny210的barebox分析(一)

barebox是一个bootloader,虽然不如uboot那么出名,但是相对uboot风格上更像linux kernel,而且相对简单,更有利于我们对启动做一个详细深入的学习. 全文分析的barebox的版本是barebox-2014.05.0 编译 首先是下载并解压barebox-2014.05.0, 默认这个版本就对tiny210有不错的支持,我们只需要用下面这些命令就可以了 export ARCH=arm export CROSS_COMPILE=/home/panzhenjie/too

netty 源码分析二

以服务端启动,接收客户端连接整个过程为例分析, 简略分为 五个过程: 1.NioServerSocketChannel 管道生成, 2.NioServerSocketChannel 管道完成初始化, 3.NioServerSocketChannel注册至Selector选择器, 4.NioServerSocketChannel管道绑定到指定端口,启动服务 5.NioServerSocketChannel接受客户端的连接,进行相应IO操作 Ps:netty内部过程远比这复杂,简略记录下方便以后回忆

十三种基于直方图的图像全局二值化算法原理、实现、代码及效果(转)

十三种基于直方图的图像全局二值化算法原理.实现.代码及效果(转) http://www.cnblogs.com/carekee/articles/3643394.html 图像二值化的目的是最大限度的将图象中感兴趣的部分保留下来,在很多情况下,也是进行图像分析.特征提取与模式识别之前的必要的图像预处理过程.这个看似简单的问题,在过去的四十年里受到国内外学者的广泛关注,产生了数以百计的阈值选取方法,但如同其他图像分割算法一样,没有一个现有方法对各种各样的图像都能得到令人满意的结果. 在这些庞大的分

基于Qt的信号分析简单应用软件的设计

一.需求描述: 1.读取data.asc文件,分析其连续性: 2.绘制信号图像,并保存. 二.UI界面组成: 该应用的UI由以下几个控件组成: 3个PushButton:打开文件.图像保存.退出: 1个Combox:下拉框用于信号的选择: 1个Widget:用于确定绘图区域的坐标,并在Widget部件上绘制图像曲线. 3个Label:用于标注注释,及坐标轴 三.主要功能的实现 信号分析结果如下: 其中最主要的涉及信号数据的标准化处理,标准化处理计算公式: std=(当前信号值-此类信号的最小值)

Java线程池使用和分析(二) - execute()原理

相关文章目录: Java线程池使用和分析(一) Java线程池使用和分析(二) - execute()原理 execute()是 java.util.concurrent.Executor接口中唯一的方法,JDK注释中的描述是“在未来的某一时刻执行命令command”,即向线程池中提交任务,在未来某个时刻执行,提交的任务必须实现Runnable接口,该提交方式不能获取返回值.下面是对execute()方法内部原理的分析,分析前先简单介绍线程池有哪些状态,在一系列执行过程中涉及线程池状态相关的判断

MapReduce源码分析之MapTask分析(二)

SpillThread分析 为什么需要Spill 内存大小总是有效,因此在Mapper在处理过程中,数据持续输出到内存中时,必然需要有机制能将内存中的数据换出,合理的刷出到磁盘上.SpillThread就是用来完成这部分工作. SpillThread的线程处理函数只是做一层封装,当索引表中的kvstart和kvend指向一样的索引位置时,会持续处于等待过程,等待外部通知需要触发spill动作,当有spill请求时,会触发StartSpill来唤醒SpillThread线程,进入到sortAndS

转:基于内容的视频分析与检索

摘要 文章简要介绍了从基于内容的视频分析与检索问题的提出到所涉及的关键技术以及目前研究状况,并简要介绍了现阶段在这方面的研究热点及以后要做的工作. 一.问题的提出: 互联网的出现给人类带来了很大的便利,特别是实现资源共享之后的互联网,但面对这浩如烟海的资源到底哪些是对自己有利用价值的呢?而90年代以来,多媒体技术和网络技术的突飞猛进,人们正快速的进入一个信息化社会.现代技术已能运用各种手段采集和生产大量各种类型的多媒体信息数据,出现了数字图书馆.数字博物馆.数字电影.可视电话.交互电视.会议电视

《Objective-C Runtime分析(二)-Class,Method,SEL,IMP》

本系列主要参考资料:Objective-C Runtime ReferenceObjective-C Runtime Programming Guide涉及主要文件:objc/message.h,objc/objc-api.h,objc/objc.h,objc/runtime.h 特酷吧[tekuba.net]采用"署名-非商业用途-保持一致"的创作共用协议,使用本文内容请遵循该协议 Objective-C Runtime是Objective-C的基础内容,理解了Objective-C

基于TableStore的数据采集分析系统介绍

摘要: 摘要 在互联网高度发达的今天,ipad.手机等智能终端设备随处可见,运行在其中的APP.网站也非常多,如何采集终端数据进行分析,提升软件的品质非常重要,例如PV/UV统计.用户行为数据统计与分析等.虽然场景简单,但是数据量大,对系统的吞吐量.实时性.分析能力.查询能力都有较高的要求,搭建起来并不容易. 摘要 在互联网高度发达的今天,ipad.手机等智能终端设备随处可见,运行在其中的APP.网站也非常多,如何采集终端数据进行分析,提升软件的品质非常重要,例如PV/UV统计.用户行为数据统计