嵌入式启动之四:S5PV210 IROM BL0启动

三星S5PV210基于A8内核,是arm v7体系,广泛应用于手机和平板解决方案中。市场上也有很多基于S5PV210芯片的开发板(如smart210, gec210等),用于学习高级ARM体系编程。S5PV210跟S5PC11X基本一致,很多人认为两者是同样的SOC,只不过是封装不同,事实上,两者确实略有不同。跟S5PC11X相比,S5PV210没有内置16MSRAM和电源管理模块,解码能力也有些许不同。但从软件使用的角度,两者在内核体系、集成模块、管脚封装上确实有很大的相似性,以致UBOOT在命名上看来,其只支持S5PC11X,但事实上,将支持S5PC11X的UBOOT移植支持S5PV210的工作量相当小。主要的工作就是将16M的SRAM和PMIC初始化支持注释掉。从本篇博文开始,详细讲解S5PV210的启动过程,下面阐述启动的第一个阶段--IROM的BL0启动。

嵌入式启动之二:资源宽裕型嵌入式系统已经说明内存资源宽裕型系统的一般启动过程。S5PV210属于这一类系统,外挂SDRAM内存和NAND、SD卡等外存设备,系统和应用代码等作为固件存放在外存设备中,并通过S5PV210内置的IROM启动并逐步引导到SDRAM中。S5PV210的SPEC是《S5PV210_UM_REV1.1.pdf》,在其第29页~30页中描述了IROM和IRAM的内存映射图。IRAM,即内置RAM,在启动引导阶段有两个作用:一是IROM运行时使用的数据变量所在的区域,二是IROM,即BL0会将外存中的BL1引导到该区域中。因为IROM启动运行的时候,外置SDRAM还没有初始化好,而IRAM是可用的,因此必须要把BL1加载到IRAM中运行,由BL1对SDRAM进行初始化。IROM为什么不初始化SDRAM呢?那是因为支持的SDRAM规格是可变的,由固化代码来初始化显得不够灵活,而且固化代码往往代码量比较小,因为越多越容易出BUG,出BUG就会导致SOC芯片重新掩膜tapout,一次可要好几百万人民币呢。由内存映射图可以得到:

IROM是64K,在0x0000-0000开始的区域,而IRAM是96K,在0xD0020000-0xD0037FFF。

S5PV210的IROM的SPEC是《S5PV210_iROM_ApplicationNote_Preliminary.pdf》,其主要描述以下内容:

1. 启动过程,如下图:

这个图的信息量比较大,描述了启动引导过程大部分的知识点。

1)BL0位于IROM中,其选择引导的介质受外围引脚OM电平所决定。其能引导的介质包括:nor,nand,onenand,SD/MMC等等。如下图,0x2表示nand(page为2k byte,5个command周期,8bit ECC)启动,0xc表示SD/MMC。OM的值可以通过读寄存器0xE000-0004得到。

2)根据OM的值,IROM中的BL0选择其固话的对应驱动将对应介质的前16K代码数据读到IRAM中。引导代码之后会进行校验,校验和BL1的长度信息放在16K代码数据的最前面16个字节。为什么需要长度?因为校验是对确定长度的内容进行计算得到,而BL1的有效代码数据可能并没有16K。BL1头部信息和校验算法如下图:

加载BL1之后,BL0会将给PC赋值为0xd0020010,即BL1代码真正的入口应该设置链接到0xd0020010。在编译链接生存BL1之后需要用专门的工具计算出BL1的长度和校验码,并填充到BL1的头部,在uboot中称为NAND_SPL.BIN。

3)启动过程中的示意图的第三步只是一种方案的建议,在实际的启动模块中,BL2一般比较大,因为其包括引导操作系统,还包括在启动阶段支持下载等交互功能,所以BL2会大于IRAM中剩下的80K,因此,BL1执行时会先初始化好SDRAM,然后将BL2引导到SDRAM。因此图中的第三步示意图并不准确。BL1执行时MMU是关闭的,其在建立好临时页表后,会开启MMU,并跳转到BL2开始执行。

4)BL2会提供与用户交互的模式命令,一般用于研发人员调试,如果是真正的产品则没有这种模式,直接开始引导OS到SDRAM。并跳转到OS开始执行。

5)一般的启动流程图如下:

从上图可以得知,当引导OM所对应的介质的BL1失败(如介质接口有问题、校验失败等)时,还有另外的备选引导方案,即2nd boot,那就是USB引导和串口引导,这里不再展开。

2. IROM除了引导之后,还做了一些硬件和软件环境初始化工作。主要流程包括:

1)关闭看门狗

2)初始化指令cache,开启指令cache

3)初始化 IRAM中的栈(中断栈、SVC栈)和堆,异常向量注册表等。具体如下图:

IROM运行是处于SVC模式。这里的exception vector table并不是异常向量表,而应该称为异常向量注册表。因为异常向量表是在IROM的起始位置上,即0x00000000开始的地方,如下所示,IROM建立起的环境只能支持中断(异常的一种)注册,即注册到0xd0037418,对于其他异常的支持需要在启动或者OS阶段进行重建,并将其定位到SDRAM区域,并设置异常向量的基地址(通过改变协处理器P15的C12-Vector
Base Address Register)指向该区域。

_start: b reset

.word 0x0

.word 0x0

.word 0x0

.word 0x0

.word 0x0

ldr pc, _irq

.word 0x0

4)填充好IRAM的块设备读接口区域。如上图,0xd0037f80开始的128个字节存放的是块设备的拷贝函数地址,如nand,sd/mmc等的读接口地址。其用于后续BL1和BL2使用。即BL1和BL2代码不需要实现外存设备的读驱动函数,只需要调用IROM的接口就可以了。SPEC的p14-p18具体描述了各种不同的介质设备的操作接口地址以及相关的信息。

5)开启PLL,初始化系统时钟。

6)copy 16k字节的BL1到SRAM。

7)对BL1进行校验,即计算BL1的校验值,并与BL1的头部的校验值进行比较,失败即会跳到2nd boot中去引导,成功即跳到BL1的0xd0020010执行。

后续将详细描述基于S5PV210的uboot启动过程,欢迎关注。

时间: 2024-08-05 21:17:05

嵌入式启动之四:S5PV210 IROM BL0启动的相关文章

【ARM】S5PV210芯片的启动流程

S5PV210芯片的设计者的思想 (1)芯片启动后执行iRom(BL0)的内容,进行时钟和看门狗等外设的初始化,将BL1和BL2拷贝到片内SRAM; (2)跳转到片内SRAM执行,完成外部SDRAM的初始化,并将OS从存储设备拷贝到SDRAM内; (3)跳转到SRAM内执行OS的起始代码. 由于U-BOOT的大小的限制,无法全部拷贝到片内的SRAM,所以U-BOOT的设计者设计了一下流程 (1)芯片启动后执行iRom(BL0)的内容,进行时钟和看门狗等外设的初始化,将BL1拷贝到片内SRAM;

OpenFire源码学习之四:openfire的启动流程

openfire启动 ServerStarter 启动流程图: 启动的总入口在ServerStarter的main方法中.通过上图首先它会先加载它所需要的jar文件.最后通过java反射机制将XMPPServer加入当前线程. Thread.currentThread().setContextClassLoader(loader); Class containerClass = loader.loadClass( "org.jivesoftware.openfire.XMPPServer&quo

Linux嵌入式驱动学习之路⑥u-boot启动内核

内核启动是需要必要的启动参数.不能开机自动完全从0开始启动,需要uboot帮助内核实现重定位并提供参数. 首先,uboo会从Kernel分区中读取bootcmd环境变量,根据环境变量可自动启动. 分区: 每个硬盘上都有一个分区表.由于Flash中没有分区表,所以Flash的分区只能在源代码中定义,故无法更改. mtdparts=nandflash0:[email protected]0(bootloader),128k(params),2m(kernel),-(root) 注:@0 表示从0开始

(转)OpenFire源码学习之四:openfire的启动流程

转:http://blog.csdn.net/huwenfeng_2011/article/details/43413233 openfire启动 ServerStarter 启动流程图: 启动的总入口在ServerStarter的main方法中.通过上图首先它会先加载它所需要的jar文件.最后通过Java反射机制将XMPPServer加入当前线程. [java] view plain copy Thread.currentThread().setContextClassLoader(loade

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938396.html 在基本分析完内核启动流程的之后,还有一个比较重要的初始化函数没有分析,那就是do_basic_setup.在内核init线程中调用了do_basic_setup,这个函数也做了很多内核和驱动的初始化工作,详解

Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 【转】

原文地址:Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938390.html 在构架相关的汇编代码运行完之后,程序跳入了构架无关的内核C语言代码:init/main.c中的start_kernel函数,在这个函数中Linux内核开始真正进入初始化阶段, 下面我就顺这代码逐个函数的解释,但是这里并不会过于深入

Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938393.html 在分析start_kernel函数的时候,其中有构架相关的初始化函数setup_arch. 此函数根据构架而异,对于ARM构架的详细分析如下: void __init setup_arch(char **cmdlin

双系统修改启动项顺序&&&修改开机启动等待时间

1. 双系统修改启动项顺序 更改/etc/grub.d目录 下的文件名是可行的 默认情况下Windows 7对应的文件名是30_os-prober,第一个linux系统对应的是10-linux,00是header,05是debian-theme,可见10是第一个启动项,只需要更改Windows 7的文件名(06-09均可)即可改变启动顺序,经我测试,成功地修改了启动顺序. 具体做法: sudo mv /etc/grub.d/30_os-prober /etc/grub.d/08_os-probe