您好,欢迎访问三七文档
当前位置:首页 > 办公文档 > 其它办公文档 > 基于ARM9嵌入式BootLoader设计与实现
基于ARM9嵌入式系统的BootLoader设计与实现徐学均信息产业部电子第六研究所,北京(100083)E-mail:xuxuejun0524@126.com摘要:介绍了基于ARM9嵌入式系统在上电启动后操作系统运行之前BootLoader的启动过程,并设计出了具有良好模块性和可移植性的启动程序,试验结果表明该设计有良好的稳定性和高效性,对分析和开发其它的BootLoader程序具有一定的启发作用。关键词:BootLoaderS3C2410嵌入式系统中图分类号:TP3141.引言嵌入式系统是以应用为中心,以计算机技术为基础,软硬件可裁减以适应系统对功能、可靠性、成本、体积、功耗要求严格的专用计算机系统。嵌入式系统从软件的角度通常可分为4个层次:引导加载程序、Linux内核、文件系统、用户应用程序。引导加载程序是系统加电后的第一段代码,对PC机而言,开机后的处理器配置、存储器、硬盘等硬件设备的初始化操作由BIOS来完成的,但对于嵌入式操作系统来说,通常没有像BIOS那样的固件程序,这样就需要我们自己编写完成系统初始化操作的被称为BootLoader程序的这段代码,因此整个系统的加载启动任务完全由BootLoader来完成。简单地说,BootLoader就是在操作系统内核运行前执行的一段小程序。通过这段小程序,可以初始化必要的硬件设备,创建内核需要的一些信息并将这些信息通过相关机制传递给内核,从而将系统的软硬件环境设定在一个合适的状态,以便为最终调用操作系统内核、运行用户设计的应用程序准备好正确的运行环境[1]。BootLoader是依赖于硬件实现的,不同的体系结构、不同的嵌入式板级设备配置需要的BootLoader都是不同的。也就是说,对于两块不同的嵌入式板级设备而言,即使它们基于相同的微处理器构建,运行在其中一块嵌入式板级设备上的BootLoader,未必能够运行在另一块嵌入式板级设备上。因此要为嵌入式系统建立一个通用、标准的BootLoader是非常困难的。在多数情况下,我们有必要根据嵌入式板级设备和微处理器的需求自行设计BootLoader。2.BootLoader启动过程设计三星的S3C2410处理器是一款基于ARM920T内核的处理器,是三星公司专为手持设备和一般类型的应用提供的一款低价格、高性能、低功耗的微处理器。本系统采用S3C2410微处理器搭建,外加一片64M*8位数据宽度的NANDFlash和两片16M*16位数据宽度的SDRAM,其地址范围为0x30000000-0x34000000。S3C2410将系统的存储空间分为8组(Bank),每组。其中Bank0-Bank5主要用于ROM或SROM,Bank6-Bank7主要用于ROM、SROM或SDRAM[2]。当嵌入式系统加电复位后,以微处理器为核心的嵌入式系统通常都有某种类型的固态存储设备(如EEPROM、Flash等)被映射到预先设置好的地址上,因此处理器将首先执行存放在复位地址处的程序。复位地址可以通过ADS集成开发环境进行设置,以把BootLaoder定位在复位地址开始的存储空间内,同时通过Linker选项定义ROBase地址为0x30200000作为BootLoader的入口地址—_ENTRY地址。对于嵌入式系统来说,不管是否使用操作系统,在系统启动时都必须执行BootLoader,以便为系统及应用程序的运行准备好软硬件运行环境。基于S3C2410的嵌入式系统的启动方式通常有两种方式:一种方式是从NORFlash启动,由于NORFlash可以支持随机访问,所以代码可以直接在Flash上执行,系统启动时,系统会把Flash的首地址映射到0x00000000位置,并且启动程序本身要把自己从Flash中移动到RAM中去;另一种方式是从NANDFlash启动,由于NANDFlash不支持随机访问,一般要通过专用控制器的I/O方式来访问,所以需要配置专用的引导程序,当从NANDFlash启动时,S3C2410会自动把NANDFlash的前4KB数据搬到自己内部的RAM中去,并把内部RAM的首地址设为0x00000000,CPU从0x00000000处开始运行。在本文中选择从NANDFlash启动,图2-1为通过NorFlash启动和NANDFlash启动两种方式存储空间分配的比较[3][4]。0xFFFFFFFF0x600000000x480000000x40000FFF0x400000000x380000000x300000000x280000000x200000000x180000000x100000000x080000000x00000000(a)NorFlash(b)NANDFlash图2-1两种启动方式存储空间分配的比较BootLoader在完成基本软硬件环境初始化后,对于在有操作系统的情况下,会启动操作系统,启动进程管理、内存管理、任务调度、装载驱动程序等,最后执行应用程序或等待NotUsedSFRBootSRAM(4KB)BANK7(SDRAM)BANK6(SDRAM)BANK5(SROM)BANK4(SROM)BANK3(SROM)BANK2(SROM)BANK1(SROM)BANK0(SROM)NotUsedSFRNotUsedBANK7(SDRAM)BANK6(SDRAM)BANK5(SROM)BANK4(SROM)BANK3(SROM)BANK2(SROM)BANK1(SROM)BootSRAM(4KB);对于没有操作系统的情况下,会直接执行应用程序或等待用户口令。基于S3C2410嵌入式系统BootLoader的启动过程设计如图2-2所示:图2-2基于S3C2410嵌入式系统BootLoader的启动过程设计图3.BootLoader的具体实现过程BootLoader的实现和U-Boot类似,也分为Stage1和Stage2两个阶段实现。作为自己制作BootLoader来说,首先需要在src目录下建立一个用汇编语言实现的start.S文件,通常BootLoader的启动代码都是用汇编语言来实现的,因为它的执行效率高,并且代码量小,所以我们在开发嵌入式系统BootLoader时首选汇编语言。start.S文件主要实现Stage1部分,其主要功能有:设置异常向量表、初始化存储器、初始化堆栈、初始化数据区及呼叫主程序等。当Stage1的任务结束后就要开始Stage2的工作了,此时定义一个mybios.c文件,主要完成一些I/O端口、中断、串口、MMU(内存管理单元)等高级和复杂功能的初始化工作,以及实现操作系统加载的功能[5]。3.1设置异常向量表ARM处理器的异常向量表通常放在以0x00地址开头的地方,且需放在连续的8*4字节的存储空间内。可以通过图3-1来描述异常向量表的地址分配。每当中断或异常发生时,ARM处理器便强制把PC(程序计数器)指针置为向量表中相应中断类型的地址值。因为每个中断只占用向量表中一个字的存储空间,所以只能存放一条ARM指令,使程序转向存储器的其它地方,然后再执行中断处理。在实现异常向量表的程序中,首先定义代码区域的属性为只读属性且代码区为自启动代码区:AREASelfBoot,CODE,READONLY,然后定义了中断向量表,并用ENTRY关键字指定编译器要保留这些设置异常向量表初始化存储器初始化堆栈初始化数据区呼叫主程序结束开始。在连接的时候要保证这段代码被放在以0x00开始的地址处或由ADS集成开发工具指定的自定义地址处,并且作为整个程序的入口。0x1C0x180x140x100x0C0x080x040x00图3-1异常向量表3.2初始化存储器初始化存储器主要是指对Flash、RAM存储器,数据总线宽度及DRAM的刷新进行初始化,具体实现可参考以下代码:adrr0,MCRDATA//MCRDATA定义了内存控制寄存器值ldrr1,=BAWSCON//BWSCON为总线宽度和等待状态控制寄存器addr2,r0,#48//SMRDATA结束地址…….3.3初始化堆栈一般ARM有7种处理器模式,分别为:用户模式(usr)、快速中断模式(fiq)、外部中断模式(irq)、管理模式(svc)、数据访问终止模式(abt)、系统模式(sys)和未定义指令终止模式(und)。除了用户模式之外的其他6种模式称为特权模式,在这些模式下,程序可以访问所有的系统资源,也可以任意切换处理器模式。每一种模式的堆栈指针寄存器(SP)都是相互独立的,因此对程序中需要用到的每一种模式都要给SP寄存器定义一个堆栈地址。在某种意义上,初始化堆栈也就是初始化这7种模式下的堆栈,其具体实现可参考如下代码:InitStacks//初始化堆栈mrsr0,cpsrbicr0,r0,#MODEMASKorrr1,r0,#UNDEFMODE|NOINTmsrcpsr_cxsf,r1ldrsp,=UndefStack//未定义指令终止模式orrr1,r0,#ABORTMODE|NOINT快速中断请求中断请求没有定义数据终止异常预取终止异常SWI软件中断未定义指令异常复位异常,r1//数据访问终止模式ldrsp,=AbortStackorrr1,r0,#IRQMODE|NOINTmsrcpsr_cxsf,r1//外部中断模式ldrsp,=IRQStackorrr1,r0,#FIQMODE|NOINTmsrcpsr_cxsf,r1//快速中断模式ldrsp,=FIQStackbicr0,r0,#MODEMASK|NOINTorrr1,r0,#SVCMODEmsrcpsr_cxsf,r1//管理模式ldrsp,=SVCStackmovpc,lr//如果当前模式不是SVC模式,LR寄存器将无效LTORG3.4初始化数据区内核映像一开始总是存储在ROM或Flash里面的,由RO、RW和ZI部分组成。其中RO部分既可以在ROM或Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分必须转移到可写的RAM中去的,所谓数据区的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零,具体实现可参考如下代码:InitRam//初始化数据区ldrr2,Base_BSS//定义了RW部分的基地址ldrr3,Base_Zero//定义了ZI部分的基地址0cmpr2,r3ldrccr1,[r0],#4strccr1,[r2],#4bcc%B0movr0,#0ldrr3,End_BSS//定义了ZI部分的末地址1cmpr2,r3strccr0,[r2],#4bcc%B13.5呼叫主程序当初始化数据区完成后,发送复位状态信息给Main函数呼叫主程序,开始实现,在Stage2阶段主要完成Flash、系统频率、I/O端口、中断处理程序表、串口等初始化工作以及加载操作系统内核等。其实现代码可参考下面:intMain(U32RstStat){Init();//初始化Flash控制器、系统频率Port_Init();//初始化I/O端口Isr_Init();//初始化中断处理程序表Uart_Init(0,Console_Baud);//初始化串口Uart_Select(Console_Uart);MMU_Init();//初始化内存管理单元MMUEnableModuleClock(CLOCK_ALL);//使GPIO,UART,PWMTIMER,NANDFLASH等模块时钟有效…….//复制嵌入式linux操作系统内核hSource=(unsignedint*)FLASH_LINUX_KERNEL;hDestination=(un
本文标题:基于ARM9嵌入式BootLoader设计与实现
链接地址:https://www.777doc.com/doc-17084 .html