BootLoader简介:
当完成用户程序的编译并下载到目标板上运行时,总是要首
先进行存储器的映射,然后通过 ADS(或 SDT)调试环境下载,显然,这个过程对
普通用户来说显得特别烦琐,然而,要在裸板(没有任何程序的系统板)上调试运
行程序,也只能采用这种方法。
如果能在用户设计的系统板上烧写一段 BootLoader程序,就可以将该过程屏蔽
起来,让用户通过一些简单的操作,就可完成程序的下载、调试等工作。在嵌入式
系统中,BootLoader的作用与 PC 机上的 BIOS 类似,通过 BootlLoader可以完成对
系统板上的主要部件如 CPU、SDRAM、Flash、串行口等进行初始化,也可以下载
文件到系统板、对 Flash 进行擦除与编程。事实上,一个功能完善的 BootLoader 已
经相当于一个微型的操作系统了。
BootLoader 作为系统复位或上电后首先运行的代码,一般应写入 Flash 存储器
中并从起始物理地址 0x0 开始。BootLoader 根据实现的功能不同,不相同。一个简单的 BootLoader程序可以仅仅完成串行口的初始化,并进行
通信,而功能完善的 BootLoader可以支持比较复杂的命令集,对系统的软硬件资源
进行合理的配置与管理。因此,用户可根据自身的需求实现相应的功能
先进行存储器的映射,然后通过 ADS(或 SDT)调试环境下载,显然,这个过程对
普通用户来说显得特别烦琐,然而,要在裸板(没有任何程序的系统板)上调试运
行程序,也只能采用这种方法。
如果能在用户设计的系统板上烧写一段 BootLoader程序,就可以将该过程屏蔽
起来,让用户通过一些简单的操作,就可完成程序的下载、调试等工作。在嵌入式
系统中,BootLoader的作用与 PC 机上的 BIOS 类似,通过 BootlLoader可以完成对
系统板上的主要部件如 CPU、SDRAM、Flash、串行口等进行初始化,也可以下载
文件到系统板、对 Flash 进行擦除与编程。事实上,一个功能完善的 BootLoader 已
经相当于一个微型的操作系统了。
BootLoader 作为系统复位或上电后首先运行的代码,一般应写入 Flash 存储器
中并从起始物理地址 0x0 开始。BootLoader 根据实现的功能不同,不相同。一个简单的 BootLoader程序可以仅仅完成串行口的初始化,并进行
通信,而功能完善的 BootLoader可以支持比较复杂的命令集,对系统的软硬件资源
进行合理的配置与管理。因此,用户可根据自身的需求实现相应的功能
涉及具体汇编代码前,有些术语要必须弄懂的
O:映像文件(p_w_picpath):指一个可执行文件,在执行的时候被加载到处理器中,它是ELF(Executable and Linking Format)格式的。
O:RO :是Read-Only的简写形式。一般存放的代码
O:RW:是Read-Write 的简写形式,一般存放初始化的数据
O:ZI:是zero-Initialized的简写形式。一般是存放初始化数据
O:输入段(Output Section):它包含一系列具有相同RO,RW,ZI属性的输入段
对于
一个ARM bootloader系统来说,本质上,bootloader作为引导与加载内核镜像的工具,必须提供以下几个功能,更确切地说,必须做到以下几点:
~1~初始化RAM(必需):bootloader应该能初始化RAM,因为将来系统要通过它来保存一些Volatile数据,但具体地实现要求依赖与具体的CPU以及硬件系统。~2~初始化串口(可选),bootloader应该要初始化及使能一个串口,通过
~1~ 它与控制台联系进行一些debug的工作;甚至与PC通信。
创建内核参数列表(针对linux操作系统,推荐)。
启动内核镜像(必需):根据内核镜像保存的存储介质不同,可以有两种启动方式:FALSH启动以及RAM启动;但是无论是哪种启动方式,下面的系统状态必须得到满足:
Bootloader 阶段1的代码实现:
1,定义ARM个模式的栈大小
2,申明各模式的栈
3,将各模式的栈与栈大小结合起来,既为各栈分配栈大小
4,申明一些标号量
5,以某标号标识,一开始处设置异常中断向量表,当冷启动时,直接跳转至对应处启动
6系统正常启动时:1使能各协处理器,2关闭MMU,内部指令/数据cache以及缓冲区,ARM体系bootloader中都无需MMU的功能,所有的地址都直接使用物理地址:cache也都关闭,原因.3
清空TLB,Caches以及写缓冲区,当系统冷启动时所有的保留数据都以无效处理,因此都要清空,况且cache都已经关闭 4
开系统各存储空间域的访问权限;ARM体系中系统的存储空间分为最多的16个域,每个域对应一定的内存区域,该区域具有相同的访问控制属性。MMU中寄存器C3用于控制与域相关属性的配置。(
以上涉及的是相关存储方面通用的处理,接着就要开始具体的硬件初始化的工作了,与
具体的CPU以及具体的存储芯片大小有关。)
1. 屏蔽所有的中断:为中断提供服务通常是操作系统设备驱动程序的责任,因此在bootloader的执行全过程中可以不必相应任何中断,中断屏蔽是通过写CPU提供的中断屏蔽寄存器来完成的。
2. 设置CPU的速度与时钟频率:系统复位后对于CPU的速度与时钟频率都有一个初始的默认值,可以直接使用该值,到内核启动初始化的时候再设置;也可以在此处直接设置。
3. SDRAM 的初始化以及使能,这个设置与具体的RAM大小有关,包括正确地设置系统的内存控制器以及各内存库控制寄存器。具体代码稍长,在这里相关代码略去。
相关基本硬件初始化之后,开始设置模式。
1. 为ARM的各个操作模式设置称栈指针:在前面的伪代码中已经为各个操作模式分配相应的栈区,而且ARM各个模式下都有自己通用的栈顶指针SP,现在要做的是在不同模式下将该模式下的SP指向栈顶。每个模式的处理都类似,都是通过设置状态寄存器CPSR(可以参看前面章节的介绍)来完成,并且每个模式都要完成。以IRQ模式为例:
到此时,用汇编编写的硬件基本初始化代码完成,对于阶段1来说,剩下的工作就是将镜像2拷贝到SDRAM的指定处,这个工作我们通过一小段C代码来完成,文件名为cstart.c,完成拷贝功能的函数设为cstart。则在汇编末尾可以通过跳转指令进入阶段1的这一小段C代码:
/***************************有关中断向量表**************/
为什么在中断向量表中不直接LDR PC,"异常地址".而是使用一个标号,然有再在后面
使用DCD 定义这个标号
A:因为LDR 指令只能跳到当前PC 4kB 范围内,而B 指令能跳转到32MB 范围,而现在这样
在LDR PC, "xxxx"这条指令不远处用"xxxx"DCD 定义一个字,而这个字里面存放最终异
常服务程序的地址,这样可以实现4GB 全范围跳转
使用DCD 定义这个标号
A:因为LDR 指令只能跳到当前PC 4kB 范围内,而B 指令能跳转到32MB 范围,而现在这样
在LDR PC, "xxxx"这条指令不远处用"xxxx"DCD 定义一个字,而这个字里面存放最终异
常服务程序的地址,这样可以实现4GB 全范围跳转
如:在PROTEUS 中的芯片组:
LPC2220的
复位与存储器映射
芯片复位后, MAP=00 ,启动 boot 装载程序, boot 装载程序检测 P0.14 口的状态和用户的异常向量表,判断是进入 ISP 还是启动用户程序,若启动用户程序,则自动设置 MAP=1 或 3 。若用户程序需要更改异常向量表,可以将异常向量表复制到片内 0x40000000 ,然后设置 MAP=2 进行重新映射, 0x40000000 地址上的向量表就可以更改了。
LPC2220 在复位运行的第一段程序并不是用户程序,而是 boot block( 引导模块 ) ,是设计厂家在 ARM 内部固化的一段代码,用户无法修改或删除,其主要功能为:
判断运行那个存储器上的程序。
检查用户代码是否有效。(主要检测异常向量表的机器码值之和是否为 0 )
判断芯片是否被加密。
芯片的在应用编程( IAP )和在系统编程( ISP )
boot block( 包括 bootload 和 64 字节异常向量表 ) 。
对于LPC2220,复位后(也即是运行完Boot Block后),用户所能见到的存储空间,及其各存储空间上的内容。
0xF0000000----0xFFFFFFFF:AHB外设;
0xE0000000----0xEFFFFFFF:VPB外设;
0x80000000----0xDFFFFFFF;保留给外部存储器;
0x7FFFDFFF---0x7FFFE000 ; BOOT BLOCK ;
0x40004000----0x4000FFFF;64KB片内RAM;
0x00000000—0x0000003f,ARM异常向量位置;
芯片复位后, MAP=00 ,启动 boot 装载程序, boot 装载程序检测 P0.14 口的状态和用户的异常向量表,判断是进入 ISP 还是启动用户程序,若启动用户程序,则自动设置 MAP=1 或 3 。若用户程序需要更改异常向量表,可以将异常向量表复制到片内 0x40000000 ,然后设置 MAP=2 进行重新映射, 0x40000000 地址上的向量表就可以更改了。
LPC2220 在复位运行的第一段程序并不是用户程序,而是 boot block( 引导模块 ) ,是设计厂家在 ARM 内部固化的一段代码,用户无法修改或删除,其主要功能为:
判断运行那个存储器上的程序。
检查用户代码是否有效。(主要检测异常向量表的机器码值之和是否为 0 )
判断芯片是否被加密。
芯片的在应用编程( IAP )和在系统编程( ISP )
boot block( 包括 bootload 和 64 字节异常向量表 ) 。
对于LPC2220,复位后(也即是运行完Boot Block后),用户所能见到的存储空间,及其各存储空间上的内容。
0xF0000000----0xFFFFFFFF:AHB外设;
0xE0000000----0xEFFFFFFF:VPB外设;
0x80000000----0xDFFFFFFF;保留给外部存储器;
0x7FFFDFFF---0x7FFFE000 ; BOOT BLOCK ;
0x40004000----0x4000FFFF;64KB片内RAM;
0x00000000—0x0000003f,ARM异常向量位置;
存储器映射控制
MAP=00 :由任何硬件复位激活, boot block 中断向量映射到存储器的底部以允许处理异常。
MAP=01 :中断向量表没有被重新映射,它位于存储器的底部。
MAP=10 :由用户程序激活,中断向量表重新映射到静态 RAM 的底部。
MAP=11 :用户外部模式,由 BOOT[1:0] 来控制存储器的引导方式,中断向量表重新映射到外部存储器的底部。
例如:每当产生一个软件中断, ARM 内核就从 0x00000008 处取出 32 位数据,当 MAP=0x11 时,这就意味着从 0x00000008 处取值既是对 0x80000008 处取值。
存储器重新映射控制用于改变从地址 0x00000000 开始的中断向量表的映射,使就使得运行在不同存储器空间中的代码对中断的控制。
拿LPC说
bootblock 出厂时固化的Loader 主要实现ISP功能!
bootloader 自己写的程序
再到main()
上电后bootblock 检测是否有ISP的相关引脚被设定,如果设定进入ISP模式,如果没有设定 运行用户程序(一般来说时用户的BootLoader),然后启动内核或者其他的。
关于异常向量表,配置好你自己的就可以了,不用管 bootblock 上的!
bootblock 出厂时固化的Loader 主要实现ISP功能!
bootloader 自己写的程序
再到main()
上电后bootblock 检测是否有ISP的相关引脚被设定,如果设定进入ISP模式,如果没有设定 运行用户程序(一般来说时用户的BootLoader),然后启动内核或者其他的。
关于异常向量表,配置好你自己的就可以了,不用管 bootblock 上的!
1 设置异常中断向量表
ARM处理器的中断向量表从地址0x0处开始存放,连续有8×4字节的空间。在ARM存储空间里每个字32位,占4个字节。可以通过图1来描述中断向量表的地址分配。
每当有中断或者异常发生时,ARM处理器便强制把PC指针指向向量表中对应中断类型的地址值。为了加快中断响应,我们在Flash的0x0地址存放能跳转到0x0c000008地址处中断向量的跳转指令,即在RAM中建立一个二级中断向量表,起始地址为0x0c000008,除复位外,其它异常入口地址由Flash跳转得到,如表1所示:
转载于:https://blog.51cto.com/sviews/673767