暑假在淘宝上买了一块OK6410板子,希望有空的时候研究一下,毕竟对这方面蛮感兴趣的。
大致的计划,现了解linux系统,包括bootloader,kernel和cramfs。整个流程自己编译一遍,体验一下,希望从中能够学到点东西。
好现在入正题。
u-boot源代码的官方下载地址:点击打开链接
1. 搭建开发平台
采用ubuntu10.04,毕竟自己比较熟悉。第一步要安装交叉编译工具,arm-linux-gcc 4.3.2。即我要在linux操作系统上编译能够在arm平台上运行的代码。“交叉”非常形象。
2. uboot分析
首先看下uboot(使用的是1.1.6版本)的工程结构
子 目 录 名 | 作 用 |
board | 开发板相关的定义和结构 |
common | 包含U-Boot用到的各种处理函数 |
cpu | 各种不同类型的处理器相关代码 |
doc | U-Boot文档 |
drivers | 常用外部设备驱动程序 |
examples | 存放U-Boot开发代码样例 |
fs | 文件系统有关的代码,包括cramfs、ext2、fat等常见文件系统 |
include | U-Boot用到的头文件 |
lib_arm | ARM体系结构有关的数据定义和操作 |
lib_generic | U-Boot通用的操作函数 |
net | 常用的网络协议,包括bootp、rarp、arp、tftp等 |
post | 上电自检相关代码 |
rtc | 实时时钟有关操作 |
tools | U-Boot有关的数据代码 |
● board目录存放与开发板有关的文件,每种开发板需要的文件被归纳在board目录的一个目录下。该目录包括每个子目录需要至少提供Makefile和u-boot.lds两个文件,用来设置文件编译的方式以及开发板的硬件资源。如board/smdk2410目录存放了与smdk2410开发板相关的硬件资源和配置函数。
● common目录是与体系结构无关的文件,包括实现各种命令的C语言源代码文件。
● cpu目录存放与CPU相关的文件,每种CPU需要的代码文件存放在以CPU名称命名的子目录下,arm920t存放了arm920t为内核的CPU相关的文件。在每个特定的子目录下都包括cpu.c、interrupt.c和start.S这3个文件,这3个文件是CPU初始化以及配置中断的代码。U-Boot自带了很多CPU相关的代码,用户可以在现有CPU支持的基础上修改自己所需要的配置。
● 通用设备的驱动程序存放在drivers目录下。U-Boot自带了许多设备的驱动,包括显示芯片、网络接口控制器、USB控制器、I2C器件等,对于大多数用户而言已经够用,用户也可以按照自己的需求增加或者修改设备驱动。
● fs存放支持的文件系统代码,U-Boot目前支持cramfs、ext2、fat、jffs、reiserfs、yaffs等多种常见的文件系统。
● net目录是与网络协议有关的代码,比如BOOTP协议、TFTP协议、RARP协议等。
● post存放与硬件自检有关的代码。
● rtc目录存放与硬件实时时钟相关的代码。
● tools目录存放U-Boot编译过程中用到的一些工具代码
大多数 Boot Loader 都包含两种不同的操作模式:"启动加载"模式和"下载"模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,Boot Loader 的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
启动加载(Boot loading)模式:这种模式也称为"自主"(Autonomous)模式。也即 Boot Loader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。这种模式是 BootLoader 的正常工作模式,因此在嵌入式产品发布的时侯,Boot Loader 显然必须工作在这种模式下。
下载(Downloading)模式:在这种模式下,目标机上的 Boot Loader 将通过串口连接或网络连接等通信手段从主机(Host)下载文件,比如:下载内核映像和根文件系统映像等。从主机下载的文件通常首先被 BootLoader 保存到目标机的 RAM 中,然后再被 BootLoader 写到目标机上的 FLASH 类固态存储设备中。BootLoader 的这种模式通常在第一次安装内核与根文件系统时被使用;此外,以后的系统更新也会使用 BootLoader 的这种工作模式。工作于这种模式下的 Boot Loader 通常都会向它的终端用户提供一个简单的命令行接口。
UBoot 这样功能强大的 Boot Loader 同时支持这两种工作模式,而且允许用户在这两种工作模式之间进行切换。
大多数 bootloader 都分为阶段 1(stage1)和阶段 2(stage2)两大部分,uboot 也不例外。依赖于 CPU 体系结构的代码(如 CPU 初始化代码等)通常都放在阶段 1 中且通常用汇编语言实现,而阶段 2 则通常用 C 语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。
详细可以参见原文链接:uboot工作流程
大致可以这样概括,stage 1 的代码通常放在start.s中,用汇编语言实现CPU软硬件的初始化,包括中断向量,看门狗之类的,与之前做得DSP初始化相近。
stage2: Lib_arm/board.c 中的 start armboot 是 C 语言开始的函数,也是整个启动代码中 C 语言的主函数,同时还是整个uboot(armboot)的主函数,该函数主要完成 初始化工作,进入命令行模式以及代码搬运。Nand flash启动就是先把uboot的stage 1搬运到SDRAM中,俗称4K steppingstone。然后将剩下的uboot从nandflash搬到SDRAM中。
3. 尝试编译官方给的uboot源码
飞凌客服已经针对linux内核版本和内存大小(128M还是256M)修改好了源码,具体下载地址:下载
我只做了3处修改:
(1) Makefile中修改交叉编译的路径
CROSS_COMPILE = /usr/local/arm/4.3.2/bin/arm-linux-
(2)对mkconfig中删除文件夹语句加入 -r
(3)将交叉编译工具的路径加入到path中(如果不设置,在make smdk6410_config时会出错。)
具体设置方法见 参考
/usr/local/arm/4.3.2/bin
编译过程:make clean
make smdk6410_config
make
最后得到uboot.bin
所以要好好学习makefile以及shell编程
4. 对比2.6.36内核256M版本和128M版本的uboot区别
主要有两个区别,其一是\include\config\smdk6410.h文件; 其二是\board\samsung\smdk6410\lowlevel.s
主要不同点就是:
smdk6410.h
#define DMC1_MEM_CFG0x00010012/* Supports one CKE control, Chip1, Burst4, Row/Column bit */
#define DMC1_MEM_CFG 0x0001001a (256M)
#define DMC1_CHIP0_CFG0x150F8 (128M)
#define DMC1_CHIP0_CFG 0x150F0 (256M)
#define PHYS_SDRAM_1_SIZE0x08000000 (128M)
#define PHYS_SDRAM_1_SIZE 0x10000000 (256M)
lowlevel.s
// 128MB for SDRAM 0xC0000000 -> 0x50000000 | // 128MB for SDRAM 0xC0000000 -> 0x50000000
.set __base, 0x500 | .set __base, 0x500
.rept 0xD00 - 0xC00 | .rept 0xC80 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1 | FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1 | .set __base,__base+1
.endr | .endr
|
// access is not allowed. | // access is not allowed.
.rept 0x1000 - 0xD00 | .rept 0x1000 - 0xc80
.word 0x00000000 | .word 0x00000000
.endr | .endr
|
#endif | #endif
以上左边的是256M,右边的是128M.
以上代码属于GNU汇编,相关参考文件点击打开链接
D00-C00 = 10000000 = 256M,而邮编则正好等于128M。具体可以参考点击打开链接
具体为什么这么修改,可以参考这篇博客参考
5. u-boot相关命令及烧写
当板子上有了uboot后就可以通过串口线和uboot共同完成kenel和cramfs的烧写。
在linux中,使用的串口通信软件是minicom,其实还是很好用的,ctrl+a然后再按Z就能进入minicom的命令操作端,提示非常清除。
uboot像vivi一样,有丰富的命令,可以通过help来进行查询。其中比较重要的是,printenv查看一些环境信息;nand erase mem_start mem_end 擦除内容;nand write mem_start mem_end 写入内容。
在minicom中,可以通过ymodem的传输协议进行文件的传送,可以使用uboot中的loady命令,具体如下:
loady 0x50008000 (存放文件的地方)
通过minicom进行文件的传输。
nand erase 0x100000(start) 0x500000(size) 擦除以前的内容
nand write 0x100000 0x500000 写入内容
至此完成uboot的烧写工作
可以参考点击打开链接