一、 几点说明
并非大多数人都有机会做这项移植工作,但又是嵌入式开发流程不可缺少的部分,应该了了解。
一个方法论,了解框架,不研究具体代码。
作为一个新手,如何开始学习移植,怎样上手;
移植的步骤。
重点分析一下u-boot这类大型工程代码的Makefile
二、 u-boot概况
代码结构与功能
board——目标板相关文件,主要包含SDRAM、Flash驱动;
common——独立于处理器体系结构的通用代码,如 内存大小探测与故障检测;
cpu——与处理器相关的文件,如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
driver——通用设备驱动,如CFI Flash驱动(目前对Intel Flash支持较好)
doc——U-Boot的说明文档;
examples——可在U-Boot下运行的示例程序;如 helloworld.c,timer.c;
include——U-Boot头文件,configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
lib_xxx——处理器体系相关的文件,如lib—ppc,lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
net——与网络功能相关的文件目录,如bootp、nfs、tftp;
post——上电自检文件目录,尚有待于进一步完善;
rtc——RTC驱动程序;
tools——用于创建U-Boot S-RECORD和BIN镜像文件的工具。
三、 功能
l 上电自检
l 系统引导:引导内核,支持根文件系统挂载
l 一些辅助功能:CRC检验flash中的内核和文件系统映像是否完好无损;
强大的操作系统接口功能,可灵活设置、传递各种参数给内核
支持多种参数存储方式,flash,EEROM,NVRAM
l 设备驱动:
l 特殊功能:产品更新
四、 运行流程
启动模式与启动阶段
加载模式与下载模式
CPU与存储设备级启动与板级启动
启动代码的流程
ü CPU与存储设备级启动
初始化过程是这样的:首先,U-BOOT程序在Flash中运行,执行必要的代码,如CPU初始化、串口初始化和内存初始化(此时仅仅是初始化了部分内存,保证u-boot的程序能在内存中装的下即可)。
ü 板级启动
然后,程序拷贝u-boot到内存中,并跳转到内存执行,并且再执行一次的初始化,这次除了最基本的初始化如CPU初始化、串口初始化和内存初始化(整个内存),还有网络和其它外设的初始化。
启动流程图
首先要找到程序入口点。从board/ Smdk2410/u-boot.lds可以找到,u-boot的程序入口为_start,在cpu/ Arm920t/start.s中。因此首先要分析start.S程序,U-Boot中所有的Arm920t系列的处理器都从这里开始执行第一条语句。
cpu_init_crit是/start.s中的一个函数,在cpu_init_crit中的主要工作是设置时钟,配置处理器主频(这时CPU的工作频率还没有改变)。
lowlevel_init函数在board/lubbock/lowlevel_init.S中定义。调用lowlevel_init函数进行底层初始化(包括调整处理器工作频率、系统总线频率、存储器时钟频率以及存储系统的初始化等工作),随后关闭MMU并使能I-Cache,再返回
从cpu_init_crit返回后就开始relocate(重定位),即将U-boot从FLASH存储器搬运到SDRAM中TEXT_BASE开始的存储空间(TEXT_BASE在board/lubbock/config.mk中定义)。relocate是很经典的一段代码,相信学习凡是过ARM编程的,都分析过这段代码,所以也不再赘述。之所以列出这段代码,一是为了找到C程序入口start_armboot,二是为了给出U-Boot的一个存储器映射图
进入到Bootloader Stage 2即C语言代码部分,入口是start_armboot,对应的源文件是lib_arm/board.c,从lib_arm/board.c的源码可以看到系统的启动流程:首先初始化全局数据表,然后顺序执行函数指针数组init_sequence中的一系列初始化函数。这一文件对所有的ARM处理器都是通用的,因此在移植的时候不用修改。
接下来就调用flash_init()函数初始化CFI FLASH(针对NOR型闪存而言),该函数在drivers/cfi_flash.c中定义,不过,只有在目标板头文件中”#define CFG_FLASH_CFI_DRIVER”之后该驱动才会被编译;如果没定义则在board/smdk2410/ flash.c中实现自己的FLASH驱动,包括flash_init()在内。在移植U-Boot时,可以根据实际情况选择使用U-Boot自带的FLASH驱动还是自己编写新的驱动。如果配置了NAND闪存,还会对其进行初始化;
接下来调用env_relocate()函数初始化环境变量,该函数在common/env_common.c文件中定义。
再然后是调用common/devices.c中定义的devices_init()函数来创建设备列表,并初始化相应的设备,主要是”stdin”,”stdout”,”stderr”以及自定义的设备如I2C,LCD等。这些相关代码是与平台无关的,因此从移植的角度考虑,不必作细致的研究与分析。
接着调用common/exports.c中定义的jumptable_init()函数
然后是调用common/console.c中定义的函数console_init_r()初始化串口控制台,这同样是平台无关的代码,所以不必关心
这时U-Boot的基本功能已经初始化完毕,便可开中断,并进行附加功能的配置与初始化,包括网卡驱动配置,在板子配置文件中根据需要配置其他的网卡驱动,这些都在include/configs/smdk2410.h中定义。
然后是调用board/smdk2410/smdk2410.c中定义的board_late_init()函数进行板级的后期初始化,实际上是配置stdout和stderr的硬件设备。
lib_arm/armlinux.c,它实现的功能包括设置内核启动参数,并负责将这些参数传递给内核,最后跳转到Linux内核入口函数,将控制权交给内核。
五、 移植内容
U-Boot第一阶段
start.S (平台无关,处理器架构相关)
/lowlevel_init.S (平台与处理器型号相关)
config.mk (平台相关,设置TEXT_BASE
xsbase270.h (平台相关,设置寄存器初值等)
U-Boot第二阶段的大部分代码是平台无关的。
include/configs/smdk2410.h:通过使用定义或取消定义相关的预编译变量,用于对平台无关的代码进行平台相关的定制,包括定制U-Boot命令、缺省的环境变量、存储器映射、串口控制台配置、驱动程序等。
board/ smdk2410/ smdk2410.c:板级初始化,只需进行最基本的配置,包括设置mach-type,启动参数列表首地址,设置标准输入输出设备,获取系统RAM配置信息等。
驱动程序的移植。最基本的是FLASH存储器驱动程序和以太网卡驱动程序。对于U-Boot中已经支持的器件,可以进行简单移植,否则需要自己加入相关的设备驱动程序。
文章评论(0条评论)
登录后参与讨论