Linux / 嵌入式 · 2021-12-02

uboot进行烧写kernel和rootfs(squashfs)

1. 首先生成mksquashfs工具,进入osdrv\tools\pc\squashfs4.3,make 生成mksquashfs,大约1.2M,制作squashfs命令:

mksquashfs ${BASE_ROOTFS} ${PRODUCT}-rootfs.sqsh4 -b 64K -comp xz -noappend

最近再移植hi3519的kernel和rootfs,由于是在别人的板子上进行移植,已经存在uboot了,所以只需再uboot下把自己的kernel和rootfs文件烧进去即可

第一步: 准备kernel

kernel我就用海思官方提供的已经生成好的uImage,如有不同可自行下载linux源码修改编译。

第二步:准备rootfs

rootfs需要跟自己开发板上的flash相对应,不同的文件系统有不同的优缺点,下列出常用的文件系统分类,更详细的可自行百度查看。

常用文件系统包括有 cramfs、jffs2、NFS、initrd、yaffs2、ext4 以及
squashfs、ubifs。它们的特点如下:
cramfs 和 jffs2 具有好的空间特性,很适合嵌入式产品应用。
cramfs 与 squashfs 为只读文件系统,目前只有 SPI Nor FLASH 支持这两种文件系
统。
squashfs 压缩率最高。
jffs2 为可读写文件系统。
NFS 文件系统适用于开发初期的调试阶段。
yaffs2 文件系统只用于 NAND Flash。
initrd 采用 cramfs 文件系统,为只读。
ext4 文件系统用于 eMMC 卡

 

想知道自己是那种flash,可问硬件工程师,也可再uboot界面查看到,例如

图中所画出的红线里有flash的类型和大小,我的是nor flash 32MB,黄线画出的是flash的块大小,我的是64k,那么就可以制作文件系统了,制作的命令海思官方文档里有详细说明,我所需要的文件系统海思刚好有提供例程,我就直接拿来用了。

第三部:开始移植

进入uboot, 先查看基本信息:

bdinfo

arch_number = 0x00001F40
boot_params = 0x40000100
DRAM bank = 0x00000000
-> start = 0x40000000
-> size = 0x08000000
eth0name = eth0
ethaddr = 72:bd:88:4a:24:05
current eth = eth0
ip_addr = 192.168.1.70
baudrate = 115200 bps
TLB addr = 0x47FF0000
relocaddr = 0x47F5F000
reloc off = 0x0775F000
irq_sp = 0x47F1EEE0
sp start = 0x47F1EED0
Early malloc usage: 70 / 2000

 

printenv

arch=arm
baudrate=115200
board=hi3516ev300
board_name=hi3516ev300
bootargs=mem=40M console=ttyAMA0,115200 root=/dev/mtdblock2 rootfstype=squashfs mtdparts=hi_sfc:320K(boot),1856K(kernel),1024K(rootfs),384K(config),4608K(data)
bootcmd=sf probe 0;sf read 0x42000000 0x50000 0x1d0000;bootm 0x42000000
bootdelay=3
cpu=armv7
ethact=eth0
ethaddr=72:bd:88:4a:24:05
fileaddr=42000000
filesize=fe000
ipaddr=192.168.1.70
serverip=192.168.1.188
soc=hi3516ev300
stderr=serial
stdin=serial
stdout=serial
vendor=hisilicon
verify=n
Environment size: 558/65532 bytes

getinfo spi

Block:64KB Chip:8MB*1
ID:0x20 0x70 0x17
Name:”XM25QH64A”

编译好的文件:
uImage 1.3M
rootfs_hi3516ev300_64k.jffs2 3.1M

mw.b 0x42000000 0xff 0x166666  //文件1.3M, 把内容空间设为1.4M, 将0xff写入到开发板内存的0x42000000开始到加0x166666(16进制)处,
tftp 0x42000000 uImage //这一部是将准备好的uImage下载到上面指定的内存位置
sf probe 0 //在开始sf操作前,需要先执行这条命令,否则再运行sf write或者sf erase时,会报错
sf lock 0 //解除写锁定
sf erase 0x50000 0x166666 //因为我的开发板有uboot在,上面环境有显示uboot分区大小(320K),转换为16进制后是0x50000,所以我从flash开始偏移0x50000(320K)处开始擦粗上面的程序,总共要擦除0x166666(1.4M),因为我的kernel需要这么大空间
sf write 0x42000000 0x50000 0x166666 //接下来就是将原来下到开发板内存处0x22000000的程序写到刚刚flash腾出来的地方了,0x42000000代表我刚刚下的uImage存放的位置,0x50000代表flash上偏移的值,为320K,之前的0~50000我用来存放uboot, 0x166666代表我所需要搬运的程序的大小,我的uImage定的是1.4M,所以需要搬运0x166666

然后下载我的rootfs_hi3516ev300_64k.jffs2,跟烧写kernel差不多,就是偏移值不同

mw.b 0x42000000 ff 0x400000
tftp 0x42000000 rootfs_hi3516ev300_64k.jffs2
sf probe 0
sf erase 0x1b6666 0x400000 // 因为我的kernel加uboot已经有1.8M了,所以要从0x1b6666(1.8M)开始烧rootfs(4M)
sf write 0x42000000 0x1b6666 0x400000

 

 

另一种情况, 如果我只想刷rootfs呢, 那就计算已有内核和uboot的大小, 然后只下载rootfs, 偏移值不同

mw.b 0x42000000 ff 0x500000  //文件3.1M, 把空间设为5M
tftp 0x42000000 rootfs_hi3516ev300_64k.jffs2
sf probe 0;sf erase 0x220000 0x500000 // 原有uboot和kernel分别是320K和1856K, 转换一下地址值是,所以要从0x220000(2.2M)开始烧rootfs(5M)
sf write 0x42000000 0x220000 0x500000

 

setenv bootargs ‘mem=40M console=ttyAMA0,115200 root=/dev/mtdblock2 rw rootfstype=jffs2 mtdparts=hi_sfc:320K(boot),1856K(kernel),5M(rootfs)’
setenv bootcmd ‘sf probe 0;sf read 0x82000000 0x100000 0x500000;bootm 0x82000000’
hisilicon # save
Saving Environment to SPI Flash…
Erasing SPI flash…Writing to SPI flash…done
hisilicon #
hisilicon #
hisilicon # re
resetting …

 

bootarg参数介绍

mem:内存大小,我的海思板是512MB,但是我分配128M给OS,384M给mmz

console:串口配置参数,ttyAMA0是串口的设备文件/dev/ttyAMA0,115200是串口的波特率(与PC的串口波特率一致)

root:rootfs文件系统的块文件路径(/dev/mtdblock0是uboot,/dev/mtdblock1是kernel,/dev/mtdblock2是rootfs)

rootfstype:rootfs文件系统类型为jffs2

rw: 文件系统具有读写权限

mtdparts=hi_sfc:1M(boot),5M(kernel),26M(rootfs)

mtdparts:flash上的映像文件分区,boot占1M,kernel占5M,rootfs占26M(我的flash是32M); mtdparts=hi_sfc指定了其flash类型为spi flash,如果是mtdparts=hinand, 则其flash类型为nand flash;

 

==> bootcmd解析

sf probe 0 #初始化flash,0是spi总线号

sf read 0x82000000 0x100000 0x500000 #将flash上偏移地址0x100000大小为0x500000的数据读取到内存地址为0x82000000

bootm 0x82000000 #内核从内存为0x82000000启动内核映像文件

#0x82000000是固定地址,不要随便改

#0x100000为kernel映像在flash上的地址,0~0x0FFFF在flash上分配给了uboot映像文件,该值可以根据mtdparts的boot大小修改

#0x500000是kernel映像文件的大小

最后记得save或者saveenv,保存配置,不然重启(reset)不会生效。

 

设置IP:
ifconfig eth0 192.168.5.40 netmask 255.255.255.0
route add default gw 192.168.5.1

取消自动登录
将#::askfirst:-/bin/sh改为::askfirst:-/bin/login
再将::respawn:/sbin/getty -L ttyS000 115200 vt100 -n root -I “Auto login as root …”这一行注释掉

重新制作rootfs镜像:
tools/pc/jffs2_tool/mkfs.jffs2 -d ../package/rootfs_uclibc -l -e 0x10000 -o test.jffs2

-e 参数,扩展说明:
64K 对应 0x10000
128K 对应 0x20000
256K 对应 0x40000

这个命令还可以用一个-s参数,如下:
mkfs.jffs2 -o rootfs.jffs2 -r rootfs -e 0x1000 -s 0x40000 -n -l -X zlib –pad=0x300000
这个参数可以提高jffs2文件的压缩比,但是也会降低系统的启动速度,故而建议可以在生成roofs.jffs2时,默认不使用这个参数,实在需要压缩空间时,再启用这个参数。

定制busybox, 进入busybox源码目录
make ARCH=arm CROSS_COMPILE=arm-himix100-linux- menuconfig

扩展内容================================================================================

海思文档中提供了linux下的tftp,我用的是Windows下思科的TFTP服务器来进行传输,首先将准备好的uImag(kernel)和rootfs_hi3519av100_64k.jffs2(rootfs)放入思科TFTP服务器的根目录下,然后先下载uImage,首先输入

mw.b 22000000 ff 400000 //将0xff写入到开发板内存的0x22000000到0x22400000处,
为什么是400000呢,这里的400000是16进制数,转换成
十进制数后就是4M,我的kernel大小是3M多,刚好下进去还有多
这一步可以理解为将内存清出来给即将要下的uImage腾出位置。

tftp 22000000 uImage //这一部是将准备好的uImage下载到0x22000000处。

sf probe 0          // 在开始sf操作前,需要先执行这条命令,否则再运行sf write
或者sf erase时,会报错。

sf erase 100000 400000 // 因为我的开发板有uboot在,我给uboot的分区是想给他1M,所以
我从flash开始偏移100000(1M)处开始擦粗上面的程序,总共要
擦除400000(4M),因为我的kernel需要这么大空间

sf write 22000000 100000 400000 // 接下来就是将原来下到开发板内存处0x22000000的程序
写到刚刚flash腾出来的地方了
0x22000000代表我刚刚下的uImage存放的位置,
100000代表flash上偏移的值,为1M,之前的0~100000
我用来存放uboot,
400000代表我所需要搬运的程序的大小,
我的uImage定的是4M,所以需要搬运400000(4M)

后下载我的rootfs_hi3519av100_64k.jffs2,跟烧写kernel差不多,就是偏移值不同

mw.b 22000000 ff 1B00000
tftp 22000000rootfs_hi3516a_64k.jffs2
sf probe 0
sf erase 500000 1B00000 // 因为我的kernel加uboot已经有5M了,所以要从500000(5M)
开始烧rootfs(27M)
sf write 22000000 500000 1B00000

 

 

这只是最简单的分区了,分区的大小也可根据自己的需要修改,烧完后,需要设置启动参数,来告知系统我的分区是怎么样的。

setenv bootargs ‘mem=256M console=ttyAMA0,115200 clk_ignore_unused root=/dev/mtdblock2 rw rootfstype=jffs2 mtdparts=hi_sfc:1M(boot),4M(kernel),27M(rootfs)’
setenv bootcmd ‘sf probe 0;sf read 22000000 100000 500000; bootm 22000000’
sa

 

 

之后reset重启,然后就会进入你移植的文件系统了

 

 

2.内核kernel支持squashfs4.0文件系统

cp arch/arm/configs/hi3516ev200_xxx_defconfig .config
make ARCH=arm CROSS_COMPILE=arm-himixXXX-linux- menuconfig (保存退出即可)
打开支持xz压缩算法选项:
File systems —>
[*] Miscellaneous filesystems —>
<*> SquashFS 4.0 – Squashed file system support
[*] Include support for XZ compressed file systems

make ARCH=arm CROSS_COMPILE=arm-himixXXX-linux- uImage

3. 设定boot环境变量,设定文件系统分区

setenv bootargs ‘mem=32M console=ttyAMA0,115200 root=/dev/mtdblock3 mtdparts=hi_sfc:512K(boot),4096K(appfs),3584K(kernel),1984K(rootfs),64K(hardware),1024K(config),16M@0(flash)’

千万别这样写:

setenv bootargs ‘mem=32M console=ttyAMA0,115200 root=/dev/mtdblock3 rootfstype=sqsh4 rw mtdparts=hi_sfc:512K(boot),4096K(appfs),3584K(kernel),1984K(rootfs),64K(hardware),1024K(config),16M@0(flash)’

否则会出现下面的错误:

精简内核, 进入目录 osdrv/opensource/kernel/linux-3.4.y 执行:

make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- menuconfig

在make menuconfig 后在File systems —> 中看到:

a.该内核只支持ext4文件系统

b.[ ] Miscellaneous filesystems —>选项压根就没有勾选上,及时勾选上进去也看不到jffs2的选项

2.在Miscellaneous filesystems —>选项中添加jffs2选项卡:

Device Drivers —>

<*> Memory Technology Device (MTD) support —>(这个选项一选上后,File systems —> 中的Miscellaneous filesystems —>就会变成必选项了) 保存

3.去掉对ext4文件系统的支持,添加对jffs2和squashfs文件系统的支持

去掉:

File systems —>

< > The Extended 4 (ext4) filesystem

添加:

File systems —>

-*- Miscellaneous filesystems —>

<*> Journalling Flash File System v2 (JFFS2) support

和<*> SquashFS 4.0 – Squashed file system support

4.编译一遍 make uImage,然后将zImage烧到板子上go 0x81000000, /etc/init.d/S00devs脚本中有两句

mount -t squashfs /dev/mtdblock2 /mnt/app
mount -t jffs2 /dev/mtdblock3 /mnt/app_ext/

发现以下错误:

mount: mounting /dev/mtdblock2 on /mnt/app failed: No such device or address
mount: mounting /dev/mtdblock3 on /mnt/app_ext/ failed: No such device

5.解决mount 出错:

Device Drivers —>
<*> Memory Technology Device (MTD) support —>
[*] Command line partition table parsing

6.再编译一遍 make uImage,然后将zImage烧到板子上go 0x81000000,因为squashfs文件系统默认是ZLIB压缩算法的,而我们使用的是压缩率最高的XZ算法,因此会发现以下错误:

SQUASHFS error: Filesystem uses “xz” compression. This is not supported
mount: mounting /dev/mtdblock2 on /mnt/app failed: Invalid argument

7.解决xz压缩算法出错:

File systems —>
-*- Miscellaneous filesystems —>
<*> Journalling Flash File System v2 (JFFS2) support 下面的
[*] Include support for ZLIB compressed file systems(去掉勾选)
[*] Include support for XZ compressed file systems (加上勾选)

8.跑起来后,boot.sh脚本中对jffs2文件系统进行操作时,发现以下错误,因为加密算法类型0x07没有打到内核中:

jffs2: compression type 0x07 not available
jffs2: Error: jffs2_decompress returned -5

9.解决xz压缩算法出错:

File systems —>
-*- Miscellaneous filesystems —>
[*] Advanced compression options for JFFS2 下面的
[*] JFFS2 LZO compression support (加上勾选)

10.ok了,接下来就是遇到一些简单的错误,不再做详细阐述。

 

 

 

编译好的文件:
-rw-r–r– 1 developer developer 4.1M Mar 28 09:58 rootfs_hi3516dv300_64k.jffs2
-rwxr-xr– 1 developer developer 299K Mar 28 09:50 u-boot-hi3516dv300.bin
-rw-rw-r– 1 developer developer 3.5M Mar 27 18:33 uImage_hi3516dv300_smp

开始烧写

烧写步骤(用默认的按分区烧写):

1)选择传输方式:串口

2)选择与串口板连接的串口:COM1(每个人电脑各不相同)

3)打开分区xml文件;没有的自己创建或者下载我上传的附件,然后再根据自己的映像文件和器件类型修改;

4)勾选fastboot、kernel、rootfs

5)选择器件类型:spi nor(每个人的3516DV300海思板各不相同,根据实际配置);

6)可选步骤:没有分区xml文件的,手动添加方法参考上图的说明部分。配置好后,可以点<保存按钮>保存你的分区配置;

7)配置好串口后(参考准备部分),点击海思烧写工具<烧写>按钮,弹出进度条页面, 按下板上的串口升级按键,接通海思板的电源,然后海思烧写工具的进度条页面的进度条开始滚动。

网口烧录的命令分析
网口烧录的命令删除去中间的细节输出,整理如下所示:
开始下载过程。
启动成功启动!
发送命令:getinfo版本
版本:U-Boot 2016.11
[EOT](确定)
发送命令:sf probe 0 / / 选择spi flash 0
[EOT](确定)
发送命令:getinfo spi
块:64KB芯片:16MB * 1
ID:0xC2 0x20 0x18
名称:“ MX25L128XX”
[EOT](确定)
等待phy准备就绪,将需要8秒钟。
发送命令:setenv serverip 192.168.1.3
[EOT](确定)
发送命令:setenv ethaddr 00:8c:55:07:b0:88
[EOT](确定)
发送命令:setenv ipaddr 192.168.1.10
[EOT](确定)
发送命令:setenv网络掩码255.255.255.0
[EOT](确定)
发送命令:setenv gatewayip 192.168.1.1
[EOT](确定)
Tftp服务器下载主页切换到<\\ 10.175.126.15 \ zhuanjia \ zfdz \ camera0825 \ out \ ipcamera_hi3516dv300_liteos_a>
发送命令:mw.b 0x81000000 0xFF的0x590000 // 把内存中从 0X 8100 开始的 0X 590000 个字节全部置 1
[EOT](确定)
发送命令:tftp 0x81000000 OHOS_Image.bin // 把OHOS_Image.bin 文档加载到内存中去,起始地址为 0x 81000000。
海思ETH网络控制器
eth0:PHY状态更改:LINK = UP:DUPLEX = FULL:SPEED = 100M
使用eth0设备
来自服务器192.168.1.3的TFTP; 我们的IP地址是192.168.1.10
文件名“ OHOS_Image.bin”。
加载地址:0x81000000
传输的字节数= 5791744(586000 hex)
[EOT](确定)
发送命令:crc32 81000000 586000
crc32 for 81000000 … 81585fff ==> 78b90ed7
[EOT](确定)
发送命令:sf probe 0 / / 选择spi flash 0
[EOT](确定)
发送命令:sf擦除0x100000 0x600000 // 把闪存存储中从 0x 100000 开始的6M 字节的存储空间清零。
发送命令:SF写0x81000000的0x100000 0x590000 // 把内存中从 0X 8100 开始的 0X 590000 字节的内容复制到闪存中,闪存中存储的起始地址是 0X 100000
设备0偏移量0x100000,大小为0x590000
发送命令:mw.b 0x81000000 0xFF的0x780000 // 把内存中从 0X 8100 开始的0x780000 个字节全部置 1
[EOT](确定)
发送命令:tftp 0x81000000 rootfs.img // 加载rootfs.img 到内存中去,存储单位的起始地址是 0x81000000
海思ETH网络控制器
eth0:PHY状态更改:LINK = UP:DUPLEX = FULL:SPEED = 100M
使用eth0设备
来自服务器192.168.1.3的TFTP; 我们的IP地址是192.168.1.10
文件名“ rootfs.img”。
发送命令:crc32 81000000 772314
crc32为81000000 … 81772313 ==> ba26d341
[EOT](确定)
发送命令:sf probe 0 // 选择spi flash 0
[EOT](确定)
发送命令:sf擦除0x700000 0x800000 // 把闪存存储中从 0x 700000 开始的8M 字节的存储空间清零。
发送命令:SF写0x81000000 0x700000 0x780000 // 把内存中从 0X 8100 开始的0x780000 字节的内容复制到闪存中,闪存中存储的起始地址是0x700000
设备0偏移量0x700000,大小为0x780000
发送命令:mw.b 0x81000000 0xFF 0x10000 // 把内存中从 0x 81000000 开始的0x10000 个字节全部置 1
[EOT](确定)
发送命令:tftp 0x81000000 userfs.img // 加载userfs.img 到内存中去,存储单位的起始地址是 0x81000000
海思ETH网络控制器
eth0:PHY状态更改:LINK = UP:DUPLEX = FULL:SPEED = 100M
使用eth0设备
来自服务器192.168.1.3的TFTP; 我们的IP地址是192.168.1.10
文件名“ userfs.img”。
加载地址:0x81000000
载入中:* ##
0字节/秒
做完了
传输的字节数= 3020(密件抄送十六进制)
[EOT](确定)
发送命令:crc32 81000000 bcc
crc32为81000000 … 81000bcb ==> 0361fc92
[EOT](确定)
发送命令:sf probe 0 / / 选择spi flash 0
[EOT](确定)
发送命令:sf擦除0xf00000 0x100000 // 把闪存存储中从 0x F00000 开始的1M 字节的存储空间清零。
发送命令:sf write 0x81000000 0xf00000 0x10000 // 把内存中从 0x 81000000 开始的0x10000 字节的内容复制到flash 中, flash 中存储的起始地址是0xf00000
设备0偏移量0xf00000,大小为0x10000
以0xf10000进行写入-100%完成。
SF:65536字节@ 0xf00000书面:OK
[EOT](确定)
分区成功烧毁!
发送命令:重置
重置成功!
分区烧毁完成!
串行通道已成功关闭。

 

配置启动参数
烧写完成后会进入uboot模式(有3s倒计时,3s内按回车会主动进入uboot)

Uncompress Ok!

U-Boot 2016.11 (Mar 28 2020 – 09:50:11 +0800)hi3516dv300

Relocation Offset is: 0f6c2000
Relocating to 8fec2000, new gd at 8fe21ef0, sp at 8fe21ed0
SPI Nor: Check Flash Memory Controller v100 … Found
SPI Nor ID Table Version 1.0
SPI Nor(cs 0) ID: 0xc2 0x20 0x19
Block:64KB Chip:32MB Name:”MX25L(256/257)XX”
SPI Nor total size: 32MB
NAND: 0 MiB
MMC:
In: serial
Out: serial
Err: serial
Net: eth0
Warning: eth0 (eth0) using random MAC address – 32:f6:3b:2f:fc:6e

Hit any key to stop autoboot: 0