一、uboot移植
在移植之前要先对uboot的源码结构有一定熟悉
1.uboot源码顶层目录下各源码文件夹的作用
2.编译后生成的uboot.xxx 各文件后缀含义
关于以上两点社区已经有很多前辈总结的很详细,这里不做赘述。
对于uboot源码分析韦东山老师b站上有免费的课程,时间富余的话推荐看一下,会对uboot源码有更深刻的认识。
准备交叉编译工具链
1. 下载交叉编译工具链
sudo apt-get install arm-linux-guneabihf-gcc
安装完后可以看一下安装的版本号对不对,我这里arm-linux-gcc安装的是4.9.4版本,我的uboot版本是2015年的(不同版本的uboot适用的编译器版本也不同,高版本的gcc编译器不一定兼容老的uboot源码,可能会导致编译失败)
arm-linux-gnueabihf-gcc -v
2. 导出编译工具路径,指定顶层Makefile中的CROSS_COMPILE = arm-linux-gnueabihf-
ARCH = arm CROSS_COMPILE = arm-linux-gnueabihf-
3.在/home/xinje/crosscompile路径下,指定编译工具路径(这里是我自己的路径,具体路径视自己情况而定)
export PATH=$PATH:/home/xinje/crosscompile/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin
uboot配置
在控制台输入下面的命令,其中xxx_xxx_defconfig是配置文件,具体用什么配置文件取决于你的需要
make xxx_xxx_defconfig
题外话:xxx_defconfig文件从何而来呢 ?
最开始所有的配置文件 xxx_defconfig 都是不存在的,那我们拿到uboot源码后,要配置使用的话,只能通过 make menuconfig 进入图形化配置界面配置uboot后,再来编译,但这样每次都通过make menuconfig 来一个个打开开关的话过于麻烦,那能不能有一个命令可以把我们每次配置完后的配置情况记录下来呢,于是就有了make savedefconfig命令, 我们在配置完后,控制台输入make savedefconfig,这个命令便会保存我们在make menuconfig中选择的开关,并在顶层目录下生成一个配置文件defconfig,此时我们通过mv指令,mv defconfig ./configs/xxx_defconfig,源码顶层目录下的configs文件中的各种defconfig配置文件就是这样生成的。(以上是个人的一些推断,不对之处烦请指正)
注意:如果make xxx_defconfig之后,若还想要打开一些配置开关的话,可以再通过make menuconfig来进行配置,不过要注意要在make xxx_defconfig之后再make menuconfig,二者先后顺序不可颠倒,否则会清掉make menuconfig的配置。
uboot烧写
烧录工具采用Uniflash_3.4.1.00012_win32版本,通过usb 串口(模拟网口)进行烧录
首先将u-boot-spl-restore.bin,u-boot-restore.img,MLO, u-boot.img四个文件放在同一文件夹中(前两个用usb版本的配置信息生成,后两个用debug版本的配置信息生成),为烧录软件配置好IP和文件路径,再将板子的拨码开关打到no(uboot从USB处启动),之后开始烧录,烧录软件会先将前两个文件烧录到ddram中运行,这时uboot已经在板子上跑起来,然后就可以使用uboot命令将MLO和u-boot.img烧录到nandflash中。
烧录的三个阶段:
第一阶段, 设置 AM335x 的 sysboot 管脚,使 AM335x 的启动项包含 USB 启动。(前人已做好)板子上电后从 USB 启动,芯片内部的固件会初始化 USB RNDIS 以太网络通信协议,AM335x通过 uniflash 自带的 dhcp 服务获取 IP 地址,然后再通过 uniflash 自带的 tftp 服务将用于程序烧写的 u-boot-spl-restore.bin 下载到 AM335x 的内部 RAM 并运行。
第二阶段, 用于程序烧写的 u-boot-spl-restore.bin 执行之后, 会再次初始化 USB RNDIS 以太网络通信协议,AM335x 再次通过 uniflash 自带的 dhcp 服务获取 IP 地址,然后再通过 uniflash 自带的 TFTP 服务将用于程序烧写的 u-boot.img 下载到 DDR 中并运行。
第三阶段,用于程序烧写的 u-boot-restore.img 执行之后, 在 u-boot 中通过 tftp 命令,
将 MLO和u-boot.img烧录到nandflash中。
板子断电,将拨码开关复位(uboot从nandflash启动),再次上电,查看串口信息,uboot成功从nandflash启动。
注意:
1.烧录软件 TI 官网上已经下载不到这个版本(实测新版本的是无法使用的)
2.烧录软件的网络配置视自己情况而定
题外话:uboot从nandflash处启动流程的一些个人分析
一般来说,编译好的uboot镜像文件有两个:
MLO:也称 SPL ,是uboot启动的一阶段映像,作用是初始化必要的引导设备,如nandflash、IIC、DDR等
u-boot.img:是uboot启动的二阶段映像,作用是初始化其他所有的设备,如计时器、时钟等
不禁要问,为什么uboot的镜像文件要分两个呢,内核的镜像文件从来都是一个?
首先,镜像文件的本质是什么,是一段二进制可执行程序而已,既然是可执行程序,那一定得有一个能运行这段程序的一块内存空间。要知道uboot的工作是初始化板子的各个外设,在uboot运行之前可没程序为他初始化好内存(DDR),那他在哪里跑呢。
为了解决这个问题,在SOC设计之初,就将CPU和一小块片内内存SRAM和片内外存BOOTROM都集成到SOC内部,BOOTROM不同于nandflash(块设备,出厂时没有地址编码,只能固定操作512字节,使用时必须依赖一个外部nandflash控制器,而这个控制器要靠uboot来初始化)BOOTROM内部有地址编码,CPU可以直接利用地址编码来进行寻址,无须初始化,但问题是因为要集成到SOC内部,BOOTROM和SRAM受限于成本只能做的很小,一般小的几十k,大一点的也就一两百k,这点空间可不够存储和运行uboot镜像,而且烧写到这也不方便。
于是BOOTROM中只放一个永远不动的固件,这段程序只负责将uboot的一阶段映MLO像拷贝到SRAM中运行,再由MLO初始化好必要的外设后(DDR、nandflash控制器),将二阶段映像拷贝到DDR中运行,最后由二阶段映像完成所有的外设初始化。
调试过程中遇到的一些问题:
Uboot选择从usb处启动,uboot镜像文件版本为debug版本,但上电后(理论上会先把要烧写的文件先下载到ddr然后烧写到nand中,以上执行完后停在uboot菜单)不会停在uboot菜单,而是直接去启动linux内核。
Print bootcmd后发现,执行了bootnand脚本,print bootnand后发现确实去启动内核了。这和debug版本的bootcmd不符合,原因是uboot会优先从nand中拿环境变量,而nand中上一次刚好烧录了relies版本的uboot,导致uboot直接用了nand中上次的环境变量。
用env default -a命令清除nand中上次的环境变量,然后saveenv,让uboot使用本次烧录的ddr中的环境变量。再次上电问题得到解决。
二、linux内核移植
Linux源码结构熟悉:
- linux各源码文件夹的作用
- zImage .xxx各文件后缀含义
linux配置:
make xxx_defconfig
linux编译:
编译内核镜像:make zImage
编译设备树:make ts3_7.dtb
linux内核和设备树文件更新:
由于需要将内核镜像和是设备树文件打包为ubi文件(比较复杂),换一种内核更新的方式,先将已有的打包好的ubi文件通过usb的方式烧录到板子上,之后再通过tftp单独更新/boot文件夹下的zImage文件和dtb设备树文件。