友善之臂给出了一份移植U-BOOT-2010-03的移植手册,之前也跟着做了,这次带着分析源码的目的再次移植一遍,整个过程借鉴友善之臂提供的手册,韦东山老师书籍的视频,同时参考了其他一些作者的博客,在此对他们表示感谢。
开发环境:VMWARE—Fedora14
开发板:MINI2440(64M RAM,256M NAND FLASH,2M NOR FLASH)
编译器:arm-linux-gcc-4.3.2
U-Boot版本:U-Boot-2014.04 下载地址:ftp://ftp.denx.de/pub/u-boot/
我移植的U-boot属于版本比较新的了,友善之臂和网上很多帖子都是移植的U-boot-2010的版本,现在最新的U-BOOT已经支持类似linux make menuconfig这样的功能,代码结构和安排也越来越向LINUX看齐,那么移植之前我想先弄清楚一个:什么是U-boot,它的作用是什么?
U-BOOT是一段引导加载程序,是由德国的DENX软件工程中心开发和维护,当前市面上有太多种类的平台和处理器,要想开发一种通用的bootloader几乎是不可能的,但是U-BOOT是一个主流,源码开放,灵活性很强,现在已经被附加了很多的功能,其实它最主要也是最重要的一个作用就是引导加载内核,因为加载内核的时候,内核需要知道Machine ID,知道参数在RAM中的位置,必须关中断,MMU之类的,所以内核启动并不是简单地知道自己在哪里这么简单。我们客户在使用一款嵌入式产品的时候,是不需要和U-BOOT进行交互的,之所以给U-BOOT加入这么多的功能是为了更加方便的我们去观察运行结果,做开发。
U-BOOT-2014.04共有20个子目录,12个文件,其中各个子目录和重要文件功能见下表:
名称 | 类型 | 功能说明 |
api | 通用 | U-boot提供的一些接口函数 |
arch | 平台相关 | 当前U-BOOT重要的目录,arch下每个子目录代表一种处理器类型,这里我们关心arch/arm/cpu/arm920t中cpu和920t下的几个文件:interrupt.c用来设置中断和异常,cpu.c初始化CPU,start.s是U-BOOT启动后执行的第一个文件,u-boot.lds是用来组装代码。 |
board | 平台相关 | 里面有很多支持的开发板型号,这里关注samsung/smdk2410/smdk2410.c和config.mk |
common | 通用 | 主要跟U-BOOT的命令有关,cmd_xxx.c以及环境变量的处理代码env_xxx.c |
spl | 平台相关 | 只有一个Makefile,u-boot的第一阶段相关,搬运第二阶段代码到内存中 |
disk | 通用 | 磁盘驱动的分区处理代码 |
doc | 说明文档 | 可以用来做配置参考 |
drivers | 通用 | 设备的驱动程序,每种类型一个子目录包括网卡,USB,LCD等 |
dts | 通用 | 设备树的控制,主要是由于LINUX 3.X中去除了很多冗余的代码,引入device tree,许多硬件细节可以直接传递给LINUX,是新的东西 |
examples | 通用 | 一些示例程序 |
fs | 通用 | 文件系统支持 |
include | 通用 | 头文件和开发板的配制,configs子目录重要 |
lib | 通用 | 通用的库文件 |
Licenses | 通用 | 可以忽略。。。 |
nand_spl | 平台相关 | 支持了部分平台的nand启动 |
net | 通用 | 网络相关的代码,小型的协议栈 |
post | 通用 | 加电自检程序 |
scripts | 通用 | 脚本程序 |
test | 通用 | 测试程序 |
tools | 通用 | 工具,mkimage就在这里 |
boards.cfg | 文件,平台相关 | 修改添加开发板配置现在在此处 |
Makefile MAKEALL config.mk rules.mk mkconfig | 文件,通用 | 整个U-BOOT编译过程的规则文件 |
kbuild mkconfig | 文件,通用 | 对Makefile功能的补充,使得编译更加高效 |
其余 | 文件,通用 | 介绍文档以及其他 |
下面开始正式移植步骤:
(1) 修改顶层Makefile添加开发板配置选项
因为我们编译出来的u-boot是要在arm平台上运行的,所以要定义交叉编译工具arm-linux-gcc,使用vim Makefile后,可以使用/CROSS_COMPILE来搜索定位到该处,修改如下。
# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
CROSS_COMPILE = arm-linux-
# SHELL used by kbuild
U-BOOT-2010中顶层Makefile可以看到smdk2440a_config,在u-boot2014-04中已经没有了,使用命令grep “smdk24*” * -nR,结果如下:
可以看到在2014下,开发板的配置选项已经更改到了顶层目录下的boards.cfg下,这时我们进去添加mini2440的开发板配置选项
更改如下:
(2) 在/board中建立mini2440的目录和文件,拷贝配置头文件
我们移植以smdk2410为蓝本,拷贝board/samsung/smdk2410目录到board/mini2440,在顶层目录下:
cp –a board /samsung/smdk2410/ board/mini2440/mini2440
然后进入board/mini2440目录下进行修改,以smdk2410.c为蓝本移植:
mv smdk2410.c mini2440.c
接下来拷贝配置头文件:
cp include/configs/smdk2410.h include/configs/mini2440.h
(3) 配置时钟
2410和2440时钟的初始化参数不一样,这里需要做出修改,根据arch/arm/cpu/u-boot.lds文件可知执行的第一个文件是arch/arm/cpu/arm920t/start.S,
其中关于时钟频率的代码如下,我做了注释,修改的话就是在这里:
ldr r0,=pWTCON //将pWTCON变量的地址放到r0中
mov r1,#0x0 //把立即数0放到r1中
str r1, [r0] //将R1中的值放到以r0为地址的存储单元中去,意思就//是设置寄存器的值来关闭看门狗
/*
*mask all IRQs by setting all bits in the INTMR - default
*/
mov r1,#0xffffffff
ldr r0,=INTMSK
str r1,[r0] //关中断
# ifdefined(CONFIG_S3C2410)
ldr r1,=0x3ff
ldr r0,=INTSUBMSK
str r1,[r0] //屏蔽子中断
# endif
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0,=CLKDIVN
mov r1,#3
str r1,[r0] //设置分频系数,默认1:2:4
#endif /* CONFIG_S3C24X0 */
经过修改的代码如下,可以上下对比看有哪些地方不同,红色为改动部分,标注出来了:
ldr r0,=pWTCON
mov r1,#0x0
str r1,[r0]
/*
*mask all IRQs by setting all bits in the INTMR - default
*/
mov r1,#0xffffffff
ldr r0,=INTMSK
str r1,[r0]
# ifdefined(CONFIG_S3C2410)
ldr r1,=0x3ff
ldr r0,=INTSUBMSK
str r1,[r0]
# endif
#ifdefined(CONFIG_S3C2440)
ldr r1,=0x7fff
ldr r0,=INTSUBMSK
str r1,[r0]
#endif/*CONFIG_S3C2440*/
#ifdefined(CONFIG_S3C2440)
#defineMPLLCON 0x4c000004 //系统主频的配置寄存器
#defineUPLLCON 0x4c000008 //usb频率配置寄存器
#defineCAMDIVN 0x4c000018 //照相机时钟分频寄存器
ldr r0,=CAMDIVN
mov r1,#0
str r1,[r0]
ldr r0,=CLKDIVN
mov r1,#0x05
str r1,[r0]
/*如果HDIVN不等于0,则设置CPU为异步纵向模式,所谓异步总线就是各部件和设备不采用统一时钟,
彼此间通信采用握手信号,总线时序不固定,可以兼容多种设备*/
mrc p15,0,r0,c1,c0,0 /*参看ARM的数据手册,这是一个协处理器的操作指令,此处为将协处理器p15的寄存器中的数据传送到ARM处理器的寄存器r0中,其中1是协处理器操作码1,0是协处理器操作码2,c1存放第一个操作数的协处理器寄存器,c0存放第二个操作数的协处理器寄存器*/
orr r1,r1,#0xc0000000 /*让CPU的总线从fast变为asynchronous,orr的是一个逻辑或指令*/
mcr p15,0,r0,c1,c0,0
ldr r0,=UPLLCON
ldr r1,=0x38022//USB的48MHZ时钟
str r1,[r0]
nop
nop
nop
nop
nop
nop
nop
ldr r0,=MPLLCON
ldr r1,=0x5c011 //CPU时钟400MHZ
str r1,[r0]
#else
/* FCLK:HCLK:PCLK = 1:2:4 */
/* default FCLK is 120 MHz ! */
ldr r0,=CLKDIVN
mov r1,#3
str r1,[r0]
#endif /*CONFIG_S3C1440*/
#endif /* CONFIG_S3C24X0 */
由于在mini2440.c中也对时钟做了初始化,在此处需要将其去掉,在函数board_early_init_f()中,如下:
(4)修改配置头文件
在include/configs/mini2440.h中,主要是添加命令行的自动补全功能,还有命令提示符,再将一些暂时不用的功能去掉。
去掉2410增加2440,增加命令行自动补全
去掉CS8900网卡部分支持
去掉USB部分的支持,包括键盘,USB存储等等
去掉部分命令的支持
(5)下载u-boot到ram中运行
修改配置文件mini2440.h
#define CONFIG_SYS_TEXT_BASE0x30008000
这是代码的加载地址,编译好之后,我们就把u-boot下载到这个地址里面去,这个地址正好是mini2440的SDRAM起始地址,由于在lowlevel_init中对底层做了初始化,因此在mini2440.h中在加入以下宏以取消对内存数据代码的破坏
#define CONFIG_SKIP_LOWLEVEL_INIT
修改好后,在顶层目录下,执行make mini2440_config
会提示:Configuring for mini2440 board…
接着make
不出问题会生成一个u-boot.bin,这个u-boot只是最初的,还不能使用,后面还会加入很多东西。
然后chmod 777 u-boot.bin更改权限,再cp u-boot.bin /tftpboot/将生成的u-boot拷贝到tftp传输的目录下,连接开发板网线,连接串口,在开发板里面要有一个能够运行的u-boot ,我用的是之前自己移植的u-boot-2010,启动后输入指令tftp 0x30008000 u-boot.bin,下载到RAM中,然后go 0x30008000就可以看到串口输出以下信息,说明我们初步的移植成功了。
后期还有很多工作要做,打算按照友善之臂的思路,根据执行流程进一步移植,下一篇翻译讨论U-BOOT的README,这样便于移植过程的理解和掌握。