收藏 分销(赏)

自己动手编写嵌入式BootLoader.docx

上传人:仙人****88 文档编号:8471054 上传时间:2025-02-14 格式:DOCX 页数:5 大小:136.30KB
下载 相关 举报
自己动手编写嵌入式BootLoader.docx_第1页
第1页 / 共5页
自己动手编写嵌入式BootLoader.docx_第2页
第2页 / 共5页
点击查看更多>>
资源描述
自己动手编写嵌入式BootLoader之(1) (转载) 第一部分:基本功能流程 CPU上电后会从IO空间的某地址取第一条指令。但此时:PLL没有启动,CPU工作频率为外部输入晶振频率,非常低;CPU工作模式、中断设置等不确定;存储空间的各个BANK(包括内存)都没有驱动,内存不能使用。在这种情况下必须在第一条指令处做一些初始化的工作,这段初始化程序与操作系统独立分开,称之为bootloader。 实际上,很少有必要自己写一个BootLoader,因为U-Boot已经强大到能够满足各种需要。但是强大必然复杂,一个初学者想要分析U-Boot的源代码,还是有些难度的。出于学习目的,笔者写了这个最简单的启动加载器,它只包含最基本的功能,却囊括了一个嵌入式BootLaoder应该有的核心和精华。把这个启动加载器命名为s-Boot(simple Bootloader)。 使用的实验环境为OK2440开发板,板上处理器为S3C2440A,有64M内存,Nand存储器为K9F1208,64M。网口芯片为CS8900A。要实现的功能是:从串口下载Linux内核映像到RAM;从网口下载Linux内核映像到RAM;从RAM启动内核挂载NFS根文件系统。 1.第一阶段的汇编代码:Start.S 一个嵌入式BootLoader最初始部分的代码几乎必须是用汇编语言写成的,因为开发板刚上电后没有准备好C程序运行环境,比如堆栈指针SP没有指到正确的位置。汇编代码应该完成最原始的硬件设备初始化,并准备好C运行环境,这样后面的功能就可以应C语言来写了。 对S-Boot来说,上电后的起始运行代码是start/start.S. .text .golbal_start _start: b Reset @ 0x00: 发生复位异常时从地址零处开始运行 b HandleUndef @ 0x04:未定义指令终止模式的向量地址 b HandleSWI @ 0x03:管理模式的向量地址,通过SWI指令进入此模式 b HandlePrefetchAbort @ 0x0c:指令预取终止导致的异常的向量地址 b HandleDataAbort @ 0x10:数据访问终止导致的异常向量地址 b HandleNotUsed @ 0x14:保留 b HandleIRQ @ 0x18:中断模式的向量地址 b HandleFRQ @ 0x1C:快中断模式的向量地址 这里,汇编指示符.txt表明以下内容属于代码段,.global_start指明_start是全局可访问的符号(Give the symbol external linkage)。按照ARM920T的规定,从地址0x00到0x1C放置一场向量表,向量表每个条目占四个字节,正好可以放置一条跳转指令,跳转到相应异常的服务程序中去。在S-Boot中没有使用中断,所以除Reset异常外,其它异常的服务程序都可简单地写个死循环。Reset异常是系统上电后自动触发的,所以我们的代码都写在Reset的服务程序里面。 实际上,异常向量表不一定非要位于地址0X00处,CP15协处理器的C1寄存器的第13位用来控制异常向量表的起始地址。该位为0时,异常向量表位于低地址0X00处;该位为1时,异常向量表位于高地址0xFFFF0000处。我们没有必要改变这个位的值,使用默认的低地址就行了。 Reset: Mrs r0,cpsr @set cpu to SVC32 mode Bic r0, r0, #0x1F Orr r0, r0, #0xD3 Msr cpsr, r0 @cpsr = 11x10011, IRQ/FIQ disabled 代码最初始的任务是设置CPU工作在SVC32模式,关闭所有中断,禁用看门狗。实际上,即使不设置工作模式,CPU在复位之后将自动工作在管理模式。在整个S-Boot运行期间,我们没有使用中断,也没有改变CPU工作模式,它将一直工作在SVC32模式。 MMU、ICache、DCache的打开和关闭都是由CP15协处理器的c1寄存器控制的。实际上在复位之后这三者都是自动关闭的,所以省略了关闭它们的代码。 S3C2440A的PSR寄存器(Program Status Reguster)中每个Bit位的含义如图1所示。Bit4~Bit0为模式位,用来设置CPU工作模式,现在只要知道 M[4:0] = 10011 表示SVC32模式就行了。Bit5为状态位,T=0表示工作在ARM状态,T=1表示工作在Thumb状态,默认为0,不需要改变。Bit6为快速中断禁止位,F=1为禁止快速中断,F=0为使能快速中断。Bit7为中断禁止位,I=1为禁止中断,F=0为使能中断。其它Bit位暂时可以不必理会。 mrs 和msr是在PSR寄存器和其它寄存器间传递数据的指令。如:mrs r0,cpsr 把cpsr的值传送到r0中, msr cpsr,r0把r0的值传送到cpsr中。bic是位清零(Bit Clear)指令,bic r0,r0,#0x1F意思是把r0的Bit[4:0]位清零(由0x1F指示),然后把结果写入r0中。 orr是按位求或指令,orr r0,r0,#0xD3 表示把r0的 Bit7,Bit6,Bit4,Bit1,Bit0 置为1,其它位保持不变。 执行完上述操作后,cpsr中的 I=1, F=1, T保持不变(默认为0),M[4:0]=10011,意思是禁止IRQ,禁止FIQ,工作在ARM状态,工作在SVC32模式。 ldr r0, =0x53000000 mov r1, #0x0 str r1, [r0] @disable watch dog 禁用看门狗更简单,因为WTCON寄存器的地址为0x53000000,直接向该寄存器写0即可。 到目前为止,CPU工作在外接晶振12MHz频率之下。使用以下代码设置PLL,提升工作频率。 ldr r0, =0x4C000014 @CLKDIVN register mov r1, #0x05 @FCLK:HCLK:PCLK = 1:4:8 str r1, [r0] mrc p15,0,r0,c1,c0,0 @if HDIVN Not 0, must asynchronous bus mode orr r0,r0,#0xC0000000 @see S3C2440A manual P7-9 mcr p15,0,r0,c1,c0,0 ldr r0, =0x4C000004 @MPLLCON register ldr r1, =0x0005C011 @((92<<12)|(1<<4)|(1)) str r1, [r0] @FCLK is 400 MHz ! 最后的结果是,FCLK=400MHz,HCLK=100MHz,PCLK=50MHz。 @ SDRAM Init mov r1, #0x48000000 @MEM_CTL_BASE adrl r2, mem_cfg_val add r3, r1, #521: ldr r4, [r2], #4 @ 读取设置值,并让r2加4 str r4, [r1], #4 @ 将此值写入寄存器,并让r1加4 cmp r1, r3 @ 判断是否设置完所有13个寄存器 bne 1b @ 若没有写成,继续 设置存储控制器。 ldr sp, =0x32FFF000 @设置堆栈 bl nand_init @初始化NAND Flash @nand_read_ll函数需要3个参数: ldr r0, =0x33000000 @1. 目标地址=0x30000000,这是SDRAM的起始地址 mov r1, #0 @2. 源地址 =0,S-Boot代码都存在NAND地址0开始处 mov r2, #102400 @3. 复制长度=102400(bytes) bl nand_read @调用C函数nand_read ldr lr, =halt_loop @设置返回地址 ldr pc, =main @b指令和bl指令只能前后跳转32M的范围,故使用向pc赋值的方法进行跳转 halt_loop: b halt_loop 这里把所有的代码从Nand拷贝到RAM中,然后跳转到main函数去执行。此后程序便在RAM中运行了。但是到目前为止,前面的程序都是在SteppingStone里运行的。所谓SteppingStone,是指在S3C2440A的内部的4KB的RAM缓存,它总是映射到地址0x00处。硬件加电后会自动将Nand Flash中的前4KB的数据拷贝到Stepping Stone中,然后从地址0x00处开始运行。 如果代码足够小(小于4KB)的话,那只在SteppingStone中运行,加载Linux内核到内存即可。但通常代码肯定会大于4KB。所以Bootloader一般分为两部分,Stage1的代码在SteppingStone中运行,它会把Stage2的代码拷贝到RAM中,并跳转到RAM中执行;Stage2的代码在RAM中执行,它可以完成加载内核及其它任何复杂的功能。因为Stage2的起始位置不好确定,为了方便,我们把所有的代码都拷贝到RAM中了。 C 函数nand_read有三个参数,第一个参数为目的地起始地址,第二个参数为源起始地址,第三个参数为要复制的数据长度,以字节为单位。根据ATPCS函数调用规则,三个参数分别用寄存器r0,r1,r2来传递。我们在内存的0x33000000处存放Bootloader,复制长度根据编译生成的S- Boot.bin映像文件大小,向上取512字节的整数倍。 这里先来规划一下内存空间的分配。RAM的地址范围是从0x30000000到0x34000000共64MByte。把S-Boot和Kernel放在高地址处,S-Boot从0x33000000开始,预留8MByte的空间,内核从0x33800000开始,可供使用的空间也是8MByte。因栈空间是向下生长的,我们在S-Boot下面预留4096Byte的空闲区域,然后向下为栈空间,故栈指针SP初始化为0x32FFF000。其实留不留空闲区域是无所谓的,这里只是为了把二者更明显地区分开。我们只设置SVC模式下的SP,不使用CPU的其它工作模式,所以也没必要设置其它模式下的栈指针。另外,程序中不使用动态内存分配,故而也不必分配堆空间。 2. nand读操作 在编译连接时,我们把上述 start.S 代码放在生成的二进制映像文件的最开始位置,因而也被烧写到 Nand Flash的最起始位置,因而会被自动拷贝到 SteppingStone 里运行。start.S 要完成的任务之一,是把S-Boot的所有代码从Nand Flash拷贝到内存中,这里需要对NAND的读操作,因此对NAND的初始化和读操作要在第一阶段写好。 以开发板上使用的K9F1208为例,每个页(page)为512Byte数据和16Byte校验,每个块(Block)为32个页,即16KByte数据和512Byte校验。
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传
相似文档                                   自信AI助手自信AI助手

当前位置:首页 > 教育专区 > 小学其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服