Motorola微处理器的bootloader分析与应用
bootloader 是用来完成系统启动和系统软件加载工作的程序。它是底层硬件和上层应用软件之间的一个中间件软件,完成处理器和周边电路正常运行所要的初始化工作;可以屏蔽底层硬件的差异,使上层应用软件的编写和移植更加方便;不仅具有类似 PC 机上常用的 BIOS(Basic Input Output System,基本输入、输出系统监控程序)功能,而且还可具有一定的调试功能。目前,在嵌入式系统开发中有多种 bootloader 可供选择,其中 Motorola 公司的名为 dBUG 的 bootloader 比较优秀。
它可以移植在 Motorola MC68000、ColdFire 和 PowerPC 系列所有微处理器上面,有强大的调试功能,支持单步、下载、网络更新等;其良好的软件架构使用户能很方便地修改其代码,扩展新的功能。本文以作者用于网络数据存储的 coldfire5307C3 开发板为例,简析其上的 dBUG bootloader 的结构和运行机制,并给出实际修改范例。1 bootloader 源码结构(1)bootloader 的文件组织 dBUG bootloader 源代码可以从 Motorola 公司网站获得。
它是一个范例程序,通过修改相应的配置文件和处理器相关文件,可以很方便地移植到不同的处理器系统上。其源码由两个部分组成,一部分是 lib 项目,另外一部分是每种 Motorola 微处理器单独的处理器项目。比如,ColdFire 5307 就使用 MCF5307C3 项目和 lib 项目一起来生成最终的 dBUG 代码。其中 lib 项目中是与处理器无关的一些命令或者函数,而每个单独的处理器项目是和每种不同的处理器息息相关的。
在编译的时候,首先需要将 lib 项目编译生成标准库函数(也就是将一些通用命令和函数先封装起来)。然后,编译 MCF5307C3 项目,就会将刚才编译的 lib 项目和 MCF5307C3 项目结合在一起生成最终代码。 整个 dBUG bootloader 代码的架构比较复杂,其源码按功能可分为 3 个模块[1]:User Interface Component、CPU-specific Component、Board-specific Component。
用户进入 dBUG 的目录以后,会看到三个子目录,如图 1 所示[1,2]。 ① 第一个目录是 bin 目录,在该目录下面主要是一个简单的 TFTP Server 软件。TFTP 是简单的 FTP(文件传输协议)。它是基于 UDP 协议的,主要用来下载程序目标代码。② 第二个目录是 prog 目录,下面主要是 lib 项目和 MCF5307C3 项目的项目组织文件和一部分源代码。在 prog 目录下面的 libdbug 目录下,有 lib 项目的项目管理文件 libdbug.mcp,使用 CodeWarrior 可以打开该项目文件和编译等。
prog 目录下面的 M5307C3 目录下是 ColdFire 5307 系统的项目文件,而该目录下的 obj 目录下是生成的 dBUG 目标代码。src 目录下是 5307 项目的项目管理文件。用户可以使用 CodeWarrior,打开 M5307C3 目录下的/src/dbug/mwerks/m5307c3.mcp 项目管理文件来编译代码。③ 第三个目录是 src 目录,是 dBUG 的主要源代码。 综上所述,用户只要打开 m5307c3.mcp 和 libdbug.mcp 两个项目文件,即可以看到 dBUG 所有的源代码。
(2)与处理器和外围硬件配置相关的文件① 入口文件:vector.s。 存有处理器复位初始入口地址、跳转指令及中断矢量表。② 初始化汇编语言文件:mcfxxxx_lo.s。功能为预初始化处理器、调用初始化函数及跳转到 main 主函数。其中 xxxx 表示某特定的处理器型号,如 5307。③ 初始化 C 语言文件:Sysinit.c。内含多个初始化函数,功能为初始化处理器及各底层硬件。 ④ 系统配置文件:Config.h 和 Board.h。
Config.h 设定板上处理器类型和其它模块功能。Board.h 设定板上各参数信息,如片外 Flash 和 SDRAM 大小、类型、数据宽度和地址范围、划分板上内存空间范围、系统时钟大小、系统总线速率以及一些其它要用到的系统常量。⑤ 连接配置文件:Flash.lcf。设定连接时各函数空间地址及内存分配。⑥ 预包含头文件:mxxxx_mwerks.h 和 mwerks.h。两函数被所有的 C 语言和汇编语言函数包含,它们设定 CodeWarrior 预处理器所用到的常量和编译器编译选项。
2 bootloader 运行流程简介 bootloader 启动流程如图 2 所示。 系统上电复位后,跳到 Boot ROM 的最低地址处。Boot ROM 的开始空间 FFE00000~FFE00400 为 vector.s 中的中断矢量表。将表中第一个 32 位字传给 5307 的 SP,将第二个 32 位字传给 PC,即完成复位中断跳转。 该复位中断跳转到 vector.s 中的 start 处。此处仅初始化 sr,然后跳转到 mcf5307_lo.s 中的 asm_startmeup。
该段代码首先进行部分初始化和真正初始化前的准备工作:禁止 Cache、禁止中断和地址转换、初始化用户指定的内部模块(MBAR)和内部 SRAM(RAMBAR)起始地址。然后,将 SP 指向内部 SRAM 空间,即当调用真正的初始化程序时用内部 SRAM 的一段地址空间作为临时堆栈。接下来,调用 sysinit.c 文件中的外围电路和系统配置的初始化程序 mcf5307_init()。 mcf5307_init()函数顺序调用各个功能的初始化子函数,初始化系统集成模块、并行通用输出输入口、串口、I2C 控制器、DMA 控制器、片选寄存器、SDRAM 控制器。
当运行完 mcf5307_init()后,流程回到 asm_startmeup 中。此时,外围电路和内部模块已按用户要求进行了正确的配置,系统的初始化已基本完成。于是,将堆栈指针 SP 指向用户要求的堆栈空间,该堆栈为该板上的外部 SDRAM 空间。最后,跳转至 main 函数。 在 main 中,首先将系统的矢量表从 Flash 空间拷贝到用户指定的外部 SDRAM 中。然后,将 Flash 中的 data 段初值拷贝到外部 SDRAM 指定的 data 空间中,根据配置将外部 SDRAM 中的 bss 段清 0,之后进行一些系统全局数据结构、参数表等的初始化。
最后,调用 mainloop 开始人机交互循环:不断接收用户的命令、根据命令查表调用相应的任务函数、在界面上打印出相应的执行信息。3 bootloader 用户应用
(1)bootloader 的系统移植由于 Motorola 的 dBUG bootloader 为一标准的范例程序,要将其移植到具体的嵌入式系统中,还需要根据系统的硬件配置,修改其部分配置文件和底层接口文件。本文以用于网络数据存储的 ColdFire5307C3 开发板为例,介绍在其上的 dBUG 移植过程。①ColdFire5307C3 开发板硬件情况:ColdFire5307 32 位处理器,16MB (32 位数据总线)SDRAM,2MB (16 位数据总线)Flash ROM,2 UART,10Mbps (16 位数据总线)以太网接口。
②修改 bootloader 的处理器和配置相关文件:a. 根据 5307 处理器手册及用户需要,修改 vector.s 中的中断矢量表。b. 根据 5307 处理器手册编写 mcf5307_lo.s 文件。c. 根据板上的硬件配置修改 sysinit.c 文件,编写相应的硬件初始化函数。d. 根据系统配置修改 config.h 和 board.h 文件。e. 根据需要修改 mxxxx_mwerks.h 和 mwerks.h,设定某些编译选项。
f. 根据需要修改连接配置文件 Flash.lcf,设定连接时目标代码的地址分配。g. 编写相应的硬件驱动,如该板上用到的 MBM29LV 160BE70 Flash 芯片的驱动程序文件 am29xxxx.c 和 am29 xxxx.h、该板上用到的网卡芯片的驱动程序文件 Ns8390.c 以及 5307 的串口驱动函数等。
(2)bootloader 命令简介[2] dBUG 提供了丰富的调试命令:① 程序流程控制命令 reset(系统重启)、go、exe(用户程序执行)、br(断点设置)、step(单步)、trace(单步跟入)、gt(运行到);② 内存和寄存器操作命令 md、mm(内存查看和修改)、rd、rm(寄存器查看和修改)、bm(内处块移动)、bf(内存块数据填充)、bc(内存块比较)、bs(内存块查找);③ 指令和数据操作命令 dc(数据转换)、dis(反汇编)、asm (汇编指令插入)、sym(符号表管理);④ 程序下载命令 dl(通过串口下载)、dn(通过网络下载)。
(3)bootloader 用户功能扩展除了 dBUG bootloader 本身提供给用户的命令外,用户还希望根据不同的情况定制自己的命令。如 Linux 加载、μC/OS 加载、kermit 下载等。一般自己添加的命令都会放在一个单独的 C 文件里面。为了方便,用户也将自己添加的命令都放在 board.c 文件的最后。 例如,用户想要给 dBUG 添加μC/OS 操作系统加载的功能,除了在 dBUG 中加上自己的程序加载代码外,还应给 dBUG 添加一个名为 ucosii 的用户命令。
这样可以通过在界面上输入命令的形式实现相应的加载功能。首先应该在 board.c 里面实现这个函数:ucos_boot (int argc, char **argv){…………} 而后,应在 cmds.c 文件里面声明这个函数,并在紧接着的 UIF_CMD UIF_CMDTAB 数组里面声明这个命令的特性和参数。 {“ucosii”, 4,0,0,0,ucos_boot, “Boot uCOS-II from RAM”,””}, 其中,第一个 test 字符串是命令的名称,第二个 4 表明命令识别的时候要匹配 4 个字符才行,最后的字符串是 help 命令时对 test 命令的解释。
在描述中间的 test 表明指向的函数名称。这样就很方便地添加了这个用户命令。4 结论 综上所述,Motorola 公司的 dBUG 软件由于其良好的源代码组织结构使得用户在其上开发应用非常方便,用户稍加修改就可将其移植到不同的硬件平台上。它拥有良好的用户界面,不仅可以完成用户所需的程序下载、加载等功能,而且还可以方便地进行调试,使用户可以更好地监控自己的程序。除此之外,用户还可以很方便地添加自己所要的功能,其结构具有良好的可扩展性。
所以,Motorola 公司的 dBUG bootloader 的确是一个优秀的 bootloader 范例,给广大的嵌入式系统开发者提供了一个不错的选择。