移植U-boot
(一)初试
在官网上下载最新的uboot(u-boot-2012.04.01)压缩包,并将其拖到服务器上;
1.1 在SecureCRT上第一次尝试编译
1.2 出错
出错原因:编译工具链版本低。
1.3 查看当前交叉编译工具链版本
安装新的编译工具链(arm-linux-gcc-4.3.2);
2.1 解压到根目录
2.2 修改环境变量(进入根目录/usr/local/arm/4.3.2/bin)
另一种方法(如下图):sudo vi /etc/environment
再次编译u-boot,进入之前u-boot-2012.04.01文件夹
3.1 清除之前编译的:make distclean
3.2 配置:make smdk2410_config
3.3 编译:make
3.4 编译成功–生成u-boot.bin文件
将生成u-boot.bin文件用eop下载到NOR Flash,启动,但串口上并没有什么显示。(这是正常的,因为还没有做修改)
(二)源码分析启动过程
创建si工程;
添加代码时:board文件夹只需添加的Samaung中的smdk2410,arch文件夹下的Arm->cpu->arm920t->s3c24x0、include->Asm->arch-s3c24x0是我们关注的,其他文件夹可以均添加上。
第一阶段代码分析(文件:start.S (arch\arm\cpu\arm920t),lowlevel_init.S (board\samsung\smdk2410))
2.1 将CPU的工作模式设为管理模式(svc):/* set the cpu to SVC32 mode */
2.2 关闭看门狗:/* turn off the watchdog */
2.3 /* mask all IRQs by setting all bits in the INTMR - default */
2.4 设置FCLK、HCLK、PCLK的比例(设置CLKDIVN寄存器):/* FCLK:HCLK:PCLK = 1:2:4 */
2.5 设置内存控制器: cpu_init_crit
a. /* flush v4 I/D caches */ b. 关闭MMU、CACHE:/* disable MMU stuff and caches */ c. 跳转至lowlevel_init:bl lowlevel_init 为加载BootLoader的第二阶段代码准备RAM空间(lowlevel_init.S)--开发板相关 即:初始化内存芯片,对于S3C2440,使得外接的SDRAM可用。 lowlevel_init函数,并不复杂,只是这时的代码、数据只保存在NOR FLASH中,内存中还没有,所以读取数据时要变换地址。
第137-139行:进行地址变换,因为这时候内存中还没有数据,不能使用链接程序时确定的地址来读取数据。 第137行:SMRDATA表示这13个寄存器的值存放的开始地址(连接地址),为0x33F8xxxx,处于内存中。 第138行:获得代码段的起始地址,即“_TEXT_BASE”,在board\smdk2410\config.mk中定义"TEXT_BASE = 0x33F80000" 第139行:将0x33F8xxxx与0x33F80000相减,就是13个寄存器值在NOR Flash上存放的地址。
2.6 设置栈,调用C函数board _ init _ f:/* Set stackpointer in internal RAM to call board_init_f */
a. 调用函数数组init_sequence里的各个函数:(例)board_early_init_f : 设置系统时钟、设置GPIO b. board _ init _ f最后调用的重定位函数:relocate_code(addr_sp, id, addr); addr:把NOR Flash中的程序拷贝到哪里去; addr_sp:设置的栈; id:一些变量的地址 1. addr addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size; /* CONFIG_SYS_SDRAM_BASE=0x30000000, gd->ram_size=64MB, 所以addr=0x34000000 */ addr -= (4096 * 4); /* addr = 33FFC000 */ addr &= ~(0x10000 - 1); /* addr = 33FF0000 */ addr -= gd->mon_len; /* gd->mon_len = _bss_end_ofs;--uboot程序的大小:AE4E0(反汇编文件中),所以addr= 33F41B20 */ addr &= ~(4096 - 1); /* addr=33F41000 */ 2. addr_sp addr_sp = addr - TOTAL_MALLOC_LEN; addr_sp -= sizeof (bd_t); addr_sp -= sizeof (gd_t); addr_sp -= 12; 3. id id = (gd_t *) addr_sp; /* 指向一个结构体gd_t */
2.7 重定位代码
分析重定位代码(start.S文件):relocate_code(addr _ sp, id, addr)–C语言调用汇编(其中addr _ sp存储到r0,id存储到r1,addr存储到r2)
2.8 clear_bss
2.9 调用C函数board_init_r:第2阶段的代码
(三)修改代码
(I)修改代码— 建新板 _ 时钟 _ SDRAM _ UART
(II)修改代码—支持NAND启动
(III)修改代码—支持Nor Flash(读写)
(IV)修改代码—支持Nand Flash(读写)
(V)修改代码—支持DM9000网卡
(四)裁剪和修改默认参数
易用性裁剪uboot(修改配置文件smdk2440.h)
—重新编译后的uboot大小
修改默认参数
2.1 修改默认参数
—启动后,从串口提示信息找到文件
—设置配置文件中的参数
2.2 参考内核中的分区
set ipaddr 192.168.0.4 set ethaddr 00:0c:29:07:33:a6 set serverip 192.168.0.2 tftp 30000000 uImage_4.3 bootm 30000000
—设置参数
—内核启动后,查看分区
2.3 设置关于存储环境变量分区的参数
—由sav命令的帮助信息(saveenv),找到所需文件
—根据目录,查看其文件夹下的Makefile,找到该文件编译进uboot所需的宏,并在配置文件中定义该宏
—在Env_nand.c文件的saveenv函数中,找到我们还需要定义的宏
—在配置文件中,参照2.2中内核的分区,设置宏
上传配置文件,重新编译uboot后,在串口设置环境变量后用tftp烧写新的uboot到sdram,然后再用命令将其拷贝到NOR Flash中
—重启后,打印变量
—消除之前的警告
—uboot移植到这里也基本上完整了。
设置分区–以便我们使用(仅仅是方便的功能)
4.1 添加mtdparts命令所需的宏:所需要编进uboot的文件为cmd_mtdparts.c,在所在目录下的Makefile中找到所依赖的宏,并在配置文件中定义该宏
4.2 在uboot源码下执行命令搜索:grep “mtdparts” * -nR,找出参考文件来仿照设置分区
—参考文件
—配置文件中定义
4.3 根据老师试验,还需在Board.c文件中加入一行代码
4.4 将修改的两文件上传,重新编译失败并解决该问题
4.4 将修改的两文件上传,重新编译成功后,现在可以直接下载到sdram(不用设置环境变量),再复制到NOR Flash中重启开发板,执行mtdparts命令,出现如图打印
4.5 试验–把下载到sdram中的拷贝到Nand Flash
—下载uImage_4.3到sdram
—擦除(原:nand erase 60000 200000)
—nand写(原:nand write 30000000 60000 200000)
最后,我们在将之前的bootcmd修改一下,重新编译
—此时,我们可以不用再烧写uboot,直接在串口上设置bootcmd,保存,重启
—打印查看
—此时我们再次reset,uboot启动后,倒数5秒后就会直接启动内核
(五)支持yaffs映像及制作补丁
试验1–烧写JFFS文件系统
1.1 tftp烧写文件(嵌入式–第二期\资料光盘\bin\文件系统)fs_mini_mdev.jffs2
tftp 30000000 fs_mini_mdev.jffs2
1.2 拷贝到Nand中文件系统分区
nand erase.part rootfs nand write.jffs2 30000000 260000 5b89a8 注:这里260000就是文件系统分区的偏移地址,5b89a8就是fs_mini_mdev.jffs2的文件大小(tftp烧写完即可得到)
1.3 设置bootargs
set bootargs console=ttySAC0 root=/dev/mtdblock3 rootfstype=jffs2
1.4 boot后,启动内核,成功挂载jffs2文件系统
试验2–烧写yaffs文件系统
1.1 重启开发板,tftp烧写文件(嵌入式–第二期\资料光盘\bin\文件系统)fs_mini_mdev.yaffs2
tftp 30000000 fs_mini_mdev.yaffs2
1.2 拷贝到Nand中文件系统分区
nand erase.part rootfs nand write.yaffs 30000000 260000 889bc0 注:这里260000就是文件系统分区的偏移地址,889bc0就是fs_mini_mdev.yaffs2的文件大小(tftp烧写完即可得到)
执行完上条命令会出现如下图错误提示,需在配置文件中配置相应的宏,重启编译并烧写新的uboot后,重新烧写文件系统
—找到根源文件
—配置宏
1.3 bootargs不用修改,选择默认即可
1.4 boot后,启动内核,串口出现如下图错误指示
解决试验2的问题
3.1 比较源文件fs_mini_mdev.yaffs2(用UE打开)和烧写到Nand中的文件(nand dump命令),发现Nand中的第一页的oob与源文件不符并且其余页均为数据均不符
补充:现开发板使用的Nand:一页大小为2M(包含oob)
—源文件(第一页oob)
—nand(第一页oob)
—源文件(第二页数据)
—nand(第二页数据)
3.2 修改相关文件
—适用nand有坏块的情况
3.3 重新编译、烧写uboot
tftp 30000000 u-boot.bin;protect off all;erase 0 3ffff;cp.b 30000000 0 40000
3.4 重复试验2烧写yaffs文件系统的步骤
到这里,我们已经完整的移植了2012版的uboot了!!!
<补充:制作uboot的补丁文件>
制作补丁文件(使用diff命令)
—制作步骤
—查看补丁文件
打补丁(进入之前源码解压后的文件夹)
patch -p1 <../u-boot-2012.04.01_tp.patch
注:../表示补丁文件在该文件夹的上层目录下,即/work/system
最后,配置编译,生成新的uboot.bin文件,用tftp烧写到NOR Flash中,并将yaffs文件系统烧到NAND分区中,boot后成功挂载(与之前一步一步修改的效果是一样的)。
2017.11.25