Rockchip RK3588 - uboot引导方式介绍
----------------------------------------------------------------------------------------------------------------------------
开发板 :NanoPC-T6
开发板
eMMC
:256GB
LPDDR4
:16GB
显示屏 :15.6
英寸HDMI
接口显示屏
u-boot
:2017.09
linux
:6.1
----------------------------------------------------------------------------------------------------------------------------
在介绍完uboot
引导方式后,本节主要介绍recovery.img
镜像的制作,以及如何实现debian/ubuntu
系统的在线升级功能。
一、recovery.img
制作
我们首先需要去下载友善官方提供的固件和源码,具体参考《Rockchip RK3588
- 移植uboot 2017.09
& linux 6.1
(友善之家脚本方式)》前两章。
本节我们将参考Rockchip Linux SDK
尝试自行制作一个recovery.img
系统镜像,并将其烧录到NanoPC-T6
开发板,用来实现该开发板的OTA
升级功能。
recovery.img
系统镜像由kernel + dtb + ramdisk
三部分组成。
我们在/work/sambashare/rk3588
下创建一个recovery
目录,用于制作recovery.img
;
root@ubuntu:/work/sambashare/rk3588$ sudo mkdir recovery
1.1 kernel
1.1.1 支持RAM
块设备
如果我们需要使用ramdisk
根文件系统,就需要配置RAM
块设备驱动,否者不用配置这个。
ram disk
顾名思义,内存磁盘。我们平常接触的一些存储介质,如:Nor Flash
、Nand Flash
、eMMC
、ufs、以及机械硬盘固态硬盘等,都是用来存储数据的,同理内存也是可以当成磁盘来存储数据的,唯一不同的就是ram
是掉电不保存的,而前面提到的那些存储介质掉电都是保存数据的。
我们都知道,在linux
中,上面介绍的Flash
这些存储介质,都是需要有对应的驱动,注册成块设备。并向上层提供接口。如Nor
、Nand
等都抽象成mtdblock
块设备。
同理,linux
中的ram disk
意思就是拿出ram
中的一部分大小,用对应的驱动注册层块设备,提供给上层调用。一般的ram disk
注册成的块设备,在文件系统中设备节点体现为/dev/ramx
。
我们需要配置内核支持ramdisk
:
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# cd kernel-rk3588
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588/kernel-rk3588# sudo make menuconfig
配置:
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
这里的意思是配置内核初始化时,去寻找initramfs
和initrd
,initrd
就是我们的ramdisk
文件系统,至于initramfs
,是一个可以编译进内核的根文件映像。
Device Drivers --->
[*] Block devices --->
<*> RAM block device support
(1) Default number of RAM disks
(131072) Default RAM disk size (kbytes)
勾选第一项RAM block device support
,才会出来第二项和第三项的选项;
- 第一项的意思是内核支持
ram disk
块设备驱动; - 第二项是注册的块设备数量,内核默认是
8
,我这里就写了1
,内核启动后会有/dev/ram0
块设备节点,配置16
则会有/dev/ram0~ram15
; - 第三项的意思是
ram disk
占得最大内存,这里我写的是128M
,一般来说可以写的再小点。实际在使用/dev/ramx
设备时,并不是一下子就占系统128MB
内存,而是根据实际使用情况而分配的。
注意:这里配置的大小要超过我们制作的ramdisk
文件系统的大小。
配置完成,会在.config
生成如下配置:
CONFIG_BLK_DEV_RAM_COUNT=1
CONFIG_BLK_DEV_RAM_SIZE=131072
在./build-kernel.sh
构建内核的时候要想使得该配置生效,我们必须修改./arch/arm64/configs/nanopi6_linux_defconfig
文件中的配置。
这一步我们一定要配置,不然内核挂载ramsidk
文件系统可能出现如下错误:
[ 6.558702] RAMDISK: ext2 filesystem found at block 0
[ 6.558709] RAMDISK: image too big! (74136KiB/4096KiB)
[ 6.559257] /dev/root: Can't open blockdev
[ 6.559266] VFS: Cannot open root device "(null)" or unknown-block(0,0): error -6
[ 6.559271] Please append a correct "root=" boot option; here are the available partitions:
[ 6.559279] 0100 4096 ram0
[ 6.559283] (driver?)
[ 6.559293] 0101 4096 ram1
[ 6.559296] (driver?)
[ 6.559304] 0102 4096 ram2
[ 6.559306] (driver?)
[ 6.559315] 0103 4096 ram3
[ 6.559316] (driver?)
[ 6.559324] 0104 4096 ram4
[ 6.559326] (driver?)
[ 6.559335] 0105 4096 ram5
[ 6.559336] (driver?)
[ 6.559344] 0106 4096 ram6
[ 6.559346] (driver?)
[ 6.559353] 0107 4096 ram7
[ 6.559355] (driver?)
[ 6.559370] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
1.1.2 编译内核
内核编译执行如下命令:
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo KERNEL_SRC=$PWD/kernel-rk3588 ./build-kernel.sh debian-bullseye-desktop-arm64
注意:编译之前需要安装交叉编译工具以及配置build-kernel.sh
脚本,具体参考《Rockchip RK3588
- 移植uboot 2017.09 & linux 6.1
(友善之家脚本方式)》。
1.1.3 Image.gz
编译完成之后,内核镜像我们采用Image
文件即可,位于kernel-rk3588/arch/arm64/boot/
目录;
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ ll kernel-rk3588/arch/arm64/boot/Image
-rw-r--r-- 1 root root 35420168 7月 20 17:51 kernel-rk3588/arch/arm64/boot/Image
Image
是内核镜像原生二进制文件,可以直接在芯片上运行的,由于Image
文件较大,我们将Image
压缩转换为Image.gz
:
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ sudo bash -c 'cat kernel-rk3588/arch/arm64/boot/Image | gzip -n -f -9 > kernel-rk3588/arch/arm64/boot/Image.gz'
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ ll kernel-rk3588/arch/arm64/boot/Image.gz
-rw-r--r-- 1 root root 12742364 7月 20 19:52 kernel-rk3588/arch/arm64/boot/Image.gz
拷贝文件到recovery
目录:
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ sudo cp ./kernel-rk3588/arch/arm64/boot/Image.gz /work/sambashare/rk3588/recovery/
1.2 dtb
NanoPC-T6
开发板默认使用的dtb
为rk3588-nanopi6-rev01.dtb
;
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ ll kernel-rk3588/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dtb
-rw-r--r-- 1 root root 270114 12月 27 2023 kernel-rk3588/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dtb
拷贝文件到recovery
目录:
root@ubuntu:/work/sambashare/rk3588$ sudo cp friendly/sd-fuse_rk3588/kernel-rk3588/arch/arm64/boot/dts/rockchip/rk3588-nanopi6-rev01.dtb ./recovery/
1.3 ramdisk
关于ramdisk
文件系统的制作我们参考《Rockchip RK3399 - busybox 1.36.0
制作根文件系统》,不过在制作过程中有以下几处需要调整。
1.3.1 交叉编译编译工具链
我们在recovery
目录下制作ramdisk
文件系统,需要注意的是交叉编译工具链的选择,这里我们使用《Rockchip RK3588
- 移植uboot 2017.09
& linux 6.1
(友善之家脚本方式)》文章中安装的gcc-10-aarch64-linux-gnu
,即和编译内核使用的交叉编译工具链一致。
root@ubuntu:/work/sambashare/rk3588/recovery$ aarch64-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/aarch64-linux-gnu/10/lto-wrapper
Target: aarch64-linux-gnu
......
Thread model: posix
Supported LTO compression algorithms: zlib zstd
gcc version 10.5.0 (Ubuntu 10.5.0-1ubuntu1~22.04)
以下是我所使用 gcc-aarch64-linux-gnu
和 g++-aarch64-linux-gnu
的默认安装路径:
库文件:
- 标准
C
库文件:/usr/aarch64-linux-gnu/lib
; - 标准
C++
库文件:/usr/aarch64-linux-gnu/lib
; - 其他第三方库文件:
/usr/aarch64-linux-gnu/lib
或/usr/aarch64-linux-gnu/lib/<library_name>
;
头文件:
C
头文件:/usr/aarch64-linux-gnu/include
;C++
头文件:/usr/aarch64-linux-gnu/include/c++/<version>
;
1.3.2 编译安装
首先我们需要下载busybox-1.36.0.tar.bz2
;
root@ubuntu:/work/sambashare/rk3588/recovery/# wget https://busybox.net/downloads/busybox-1.36.0.tar.bz2
tar
root@ubuntu:/work/sambashare/rk3588/recovery/# sudo tar -jxf busybox-1.36.0.tar.bz2
按照《Rockchip RK3399 - busybox 1.36.0
制作根文件系统》制作根文件系统有以下几处需要调整。
1.3.2.1 配置
在make menuconfig
配置时做如下配置参数:
root@ubuntu:/work/sambashare/rk3588/recovery# cd busybox-1.36.0/
root@ubuntu:/work/sambashare/rk3588/recovery/busybox-1.36.0# sudo make defconfig
root@ubuntu:/work/sambashare/rk3588/recovery/busybox-1.36.0# sudo make menuconfig
Settings --->
(aarch64-linux-gnu-) Cross compile prefix
( -march=armv8-a) additional CFLAGS
( ) Path to sysroot # 根路径未指定
[ ] Build static binary (no shared libs)
[*] Build Shared libbusybox
(./_install) Destination path for 'make install'
Networking Utilities --->
[*] Support /etc/networks
[*] udhcpc (24 kb)
[*] Verify that the offered address is free, using ARP ping
[*] Do not pass malformed host and domain names
(/usr/share/udhcpc/default.script) Absolute path to config script
(/usr/share/udhcpc/default6.script) Absolute path to config script for IPv6
1.3.2.2 编译安装
运行命令:
root@ubuntu:/work/sambashare/rk3588/recovery/busybox-1.36.0# sudo make
执行make install
:
root@ubuntu:/work/sambashare/rk3588/recovery/busybox-1.36.0# sudo make install
1.3.3 构建根文件系统
我们首先需要按照《Rockchip RK3399 - busybox 1.36.0
制作根文件系统》文章教程配置:
- 构建
etc
目录; - 修改
/etc/inittab
文件; - 修改
/etc/fstab
文件; - 修改
/etc/profile
文件; - 构建
dev
目录; - 构建其他文件;
除此之外,还需要配置以下内容。
1.3.3.1 库文件
在构建根文件系统拷贝动态库需要执行;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo cp -a /usr/aarch64-linux-gnu/lib/* ./lib/
1.3.3.2 S40network
需要创建/etc/init.d/S40network
文件:
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo vim etc/init.d/S40network
内容如下:
#!/bin/sh
#
# Start the network....
#
# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network
case "$1" in
start)
printf "Starting network: "
/sbin/ifup -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping network: "
/sbin/ifdown -a
[ $? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $?
1.3.2.3 default.script
拷贝文件simple.script
到根文件系统的/usr/share/udhcpc/
目录下,更名为default.script
;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo mkdir -p ./usr/share/udhcpc
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo cp ../busybox-1.36.0/examples/udhcp/simple.script ./usr/share/udhcpc
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo mv ./usr/share/udhcpc/simple.script ./usr/share/udhcpc/default.script
再将default.script
中RESOLV_CONF=”/etc/resolv.conf”
更改为RESOLV_CONF=”/tmp/resolv.conf”
;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo vim ./usr/share/udhcpc/default.script
RESOLV_CONF="/tmp/resolv.conf"
......
我们配置一下网络DHCP
,这样系统启动以后就会自动设置好网络;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo mkdir -p etc/network/interfaces.d
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo vim etc/network/interfaces
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
1.3.2.4 rcS
修改/etc/init.d/rcS
文件;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ sudo vim etc/init.d/rcS
内容如下:
#!/bin/sh
# 挂载 /etc/fstab 中定义的所有文件系统
/bin/mount -a
# 挂载虚拟的devpts文件系统用于用于伪终端设备
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 扫描并创建节点
/sbin/mdev -s
# 加载网卡驱动
/sbin/modprobe r8125
# 配置网络
/sbin/udhcpc
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "$i" ] && continue
case "$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. $i
)
;;
*)
# No sh extension, so fork subprocess.
$i start
;;
esac
done
整个udhcpc
的框架是可执行文件/sbin/udhcpc
、脚本文件/usr/share/udhcpc/default.script
、DNS
配置文件/tmp/resolv.conf
。在rcS
中启动udhcpc
,默认使用default.script
脚本已达到自动配置ip
、route
等。
1.3.4 安装网卡驱动
接着我们需要拷贝debian-bullseye-desktop
系统重网卡相关驱动和固件到busybox
文件系统;
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo mkdir lib
在宿主机执行如下命令:
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo scp -r pi@192.168.0.100:/lib/modules ./lib
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo scp -r pi@192.168.0.100:/lib/firmware ./lib
查看文件:
root@ubuntu:/work/sambashare/rk3588/recovery$ ls lib/modules/6.1.25/
cryptodev.ko modules.builtin.bin modules.softdep rtl8821CU.ko rtw_8723du.ko rtw_8822bs.ko rtw_sdio.ko
kernel modules.builtin.modinfo modules.symbols rtl8822bu.ko rtw_8821ce.ko rtw_8822ce.ko rtw_usb.ko
modules.alias modules.dep modules.symbols.bin rtl8822cs.ko rtw_8821c.ko rtw_8822c.ko
modules.alias.bin modules.dep.bin nft_fullcone.ko rtw_8723de.ko rtw_8821cs.ko rtw_8822cs.ko
modules.builtin modules.devname r8125.ko rtw_8723d.ko rtw_8822be.ko rtw_core.ko
modules.builtin.alias.bin modules.order rtl8812au.ko rtw_8723ds.ko rtw_8822b.ko rtw_pci.ko
zhengyang@ubuntu:/work/sambashare/rk3588/recovery$ ls lib/firmware/
brcm iwlwifi-cc-a0-59.ucode mediatek mt7662_rom_patch.bin regulatory.db.p7s rtl_bt rtw88
intel mali_csffw.bin mt7662.bin regulatory.db rockchip rtl_nic
1.3.5 目录结构
最终构建的根文件系统目录结构如下;
root@ubuntu:/work/sambashare/rk3588/recovery/busybox_install$ ll
drwxr-xr-x 13 root root 4096 7月 21 11:34 ./
drwxr-xr-x 8 root root 4096 7月 21 11:35 ../
drwxr-xr-x 2 root root 4096 7月 21 10:49 bin/
crw-r--r-- 1 root root 5, 1 7月 21 11:34 console
drwxr-xr-x 2 root root 4096 7月 21 11:34 dev/
drwxr-xr-x 3 root root 4096 7月 21 11:34 etc/
drwxr-xr-x 2 root root 4096 7月 21 11:34 lib/
-rwxr-xr-x 1 root root 5936 7月 21 10:26 linuxrc*
drwxr-xr-x 2 root root 4096 7月 21 11:34 mnt/
crw-r--r-- 1 root root 1, 3 7月 21 11:34 null
drwxr-xr-x 2 root root 4096 7月 21 11:34 proc/
drwxr-xr-x 2 root root 4096 7月 21 11:34 root/
drwxr-xr-x 2 root root 4096 7月 21 10:49 sbin/
drwxr-xr-x 2 root root 4096 7月 21 11:34 sys/
drwxr-xr-x 2 root root 4096 7月 21 11:34 tmp/
crw-r--r-- 1 root root 4, 1 7月 21 11:34 tty1
1.3.6 mk-ramdisk.sh
我们将构建根文件系统和ramdisk
镜像的过程,通过mk-ramdisk.sh
脚本实现;
#!/bin/bash
[[ -n DEBUG ]] && set -x
err_handler()
{
# 如果参数1为空,则获取最近一次执行命令的退出状态
ret=${1:-$?}
# 退出状态为0,直接返回
[ "$ret" -eq 0 ] && return
# 入参参数2为空,输出调用栈中的第二个函数名
echo "ERROR: Running $0 - ${2:-${FUNCNAME[1]}} failed!"
# 输出错误状态码,以及发生错误的行号
echo "ERROR: exit code $ret from line ${BASH_LINENO[0]}:"
# 如果参数3为空,输出当前正在执行的命令
echo " ${3:-$BASH_COMMAND}"
echo "ERROR: call stack:"
for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do
SOURCE="${BASH_SOURCE[$i]}"
LINE=${BASH_LINENO[$(( $i - 1 ))]}
echo " $(basename "$SOURCE"): ${FUNCNAME[$i]}($LINE)"
done
exit $ret
}
trap 'err_handler' ERR
set -eE
# 获取当前工作路径
WORK_DIR=$(dirname "$(realpath "$BASH_SOURCE")")
# busybox编译安装目录
BUSYBOX_SOURCR_DIR="$WORK_DIR/busybox-1.36.0"
# 保存busybox根文件系统目录
BUSYBOX_ROOTFS="$WORK_DIR/busybox_install"
# 判断当前目录下是否存在安装目录_install
if [[ ! -d "$BUSYBOX_SOURCR_DIR/_install" ]];then
echo "请先编译安装Busybox"
exit 1
fi
# 删除目录
rm -rf $BUSYBOX_ROOTFS
# 创建目录
echo "开始创建目录${BUSYBOX_ROOTS}"
mkdir $BUSYBOX_ROOTFS
cd $BUSYBOX_ROOTFS
cp -a $BUSYBOX_SOURCR_DIR/_install/* ./
# 找到交叉编译工具里的动态库复制到lib目录下
echo "开始拷贝lib文件"
cp -a /usr/aarch64-linux-gnu/lib/* ./lib
if [[ -d "${WORD_DIR}/lib" ]];then
# 拷贝所有模块,不拷贝固件 =》异常
# 只拷贝网卡模块,不拷贝固件 =》 正常启动
# 只拷贝网卡模块,拷贝固件 =》 异常
mkdir -p ./lib/modules/6.1.25
cp -a $WORK_DIR/lib/modules/6.1.25/*.ko ./lib/modules/6.1.25
# cp -a $WORK_DIR/lib/firmware ./lib
fi
# 1. 构建etc目录
echo "开始创建etc目录"
mkdir etc
mkdir -p etc/init.d/
echo "开始创建/etc/inittab文件"
# 1.1 构建/etc/inittab
cat>etc/inittab<<EOF
# 系统启动时
::sysinit:/etc/init.d/rcS
# 系统启动按下Enter键时
::askfirst:-/bin/sh
# 按下Ctrl+Alt+Del键时
::ctrlaltdel:/sbin/reboot
# 系统关机时
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r
# 系统重启时
::restart:/sbin/init
EOF
chmod 755 etc/inittab
echo "开始创建/etc/init.d/rcS文件"
# 1.2 构建/etc/init.d/rcS
cat>etc/init.d/rcS<<EOF
#!/bin/sh
# 挂载 /etc/fstab 中定义的所有文件系统
/bin/mount -a
# 挂载虚拟的devpts文件系统用于用于伪终端设备
/bin/mkdir -p /dev/pts
/bin/mount -t devpts devpts /dev/pts
# 扫描并创建节点
/sbin/mdev -s
# 加载网卡驱动
/sbin/modprobe r8125
# 配置网络
/sbin/udhcpc
# Start all init scripts in /etc/init.d
# executing them in numerical order.
#
for i in /etc/init.d/S??* ;do
# Ignore dangling symlinks (if any).
[ ! -f "\$i" ] && continue
case "\$i" in
*.sh)
# Source shell script for speed.
(
trap - INT QUIT TSTP
set start
. \$i
)
;;
*)
# No sh extension, so fork subprocess.
\$i start
;;
esac
done
EOF
echo "开始创建/etc/fstab文件"
# 1.3 构建/etc/fstab
cat>etc/fstab<<EOF
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
EOF
echo "开始创建/etc/profile文件"
# 1.4 构建/etc/profile
cat>etc/profile<<EOF
# 主机名
export HOSTNAME=NanoPC-T6
# 用户名
export USER=root
# 用户目录
export HOME=/root
# 终端默认提示符
export PS1="[\$USER@\$HOSTNAME:\\\$PWD]\\# "
# 环境变量
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
# 动态库路径
export LD_LIBRARY_PATH=/lib:/usr/lib:\$LD_LIBRARY_PATH
EOF
echo "开始创建dev目录"
#1.5 构建dev目录
mkdir dev
mknod console c 5 1
mknod null c 1 3
mknod tty1 c 4 1
echo "开始创建/etc/init.d/S40network文件"
#1.6 构建/etc/init.d/S40network
cat>etc/init.d/S40network<<EOF
#!/bin/sh
#
# Start the network....
#
# Debian ifupdown needs the /run/network lock directory
mkdir -p /run/network
case "\$1" in
start)
printf "Starting network: "
/sbin/ifup -a
[ \$? = 0 ] && echo "OK" || echo "FAIL"
;;
stop)
printf "Stopping network: "
/sbin/ifdown -a
[ \$? = 0 ] && echo "OK" || echo "FAIL"
;;
restart|reload)
"\$0" stop
"\$0" start
;;
*)
echo "Usage: \$0 {start|stop|restart}"
exit 1
esac
exit $?
EOF
echo "开始创建/usr/share/udhcpc/default.script文件"
# 1.7 构建/usr/share/udhcpc/default.script
mkdir -p ./usr/share/udhcpc
cp $BUSYBOX_SOURCR_DIR/examples/udhcp/simple.script ./usr/share/udhcpc
mv ./usr/share/udhcpc/simple.script ./usr/share/udhcpc/default.script
sed -i 's/\/etc\/resolv\.conf/\/tmp\/resolv\.conf/g' ./usr/share/udhcpc/default.script
mkdir -p etc/network/interfaces.d
cat>etc/network/interfaces<<EOF
# interface file auto-generated by buildroot
auto lo
iface lo inet loopback
auto eth0
iface eth0 inet dhcp
EOF
# 修改权限
chmod -R 777 etc/init.d/*
# 构建其他文件
mkdir mnt proc tmp sys root
# 构建ramdisk镜像
echo "开始构建ramdisk镜像文件"
cd ..
mkdir busybox_rootfs
dd if=/dev/zero of=busybox_ext4_rootfs.img bs=1M count=300
mkfs.ext4 busybox_ext4_rootfs.img
mount busybox_ext4_rootfs.img busybox_rootfs
cp ${BUSYBOX_ROOTFS}/* ./busybox_rootfs/ -af
umount busybox_rootfs
rm -rf busybox_rootfs
e2fsck -p -f busybox_ext4_rootfs.img
resize2fs -M busybox_ext4_rootfs.img
gzip -v9 busybox_ext4_rootfs.img
mv busybox_ext4_rootfs.img.gz ramdisk.gz
编译安装busybox
之后,执行如下命令;
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo ./mk-ramdisk.sh
1.4 构建recovery.img
1.4.1 boot4recovery.its
由于recovery.img
是FIT uImage
镜像格式,因此我们首先需要创建its
文件。
这里我们直接将Rockchip Linux SDK
中的boot4recovery.its
文件拷贝过来;
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo cp ../armsom/armsom-rk3588-bsp/device/rockchip/.chip/boot4recovery.its .
需要对文件进行适当修改,最终内容如下:
点击查看代码
/*
* Copyright (C) 2021 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: GPL-2.0
*/
/dts-v1/;
/ {
description = "U-Boot FIT source file for arm";
images {
fdt {
description = "Flattened Device Tree blob";
data = /incbin/("@KERNEL_DTB@");
type = "flat_dt";
arch = "arm64";
compression = "none";
load = <0xffffff00>;
hash {
algo = "sha256";
};
};
kernel {
description = "Vanilla Linux kernel";
data = /incbin/("@KERNEL_IMG@");
type = "kernel";
arch = "arm64";
os = "linux";
compression = "gzip";
entry = <0xffffff01>;
load = <0xffffff01>;
hash {
algo = "sha256";
};
};
ramdisk {
description = "Ramdisk for project-x";
data = /incbin/("@RAMDISK_IMG@");
type = "ramdisk";
arch = "arm64";
os = "linux";
compression = "gzip";
load = <0xffffff02>;
hash {
algo = "sha256";
};
};
};
configurations {
default = "conf";
conf {
rollback-index = <0x00>;
description = "Boot Linux kernel with FDT blob";
fdt = "fdt";
kernel = "kernel";
ramdisk = "ramdisk";
signature {
algo = "sha256,rsa2048";
padding = "pss";
key-name-hint = "dev";
sign-images = "fdt", "kernel", "ramdisk";
};
};
};
};
由于在该文件中我们设置的load
、entry
地址满足(addr & 0xffffff00) == 0xffffff00
,因此在its
文件中我们为每个节点指定的load
和entry
都会在boot_fit
启动的时候将其替换成环境变量中指定的地址。其中:
kernel load/entry
地址会被替换成0x00400000
,该值来自环境变量kernel_addr_r
;ramdisk load
地址会被替换成0x0a200000
,该值来自环境变量ramdisk_addr_r
;fdtload
地址会被替换成0x08300000
,该值来自环境变量fdt_addr_r
;
具体可以参考《Rockchip RK3399
- 移植linux 5.2.8
》boot_fit
启动方式介绍。
1.4.2 mk-fitimage.sh
我们需要根据its
文件中的描述来打包镜像生成itb
文件(FIT uImage
)。
这里我们直接将Rockchip Linux SDK
中的mk-fitimage.sh
文件、以及mkimage
工具拷贝过来;
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo cp ../armsom/armsom-rk3588-bsp/device/rockchip/common/scripts/mk-fitimage.sh .
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo cp ../armsom/armsom-rk3588-bsp/rkbin/tools/mkimage ./
需要对mk-fitimage.sh
脚本进行适当修改,最终内容如下:
# FIT uImage镜像:recovery.img
TARGET_IMG="recovery.img"
# its文件: boot4recovery.its
ITS="boot4recovery.its"
# 内核镜像:Image.gz
KERNEL_IMG="Image.gz"
# ramsidk根文件系统:ramdisk.gz
RAMDISK_IMG="ramdisk.gz"
# 内核设备树:rk3588-nanopi6-rev01.dtb
KERNEL_DTB="rk3588-nanopi6-rev01.dtb"
# 判断its文件存在
if [ ! -f "$ITS" ]; then
echo "$ITS not exists!"
exit 1
fi
# 判断ramdisk.gz文件存在
if [ ! -f "$RAMDISK_IMG" ]; then
./mk-ramdisk.sh
fi
# 生成临时文件,复制its到临时文件
TMP_ITS=$(mktemp)
cp "$ITS" "$TMP_ITS"
# 使用sed命令替换一个临时文件$TMP_ITS中的占位符, 比如替换@KERNEL_DTB@->rk3588-nanopi6-rev01.dtb
sed -i -e "s~@KERNEL_DTB@~$(realpath -q "$KERNEL_DTB")~" \
-e "s~@KERNEL_IMG@~$(realpath -q "$KERNEL_IMG")~" \
-e "s~@RAMDISK_IMG@~$(realpath -q "$RAMDISK_IMG")~" "$TMP_ITS"
# 使用mkimage工具编译,这里一定要指定-E参数
mkimage -f "$TMP_ITS" -E -p 0x800 "$TARGET_IMG"
# 删除临时文件
rm -f "$TMP_ITS"
1.4.3 生成resource.img
然后在命令行使用mk-fitimage.sh
脚本编译即可:
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo ./mk-fitimage.sh
FIT description: U-Boot FIT source file for arm
Created: Sat Jul 20 22:40:55 2024
Image 0 (fdt)
Description: Flattened Device Tree blob
Created: Sat Jul 20 22:40:55 2024
Type: Flat Device Tree
Compression: uncompressed
Data Size: 270114 Bytes = 263.78 KiB = 0.26 MiB
Architecture: AArch64
Load Address: 0xffffff00
Hash algo: sha256
Hash value: cd297b6895d00b4626dcd74ad9a66b4c90173077585dc7a0c63034921e5ecb8a
Image 1 (kernel)
Description: Vanilla Linux kernel
Created: Sat Jul 20 22:40:55 2024
Type: Kernel Image
Compression: gzip compressed
Data Size: 12742364 Bytes = 12443.71 KiB = 12.15 MiB
Architecture: AArch64
OS: Linux
Load Address: 0xffffff01
Entry Point: 0xffffff01
Hash algo: sha256
Hash value: 7b70ba6cae5487c135c24b66122cb63002ea1d12166bd99e456d3ff43061c8a2
Image 2 (ramdisk)
Description: Ramdisk for project-x
Created: Sat Jul 20 22:40:55 2024
Type: RAMDisk Image
Compression: gzip compressed
Data Size: 49162664 Bytes = 48010.41 KiB = 46.89 MiB
Architecture: AArch64
OS: Linux
Load Address: 0xffffff02
Entry Point: unavailable
Hash algo: sha256
Hash value: da66e02be8015a035d9a36ed649e13143fab0e02699e6be332ca540886e6feed
Default Configuration: 'conf'
Configuration 0 (conf)
Description: Boot Linux kernel with FDT blob
Kernel: kernel
Init Ramdisk: ramdisk
FDT: fdt
Sign algo: sha256,rsa2048:dev
Sign padding: pss
Sign value: unavailable
Timestamp: unavailable
编译完成后我们查看recovery.img
镜像大小:
root@ubuntu:/work/sambashare/rk3588/recovery$ ll
-rw-r--r-- 1 root root 1589 7月 18 20:41 boot4recovery.its
drwxr-xr-x 38 root root 4096 7月 20 21:43 busybox-1.36.0/
drwxr-xr-x 13 root root 4096 7月 18 00:45 busybox_install/
-rw-r--r-- 1 root root 12742364 7月 20 19:54 Image.gz
-rwxr-xr-x 1 root root 957 7月 18 20:37 mk-fitimage.sh*
-rwxr-xr-x 1 root root 206888 7月 18 19:34 mkimage*
-rwxr-xr-x 1 root root 408 7月 20 22:38 mk-ramdisk.sh*
-rw-r--r-- 1 root root 49162664 7月 20 22:39 ramdisk.gz
-rw-r--r-- 1 root root 62177192 7月 20 22:40 recovery.img
-rw-r--r-- 1 root root 270114 7月 17 23:42 rk3588-nanopi6-rev01.dtb
1.5 烧录recovery.img
1.5.1 系统分区调整
由于编译的recovery.img
的大小为62MB
,而官方默认的parameter
中配置的recovery
分区大小为32MB
,空间不够,因此我们需要修改parameter.txt
;
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588/debian-bullseye-desktop-arm64$ sudo vim parameter.txt
内容如下:
FIRMWARE_VER: 12.0
MACHINE_MODEL: RK3588
MACHINE_ID: 007
MANUFACTURER: RK3588
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: NanoPi6
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00002000@0x00008000(dtbo),0x00008000@0x0000a000(resource),0x00014000@0x00012000(kernel),0x00010000@0x00026000(boot),0x00040000@0x00036000(recovery),0x007c0000@0x00076000(rootfs),-@0x00836000(userdata:grow)
解析信息如下:
Number | Name | 镜像文件 | Start (sector) | End (sector) | Size |
---|---|---|---|---|---|
1 | uboot | uboot.img | 0x4000(16384) | 0x5FFF | 4M |
2 | misc | misc.img | 0x6000(24576) | 0x7FFF | 4M |
3 | dtbo | dtbo.img | 0x8000(32768) | 0x9FFF | 4M |
4 | resource | resource.img | 0xa000(40960) | 0x11FFF | 16MB |
5 | kernel | kernel.img | 0x12000(73728) | 0x25FFF | 40MB |
6 | boot | boot.img | 0x26000(155648) | 0x35FFF | 32MB |
7 | recovery | recovery.img | 0x36000(221184) | 0x75FFF | 128MB |
8 | rootfs | rootfs.img | 0x76000(483328) | 0x835FFF | 3.968GB |
9 | userdata | userdata.img | 0x836000(8609792) | - |
1.5.2 生成统一固件
将recovery.img
拷贝到debian-bullseye-desktop-arm64/
目录;
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588$ sudo cp /work/sambashare/rk3588/recovery/recovery.img ./debian-bullseye-desktop-arm64
将debian-bullseye-desktop-arm64
目录下的镜像文件重新打包成SD
卡固件:
root@@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo ./mk-sd-image.sh debian-bullseye-desktop-arm64/
1.5.3 制作SD
启动卡
我们将SD
卡插入PC
上,SD
卡对应的设备节点为/dev/sdb
,开始制作SD
启动卡:
root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# sudo dd if=out/out/rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240720.img of=/dev/sdb bs=4M status=progress
烧录完成,将SD
卡插入开发板,启动系统,查看分区信息;
pi@NanoPC-T6:/userdata$ sudo fdisk -l /dev/mmcblk0
Disk /dev/mmcblk0: 29.72 GiB, 31914983424 bytes, 62333952 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 73987B6B-4974-4C94-A3E8-58AB2EB7A946
Device Start End Sectors Size Type
/dev/mmcblk0p1 16384 24575 8192 4M unknown # uboot uboot.img
/dev/mmcblk0p2 24576 32767 8192 4M unknown # misc misc.img
/dev/mmcblk0p3 32768 40959 8192 4M unknown # dtbo dtbo.img
/dev/mmcblk0p4 40960 73727 32768 16M unknown # resource resource.img
/dev/mmcblk0p5 73728 155647 81920 40M unknown # kernel kernel.img
/dev/mmcblk0p6 155648 221183 65536 32M unknown # boot boot.img
/dev/mmcblk0p7 221184 483327 262144 128M unknown # recovery recovery.img
/dev/mmcblk0p8 483328 8609791 8126464 3.9G unknown # rootfs rootfs.img
/dev/mmcblk0p9 8609792 62333918 53724127 25.6G unknown # userdata userdata.img
1.5.4 单独烧录recovery.img
如果我们有单独烧录recovery.img
到开发板recovery
分区的诉求,可以按照如下步骤;
pi@NanoPC-T6:/userdata$ sudo scp -r root@192.168.0.200:/work/sambashare/rk3588/recovery/recovery.img .
pi@NanoPC-T6:/userdata$ sudo dd if=recovery.img of=/dev/mmcblk0p7 bs=1M
二、update_engine
/recovery
编译
我们要实现recovery
模式下系统的升级功能,有两种升级方案可以选择,在《Rockchip RK3588 - Rockchip Linux Recovery updateEngine
源码分析》已经进行了深入介绍。
这里我们采用updateEngine
升级方案,源码位于<Rockchip Linux SDK>/external/recovery
目录下,源码有两部分组成:
external/recovery/update_engine
:生成updateEngine
二进制bin
程序,解析update.img
固件中各个分区数据,并执行对各分区升级的关键程序;external/recovery
:生成recovery
二进制bin
程序,其中recovery
二进制bin
程序部会根据编译配置调用updateEngine
或者rkupdate
进行升级。
接下来我们需要介绍源码编译,源码编译有两种方式:
- 交叉编译:即在
ubuntu
宿主机编译,该方式编译我们需要获取第三方库的交叉编译版本; - 直接将源码拷贝到开发板
debian-bullseye-desktop
系统,进行编译运行;
这里我们选择第二种方式,我们直接将Rockchip Linux SDK
中的external/recovery
源码拷贝到开发板opt
目录;
pi@NanoPC-T6:/opt$ sudo scp -r root@192.168.0.200:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/external/recovery ./
2.1 recovery
2.2 updateEngine
2.2.1 源码修改
创建文件recovery_autogenerate.h
;
pi@NanoPC-T6:/opt$ cd recovery
pi@NanoPC-T6:/opt$ sudo vim recovery_autogenerate.h
#define GIT_COMMIT_INFO -g28f720bc5-240524-dirty
修改Makefile
:
%.o: %.c recovery_version
$(CC) -c $< -o $@ $(CFLAGS)
# 修改为
%.o: %.c # recovery_version
$(CC) -c $< -o $@ $(CFLAGS)
2.2.2 源码编译
在开发板执行如下代码;
pi@NanoPC-T6:/opt/recovery$ sudo apt-get update
pi@NanoPC-T6:/opt/recovery$ sudo apt install make gcc libcurl4-openssl-dev libssl-dev libbz2-dev
pi@NanoPC-T6:/opt/recovery$ sudo make updateEngine CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -I. -fPIC -lpthread -lcurl -lssl -lcrypto -lbz2 -DUSE_UPDATEENGINE=ON -DSUCCESSFUL_BOOT=ON"
编译完成后查看可执行文件:
pi@NanoPC-T6:/opt/recovery$ ls -l updateEngine
-rwxr-xr-x 1 root root 91920 Jul 18 14:51 updateEngine
pi@NanoPC-T6:/opt/recovery$ ./updateEngine --h
LOG_INFO: *** update_engine: V1.0.1-g28f720bc5-240524-dirty ***.
LOG_INFO: --misc=now Linux A/B mode: Setting the current partition to bootable.
LOG_INFO: --misc=other Linux A/B mode: Setting another partition to bootable.
LOG_INFO: --misc=update Recovery mode: Setting the partition to be upgraded.
LOG_INFO: --misc=display Display misc info.
LOG_INFO: --misc=wipe_userdata Format data partition.
LOG_INFO: --misc_custom= < op > Operation on misc for custom cmdlineLOG_INFO: op: read Read custom cmdline to /tmp/custom_cmdlineLOG_INFO: write Write /tmp/custom_cmdline to custom areaLOG_INFO: clean clean custom areaLOG_INFO: --update Upgrade mode.
LOG_INFO: --partition=0x3FFC00 Set the partition to be upgraded.(NOTICE: OTA not support upgrade loader and parameter)
LOG_INFO: 0x3FFC00: 0011 1111 1111 1100 0000 0000.
LOG_INFO: uboot trust boot recovery rootfs oem
LOG_INFO: uboot_a uboot_b boot_a boot_b system_a system_b.
LOG_INFO: 100000000000000000000000: Upgrade loader
LOG_INFO: 010000000000000000000000: Upgrade parameter
LOG_INFO: 001000000000000000000000: Upgrade uboot
LOG_INFO: 000100000000000000000000: Upgrade trust
LOG_INFO: 000010000000000000000000: Upgrade boot
LOG_INFO: 000001000000000000000000: Upgrade recovery
LOG_INFO: 000000100000000000000000: Upgrade rootfs
LOG_INFO: 000000010000000000000000: Upgrade oem
LOG_INFO: 000000001000000000000000: Upgrade uboot_a
LOG_INFO: 000000000100000000000000: Upgrade uboot_b
LOG_INFO: 000000000010000000000000: Upgrade boot_a
LOG_INFO: 000000000001000000000000: Upgrade boot_b
LOG_INFO: 000000000000100000000000: Upgrade system_a
LOG_INFO: 000000000000010000000000: Upgrade system_b
LOG_INFO: 000000000000001000000000: Upgrade misc
LOG_INFO: 000000000000000100000000: Upgrade userdata
LOG_INFO: --reboot Restart the machine at the end of the program.
LOG_INFO: --version_url=url The path to the file of version.
LOG_INFO: --image_url=url Path to upgrade firmware.
LOG_INFO: --savepath=url save the update.img to url.
LOG_INFO: --version the version of updateEngine
LOG_INFO: --rkdebug Log output to serial port
LOG_INFO: --ui_rotation UI rotation,has 4 angles(0-3).
将可执行文件复制到/usr/bin
目录;
pi@NanoPC-T6:/opt/recovery$ sudo mv updateEngine /usr/bin/
2.3 ramdisk.img
移植updateEngine
由于编译updateEngine
需要一些依赖头文件和和库,为此不得不下载安装libcurl
、libbz2
库。
我们在《Rockchip RK3588 - Rockchip Linux Recovery updateEngine
测试》进行recovery
编译时候,实际上下载了这些源码,并进行了编译。recovery
编译完成后,在编译输出目录 output/rockchip_rk3588_recovery
会生成子目录,说明如下:
build
: 除了交叉编译的工具链之外的所有组件,包括Buildroot
所需主机工具和选择的软件包,这个目录包含所有软件包源码;host
:包含为主机编译的工具的安装,这些工具是正确执行Buildroot
所必需的,包括交叉编译工具
链;images
:所有镜像(文件系统,比如ext2/4
、squashfs
、cpio
等格式镜像)存储目录;staging
:其中的层次结构类似于根文件系统层次结构。这个目录包含了安装交叉编译工具链和为目标选择的所有用户空间包,但是,这个目录不是用来成为目标的根文件系统:它包含许多开发文件、未剥离的二进制文件和库,这些文件和库也非常多,对嵌入式系统来说是很大的;这些开发文件用于为所依赖的目标提供编译库和应用程序需要的其他库;target
: 几乎包含了目标的完整根文件系统:除了/dev/
目录中的设备文件,所有需要的东西都是存在(Buildroot
不能创建它们,因为Buildroot
不会以root
身份运行,也不希望以root
身份运行)。此外,它没有正确的权限(例如,busybox
二进制文件的setuid
),因此,该目录不应该用于你的目标;相反,您应该使用images/
目录中构建的映像之一;如果你需要在根文件系统中用NFS
挂载外部镜像,必须用root
用户在images/
目录中生成镜像,相比对于staging/
,target/
只包含运行所选目标应用程序所需的文件和库:开发文件(头文件)不存在,二进制文件被剥离。
在staging
目录下可以找到这些源码的头文件以及编译后的库文件,以libcurl
为例;
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/staging$ ls
bin dev etc lib lib64 media mnt opt proc root run sbin sys tmp usr var
bsp/buildroot/output/rockchip_rk3588_recovery/staging$ ll usr/include/ | grep curl.h
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/staging$ ll usr/lib* | grep libcurl.so
lrwxrwxrwx 1 root root 16 6月 18 01:47 libcurl.so -> libcurl.so.4.7.0*
lrwxrwxrwx 1 root root 16 6月 18 01:47 libcurl.so.4 -> libcurl.so.4.7.0*
-rwxr-xr-x 1 root root 557120 6月 18 01:47 libcurl.so.4.7.0*
三、 OTA
升级测试
在前面章节我们已经已经做了如下准备工作:
- 制作了
SD
启动卡,烧录了rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img
; - 向
SD
中debian-bullseye-desktop
系统recovery
分区烧录了我们制作的recovery.img
镜像文件; - 编译了
/opt/recovery
源码生成了updateEngine
可执行文件。
接下来我们就通过updateEngine
工具来升级固件,既然是固件升级,那我们首先要制作升级的固件。
注意:这里我们升级测试,升级的也是SD
中的固件。
3.1 制作升级固件update.img
友善提供的系统固件主要分为三大类:
SD
卡固件:可以烧录到SDK
运行的固件,比如我们开篇制作的SD
启动卡烧录的就是这种固件(rk3588-sd-debian-bullseye-desktop-6.1-arm64-20240714.img
);SD
卡刷机固件:烧录到SD
卡,SD
卡启动后会将固件烧录到eMMC
;比如友善提供的固件压缩包rk3588-eflasher-debian-bullseye-desktop-6.1-arm64-20231116.img.gz
,解压后就可以得到这种固件镜像;USB
线刷固件:以友善提供的固件压缩包rk3588-usb-debian-bullseye-desktop-6.1-arm64-20231116.zip
为例,解压后可以看到里面就是各个分区镜像以及RKDevTool.exe
烧录工具;
然而上面的几种固件格式均不是updateEngine
可执行文件能够识别的固件格式,接下来我们需要使用这些分区镜像来制作updateEngine
可执行文件能够识别的固件。
关于固件的制作步骤我们是通过《Rockchip RK3588 - Rockchip Linux SDK
脚本分析》中对90-updateimg.sh
分析得来的,具体步骤如下。
3.1.1 准备分区镜像
在/work/sambashare/rk3588/recovery
目录下创建update
文件夹;
root@ubuntu:/work/sambashare/rk3588/recovery$ sudo mkdir update
接着我们将友善提供的分区镜像文件压缩包上传到宿主机,比如这里我上传了03_分区镜像文件/ubuntu-jammy-x11-desktop-arm64-images.tgz
,解压到Image
文件夹;
root@ubuntu:/work/sambashare/rk3588/recovery/update$ tar -zxf ubuntu-jammy-x11-desktop-arm64-images.tgz -C . --strip-components=1
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo rm -rf ubuntu-jammy-x11-desktop-arm64-images.tgz info.conf
root@ubuntu:/work/sambashare/rk3588/recovery/update$ ll
-rw-r--r-- 1 root root 8072140 5月 28 2023 boot.img
-rw-r--r-- 1 root root 1424 5月 28 2023 dtbo.img
-rw-r--r-- 1 root root 307200 9月 8 2023 idbloader.img
-rw-r--r-- 1 root root 71 11月 17 2023 info.conf
-rw-r--r-- 1 root root 35551252 11月 16 2023 kernel.img
-rw-r--r-- 1 root root 471488 9月 8 2023 MiniLoaderAll.bin
-rw-r--r-- 1 root root 49152 5月 28 2023 misc.img
-rw-r--r-- 1 root root 470 11月 17 2023 parameter.txt
-rw-r--r-- 1 root root 6227456 11月 16 2023 resource.img
-rw-r--r-- 1 root root 5933630704 11月 17 2023 rootfs.img
-rw-r--r-- 1 root root 4194304 9月 8 2023 uboot.img
-rw-r--r-- 1 root root 159868 11月 17 2023 userdata.img
同样我们需要修改 parameter.txt
为:
FIRMWARE_VER: 12.0
MACHINE_MODEL: RK3588
MACHINE_ID: 007
MANUFACTURER: RK3588
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: NanoPi6
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00002000@0x00008000(dtbo),0x00008000@0x0000a000(resource),0x00014000@0x00012000(kernel),0x00010000@0x00026000(boot),0x00040000@0x00036000(recovery),0x00b60000@0x00076000(rootfs),-@0x00bd6000(userdata:grow)
此外,我们需要将我们前面制作的recovery.img
拷贝到该目录;
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo cp ../recovery.img .
如果我们更改了uboot
、kernel
、resource
等分区镜像,只需要替换该目录下的分区镜像文件即可。
3.1.2 准备package-file
在/work/sambashare/rk3588/recovery/update
目录下创建package-file
,内容如下;
# NAME PATH
package-file package-file
parameter parameter.txt
bootloader MiniLoaderAll.bin
uboot uboot.img
misc misc.img
dtbo dtbo.img
resource resource.img
kernel kernel.img
boot boot.img
recovery recovery.img
rootfs rootfs.img
userdata userdata.img
升级固件不一定要全分区升级,可修改 package-file
文件,将不要升级的分区去掉,这样可以减少升级包的大小。比如将 rootfs
的相对路径改为 RESERVED
,这样就不会打包根文件系统,即不升级根文件系统分区。
3.1.3 准备打包工具
这里我们直接将Rockchip Linux SDK
中的afptool
、rkImageMaker
工具拷贝过来;
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo cp ../../armsom/armsom-rk3588-bsp/tools/linux/Linux_Pack_Firmware/rockdev/afptool ./
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo cp ../../armsom/armsom-rk3588-bsp/tools/linux/Linux_Pack_Firmware/rockdev/rkImageMaker ./
3.1.4 打包
执行afptool
命令开始打包生成update.raw.img
:
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo ./afptool -pack . update.raw.img
Android Firmware Package Tool v2.2
------ PACKAGE ------
Add file: ./package-file
package-file,Add file: ./package-file done,offset=0x800,size=0x15c,userspace=0x1
Add file: ./parameter.txt
parameter,Add file: ./parameter.txt done,offset=0x1000,size=0x1e2,userspace=0x1,flash_address=0x00000000
Add file: ./MiniLoaderAll.bin
bootloader,Add file: ./MiniLoaderAll.bin done,offset=0x1800,size=0x731c0,userspace=0xe7
Add file: ./uboot.img
uboot,Add file: ./uboot.img done,offset=0x75000,size=0x400000,userspace=0x800,flash_address=0x00004000
Add file: ./misc.img
misc,Add file: ./misc.img done,offset=0x475000,size=0xc000,userspace=0x18,flash_address=0x00006000
Add file: ./dtbo.img
dtbo,Add file: ./dtbo.img done,offset=0x481000,size=0x590,userspace=0x1,flash_address=0x00008000
Add file: ./resource.img
resource,Add file: ./resource.img done,offset=0x481800,size=0x5c6a00,userspace=0xb8e,flash_address=0x0000a000
Add file: ./kernel.img
kernel,Add file: ./kernel.img done,offset=0xa48800,size=0x21c7814,userspace=0x4390,flash_address=0x00012000
Add file: ./boot.img
boot,Add file: ./boot.img done,offset=0x2c10800,size=0x7b2bcc,userspace=0xf66,flash_address=0x00026000
Add file: ./recovery.img
recovery,Add file: ./recovery.img done,offset=0x33c3800,size=0x3b4bfa8,userspace=0x7698,flash_address=0x00036000
Add file: ./rootfs.img
rootfs,Add file: ./rootfs.img done,offset=0x6f0f800,size=0x161ac04f0,userspace=0x2c3581,flash_address=0x00076000
Add file: ./userdata.img
userdata,Add file: ./userdata.img done,offset=0x1689d0000,size=0x2707c,userspace=0x4f,flash_address=0x00bd6000
Add CRC...
Make firmware OK!
------ OK ------
执行rkImageMaker
命令开始打包生成update.img
:
root@ubuntu:/work/sambashare/rk3588/recovery/update$ sudo ./rkImageMaker -RK3588 MiniLoaderAll.bin update.raw.img update.img -os_type:androidos
********rkImageMaker ver 2.23********
Generating new image, please wait...
Writing head info...
Writing boot file...
Writing firmware...
Generating MD5 data...
MD5 data generated successfully!
New image generated successfully!
查看生成的固件:
rot@ubuntu:/work/sambashare/rk3588/recovery/update$ ll update.*
-rw-r--r-- 1 root root 6050720330 7月 20 23:09 update.img
-rw-r--r-- 1 root root 6050248708 7月 20 23:08 update.raw.img
3.2 修改根设备节点别名
与《Rockchip RK3588 - Rockchip Linux Recovery updateEngine
测试》中介绍的buildroot
系统升级一样,updateEngine
升级方案也支持debian
或ubuntu
系统下的升级。
由于updateEngine
升级需要通过设备各个分区节点来识别并写入不同设备分区节点的固件数据,buildroot
系统是通过udev
中的别名方式(by-name
)来对设备分区节点做了通用的易识别的处理。
debian
或ubuntu
系统中因为缺少这样的方式,导致了实际中updateEngine
不能正常运行的情况,所以只需要将debian
或ubuntu
系统中设备分区的节点也跟buildroot
系统下可通过by-name
别名方式标识出来,updateEngine
即可正常工作。
3.2.1 61-partition-init.rules
具体修改方式如下:
pi@NanoPC-T6:/opt$ sudo vim /lib/udev/rules.d/61-partition-init.rules
# rockchip internal storage links: /dev/block/by-name
ACTION=="remove", GOTO="rk_internal_storage_end"
ENV{UDEV_DISABLE_ROCKCHIP_STORAGE_RULES_FLAG}=="1", GOTO="rk_internal_storage_end"
SUBSYSTEM!="block", GOTO="rk_internal_storage_end"
KERNEL!="mmcblk*[0-9]|rkflash*|rknand*|mtdblock*", GOTO="rk_internal_storage_end"
# ignore partitions that span the entire disk
TEST=="whole_disk", GOTO="rk_internal_storage_end"
# for partitions import parent information
ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
# for rknand parameter partition name
ENV{DEVNAME}=="/dev/rknand*", ENV{DEVTYPE}=="disk", ENV{DEVPATH}=="/devices/virtual/block/rknand", ENV{ID_RKNAND_PART_NAME}=""
# for rkflash gpt partition name /dev/block/by-name link
ENV{DEVTYPE}=="partition", ENV{PARTNAME}=="?*", SYMLINK+="block/by-name/$env{PARTNAME}"
# for emmc gpt partition name /dev/block/by-name link
ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="block/by-name/$env{ID_PART_ENTRY_NAME}"
# for mtd partition name /dev/block/by-name link
ENV{DEVNAME}=="/dev/mtdblock*", ENV{DEVTYPE}=="disk", SYMLINK+="block/by-name/$attr{device/name}"
LABEL="rk_internal_storage_end"
修改的目的就是开机启动后可以将debian
系统或ubuntu
系统中各个分区节点形如/dev/mmcblk0p1
、/dev/mmcblk0p2
、/dev/mmcblk0p3
、/dev/mmcblk0p4
... 修改为/dev/block/byname/uboot
、/dev/block/by-name/misc
、/dev/block/by-name/dtbo
、/dev/block/byname/ resource
...等。
3.2.2 /dev/block
重启系统,查看/dev/block
:
pi@NanoPC-T6:~$ ls /dev/block/
179:0 179:100 179:103 179:11 179:14 179:2 179:4 179:64 179:9 179:98 1:1 1:4 1:7 7:2 7:5 by-name
179:1 179:101 179:104 179:12 179:15 179:3 179:5 179:7 179:96 179:99 1:2 1:5 7:0 7:3 7:6
179:10 179:102 179:105 179:13 179:16 179:32 179:6 179:8 179:97 1:0 1:3 1:6 7:1 7:4 7:7
pi@NanoPC-T6:~$ ls /dev/block/by-name/ -l
lrwxrwxrwx 1 root root 15 Jul 18 15:55 uboot -> ../../mmcblk0p1
lrwxrwxrwx 1 root root 15 Jul 18 15:55 misc -> ../../mmcblk0p2
lrwxrwxrwx 1 root root 15 Jul 18 15:55 dtbo -> ../../mmcblk0p3
lrwxrwxrwx 1 root root 15 Jul 18 15:55 resource -> ../../mmcblk0p4
lrwxrwxrwx 1 root root 15 Jul 18 15:55 kernel -> ../../mmcblk0p5
lrwxrwxrwx 1 root root 15 Jul 18 15:55 boot -> ../../mmcblk0p6
lrwxrwxrwx 1 root root 15 Jul 18 15:55 recovery -> ../../mmcblk0p7
lrwxrwxrwx 1 root root 15 Jul 18 15:55 rootfs -> ../../mmcblk0p8
lrwxrwxrwx 1 root root 15 Jul 18 15:55 userdata -> ../../mmcblk0p9
lrwxrwxrwx 1 root root 15 Jul 18 15:55 security -> ../../mmcblk2p1
lrwxrwxrwx 1 root root 15 Jul 18 15:55 uboot_a -> ../../mmcblk2p2
lrwxrwxrwx 1 root root 15 Jul 18 15:55 uboot_b -> ../../mmcblk2p3
lrwxrwxrwx 1 root root 15 Jul 18 15:55 dtbo_a -> ../../mmcblk2p5
lrwxrwxrwx 1 root root 15 Jul 18 15:55 dtbo_b -> ../../mmcblk2p6
lrwxrwxrwx 1 root root 15 Jul 18 15:55 vbmeta_a -> ../../mmcblk2p7
lrwxrwxrwx 1 root root 15 Jul 18 15:55 vbmeta_b -> ../../mmcblk2p8
lrwxrwxrwx 1 root root 15 Jul 18 15:55 boot_a -> ../../mmcblk2p9
lrwxrwxrwx 1 root root 16 Jul 18 15:55 boot_b -> ../../mmcblk2p10
lrwxrwxrwx 1 root root 16 Jul 18 15:55 backup -> ../../mmcblk2p11
lrwxrwxrwx 1 root root 16 Jul 18 15:55 cache -> ../../mmcblk2p12
lrwxrwxrwx 1 root root 16 Jul 18 15:55 metadata -> ../../mmcblk2p13
lrwxrwxrwx 1 root root 16 Jul 18 15:55 baseparameter -> ../../mmcblk2p14
lrwxrwxrwx 1 root root 16 Jul 18 15:55 super -> ../../mmcblk2p15
其中:
mmcblk0
为SD
卡烧录的就是我们制作的SD
卡固件,系统为debian-bullseye-desktop
;mmcblk2
为eMMC
,烧录的是SD
卡刷机固件,系统为android12
。
若还是出现如下类似设备节点:
root@linaro-alip:~# ls /dev/block/
179:0 179:3 179:5 179:7 179:96 7:0 7:3 7:6
179:1 179:32 179:6 179:8 1:0 7:1 7:4 7:7
179:2 179:4 179:64 179:9 254:0 7:2 7:5
可尝试将61-partition-init.rules
放在debian
或ubuntu /etc/udev/rules.d
或/lib/udev/rules.d/
。
3.3 网络升级测试
3.3.1 升级测试
我们可以在ubunut
开启http
服务,搭建一个web
服务;
root@ubuntu:/work/sambashare/rk3588/recovery/update# python3 -m http.server 8080
然后执行updateEngine
网络升级命令;
pi@NanoPC-T6:/opt$ sudo updateEngine --image_url=http://192.168.0.200:8080/update.img --misc=update --partition=0x60000 --savepath=/userdata/update.img --reboot
这里我们仅仅升级了recovery
以及rootfs
分区。如需更新其它分区,可以修改--partition
参数:
- 如果没有传入要升级的分区,默认升级
uboot/trust/boot/recovery/rootfs/oem
,partition=0x3F0000
;也就是升级我们制作的固件中的uboot、boot、recovery、rootfs、oem
这5个分区(升级固件没有trust
分区); - 如果指定了
parameter
和misc
:parameter
、misc
分区会自动忽略; - 如果升级
uboot
分区,指定partition=0x200000
;烧录升级固件中的分区镜像uboot.img
; - 如果升级
trust
分区,指定partition=0x100000
;升级固件中没有该分区镜像,跳过; - 如果升级
boot
分区,指定partition=0x80000
;烧录升级固件中的分区镜像boot.img
; - 如果升级
recovery
分区,指定partition=0x40000
;烧录升级固件中的分区镜像recovery.img
; - 如果升级
rootfs
分区,指定partition=0x20000
;烧录升级固件中的分区镜像rootfs.img
; - 如果升级
oem
分区,指定partition=0x10000
;升级固件中没有该分区镜像,跳过; - 如果升级
userdata
分区,指定partition=0x100
;烧录升级固件中的分区镜像userdata.img
; - 如果需要升级多个的分区,需要将上面的值进行或运算得到新的
partition
值。
此外,我们制作的升级固件update.img
还包含了dtbo
、resource
、kernel
分区镜像,如需对这些分区进行升级需要参考《update_engine
/recovery
编译》支持自定义分区升级小节。
在升级指定升级分区时一定要指定recovery
分区,这样才会进入recovery
系统烧录除了recovery
之外的分区;
- 如果没有指定
recovery
分区,那么将会在normal
系统进行烧录,存在诸多风险,比如:升级中断导致normal
系统无法正常启动; - 而在
recovery
系统进行升级能保证升级的完整性,即升级过程被中断,如异常掉电,升级仍然能继续执行;
注意:除此之外,我们还需要注意一点,不可以升级升级固件update.img
存放的分区,因为这样存在覆盖的问题。比如我们如果将升级固件放在/userdata
目录,就不要升级userdata
分区。
3.3.2 normal
系统下升级日志
首先在normal
系统下升级recovery
分区,输出日志如下;
点击查看代码
LOG_INFO: *** update_engine: V1.0.1-g28f720bc5-240524-dirty ***.
LOG_INFO: Current Mode is recovery.
LOG_INFO: start RK_ota_url url [http://192.168.0.200:8080/update.img] save path [/userdata/update.img].
LOG_INFO: save image to /userdata/update.img.
LOG_INFO: url = http://192.168.0.200:8080/update.img.
LOG_INFO: [MiscUpdate:90] save path: /userdata/update.img
LOG_INFO: update recovery in normal system.
LOG_INFO: [RK_ota_set_partition:106] num [16]
LOG_INFO: need update parameter.
LOG_INFO: need update recovery.
LOG_INFO: Now is SD.
LOG_INFO: no found mtd.
LOG_INFO: start RK_ota_start.
LOG_INFO: rk m_status = 1.
LOG_INFO: down_processvalue is 0%
LOG_INFO: down_processvalue is 1%
LOG_INFO: down_processvalue is 2%
......
LOG_INFO: down_processvalue is 100%
LOG_INFO: [RK_ota_set_partition:106] num [16]
LOG_DEBUG: uiTag = 57464b52.
LOG_DEBUG: usSize = 66.
LOG_DEBUG: dwVersion = c000000.
LOG_DEBUG: btMajor = c, btMinor = 0, usSmall = 00.
LOG_DEBUG: dwBootOffset = 66.
LOG_DEBUG: dwBootSize = 731c0.
LOG_DEBUG: dwFWOffset = 73226.
LOG_DEBUG: dwFWSize = 689f7804.
LOG_DEBUG: tag = 1178684242
LOG_DEBUG: size = 1755281408
LOG_DEBUG: machine_model = RK3588
LOG_DEBUG: manufacturer = RK3588
LOG_DEBUG: version = 201326592
LOG_DEBUG: item = 12.
LOG_INFO: ================================================
LOG_DEBUG: name = package-file
LOG_DEBUG: file = package-file
LOG_DEBUG: offset = 473638
LOG_DEBUG: flash_offset = -1
LOG_DEBUG: usespace = 1
LOG_DEBUG: size = 348
LOG_INFO: ================================================
LOG_DEBUG: name = parameter
LOG_DEBUG: file = parameter.txt
LOG_DEBUG: offset = 475686
LOG_DEBUG: flash_offset = 0
LOG_DEBUG: usespace = 1
LOG_DEBUG: size = 482
LOG_INFO: ================================================
LOG_DEBUG: name = bootloader
LOG_DEBUG: file = MiniLoaderAll.bin
LOG_DEBUG: offset = 102
LOG_DEBUG: flash_offset = -1
LOG_DEBUG: usespace = 231
LOG_DEBUG: size = 471488
LOG_INFO: ================================================
LOG_DEBUG: name = uboot
LOG_DEBUG: file = uboot.img
LOG_DEBUG: offset = 950822
LOG_DEBUG: flash_offset = 16384
LOG_DEBUG: usespace = 2048
LOG_DEBUG: size = 4194304
LOG_INFO: ================================================
LOG_DEBUG: name = misc
LOG_DEBUG: file = misc.img
LOG_DEBUG: offset = 5145126
LOG_DEBUG: flash_offset = 24576
LOG_DEBUG: usespace = 24
LOG_DEBUG: size = 49152
LOG_INFO: ================================================
LOG_DEBUG: name = dtbo
LOG_DEBUG: file = dtbo.img
LOG_DEBUG: offset = 5194278
LOG_DEBUG: flash_offset = 32768
LOG_DEBUG: usespace = 1
LOG_DEBUG: size = 1424
LOG_INFO: ================================================
LOG_DEBUG: name = resource
LOG_DEBUG: file = resource.img
LOG_DEBUG: offset = 5196326
LOG_DEBUG: flash_offset = 40960
LOG_DEBUG: usespace = 2958
LOG_DEBUG: size = 6056448
LOG_INFO: ================================================
LOG_DEBUG: name = kernel
LOG_DEBUG: file = kernel.img
LOG_DEBUG: offset = 11254310
LOG_DEBUG: flash_offset = 73728
LOG_DEBUG: usespace = 17296
LOG_DEBUG: size = 35420180
LOG_INFO: ================================================
LOG_DEBUG: name = boot
LOG_DEBUG: file = boot.img
LOG_DEBUG: offset = 46676518
LOG_DEBUG: flash_offset = 155648
LOG_DEBUG: usespace = 3942
LOG_DEBUG: size = 8072140
LOG_INFO: ================================================
LOG_DEBUG: name = recovery
LOG_DEBUG: file = recovery.img
LOG_DEBUG: offset = 54749734
LOG_DEBUG: flash_offset = 221184
LOG_DEBUG: usespace = 30360
LOG_DEBUG: size = 62177192
LOG_INFO: ================================================
LOG_DEBUG: name = rootfs
LOG_DEBUG: file = rootfs.img
LOG_DEBUG: offset = 116927014
LOG_DEBUG: flash_offset = 483328
LOG_DEBUG: usespace = 2897281
LOG_DEBUG: size = 1638663408
LOG_INFO: ================================================
LOG_DEBUG: name = userdata
LOG_DEBUG: file = userdata.img
LOG_DEBUG: offset = 1755591206
LOG_DEBUG: flash_offset = 12410880
LOG_DEBUG: usespace = 79
LOG_DEBUG: size = 159868
LOG_INFO: new md5:fb182c591afe986abd10f8069cac30c0
LOG_INFO: MD5Check is ok of /userdata/update.img
LOG_INFO: analyticImage ok.
LOG_INFO: found rkimage_hdr.item[1].name = parameter.
LOG_INFO: found rkimage_hdr.item[9].name = recovery.
LOG_INFO: Now is SD.
LOG_INFO: no found mtd.
LOG_INFO: now write parameter to /dev/block/by-name/gpt.
LOG_INFO: ingore misc.
LOG_INFO: now write recovery to /dev/block/by-name/recovery.
LOG_INFO: update_cmd.flash_offset = 0.
LOG_INFO: flash_normal:205 start.
LOG_INFO: Now is SD.
LOG_INFO: no found mtd.
LOG_INFO: flash_normal:227, diff check for recovery
LOG_WARN: Not a diff image, ret = 80
LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/recovery.
LOG_INFO: Now is SD.
LOG_INFO: no found mtd.
LOG_INFO: new md5:df6b7b60a38d22f1f4c0779d2600df10
LOG_INFO: MD5Check is ok of /dev/block/by-name/recovery
LOG_INFO: new md5:df6b7b60a38d22f1f4c0779d2600df10
LOG_INFO: MD5Check is ok of /userdata/update.img
LOG_INFO: check /dev/block/by-name/recovery ok.
LOG_INFO: RK_ota_start is ok!LOG_INFO: rk ota success.
LOG_INFO: Current Mode is recovery.
LOG_INFO: rk m_status = 0.
LOG_INFO: Now is SD.
LOG_INFO: no found mtd.
通过查看日志信息,我们就可以了解到在normal
系统下的升级流程,即仅仅升级recovery
分区,这和和文章《Rockchip RK3588 - Rockchip Linux Recovery updateEngine
源码分析》分析的一致。
3.3.3 recovery
系统下升级日志
接着重启进入recovery
系统,系统启动关键日志:
点击查看代码
U-Boot 2017.09-g8241716-dirty #root (Jul 20 2024 - 11:31:35 +0800)
Board: NanoPi R6S
PreSerial: 2, raw, 0xfeb50000
DRAM: 16 GiB
Sysmem: init
Relocation Offset: eda2b000
Relocation fdt: eb9f9e20 - eb9fece0
CR: M/C/I
Using default environment
DM: v2
no mmc device at slot 1
mmc@fe2c0000: 1 (SD), mmc@fe2e0000: 0
Bootdev(atags): mmc 1
MMC1: Legacy, 52Mhz
PartType: EFI
boot mode: recovery (misc)
Failed to get rk3588-nanopi6-rev01.dtb
Failed to load DTB, ret=-19
No valid DTB, ret=-22
Failed to get kernel dtb, ret=-22
rockchip_set_serialno: could not find efuse/otp device
CLK: (sync kernel. arm: enter 1008000 KHz, init 1008000 KHz, kernel 0N/A)
b0pll 24000 KHz
b1pll 24000 KHz
lpll 24000 KHz
v0pll 24000 KHz
aupll 24000 KHz
cpll 1500000 KHz
gpll 1188000 KHz
npll 24000 KHz
ppll 100000 KHz
aclk_center_root 702000 KHz
pclk_center_root 100000 KHz
hclk_center_root 396000 KHz
aclk_center_low_root 500000 KHz
aclk_top_root 750000 KHz
pclk_top_root 100000 KHz
aclk_low_top_root 396000 KHz
vdd_usbc 12510 mV
Net: No ethernet found.
Hit key to stop autoboot('CTRL+C'): 0
## Booting FIT Image at 0xe9f0b200 with size 0x018eda94
Fdt Ramdisk skip relocation
## Loading kernel from FIT Image at e9f0b200 ...
Using 'conf' configuration
optee api revision: 2.0
TEEC: Waring: Could not find security partition
## Verified-boot: 0
Trying 'kernel' kernel subimage
Description: Vanilla Linux kernel
Type: Kernel Image
Compression: gzip compressed
Data Start: 0xe9f4d924
Data Size: 12742364 Bytes = 12.2 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x00400000
Entry Point: 0x00400000
Hash algo: sha256
Hash value: 7b70ba6cae5487c135c24b66122cb63002ea1d12166bd99e456d3ff43061c8a2
Verifying Hash Integrity ... sha256+ OK
## Loading ramdisk from FIT Image at e9f0b200 ...
Using 'conf' configuration
Trying 'ramdisk' ramdisk subimage
Description: Ramdisk for project-x
Type: RAMDisk Image
Compression: gzip compressed
Data Start: 0xeab74800
Data Size: 13124403 Bytes = 12.5 MiB
Architecture: AArch64
OS: Linux
Load Address: 0x0a200000
Entry Point: unavailable
Hash algo: sha256
Hash value: 06fce1042757d3414fbb496f362e7b537c476674eae2f9fce0f0fc77518303c6
Verifying Hash Integrity ... sha256+ OK
+ Loading ramdisk from 0x0a200000 to 0x0a200000
## Loading fdt from FIT Image at e9f0b200 ...
Using 'conf' configuration
Trying 'fdt' fdt subimage
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0xe9f0ba00
Data Size: 270114 Bytes = 263.8 KiB
Architecture: AArch64
Load Address: 0x08300000
Hash algo: sha256
Hash value: cd297b6895d00b4626dcd74ad9a66b4c90173077585dc7a0c63034921e5ecb8a
Verifying Hash Integrity ... sha256+ OK
Using fdt from load-in fdt
Loading fdt from 0xe9f0ba00 to 0x08300000
Booting using the fdt blob at 0x08300000
Uncompressing GZIP Kernel Image from 0xe9f4d924 to 0x00400000 ... with 021c7808 bytes OK
kernel loaded at 0x00400000, end = 0x025c7808
Using Device Tree in place at 0000000008300000, end 0000000008344f21
can't get otp device, ret=-19
## reserved-memory:
cma: addr=10000000 size=8000000
vendor-storage-rm@00000000: addr=ebc37000 size=10000
ramoops@110000: addr=110000 size=e0000
Adding bank: 0x00200000 - 0x08400000 (size: 0x08200000)
Adding bank: 0x09400000 - 0xf0000000 (size: 0xe6c00000)
Adding bank: 0x100000000 - 0x3fc000000 (size: 0x2fc000000)
Adding bank: 0x3fc500000 - 0x3fff00000 (size: 0x03a00000)
Adding bank: 0x4f0000000 - 0x500000000 (size: 0x10000000)
Total: 3649.665/4541.166 ms
Starting kernel ...
[ 4.551860] Booting Linux on physical CPU 0x0000000000 [0x412fd050]
[ 4.551883] Linux version 6.1.25 (root@ubuntu) (aarch64-linux-gnu-gcc (Ubuntu 10.5.0-1ubuntu1~22.04) 10.5.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #3 SMP Sat Jul 20 17:51:46 CST 2024
......
[ 4.916562] Kernel command line: storagemedia=sd androidboot.storagemedia=sd androidboot.mode=normal earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 coherent_pool=1m irqchip.gicv3_pseudo_nmi=0
......
[ 6.619259] RAMDISK: ext2 filesystem found at block 0
[ 6.619277] RAMDISK: Loading 74136KiB [1 disk] into ram disk... /
......
执行/usr/bin/recovery
升级其它分区。
3.4 其它
3.4.1 开机进入normal
系统
uboot
会根据misc
分区存放的字段来判断将要引导的系统是normal
系统还是recovery
系统。
如果uboot
引导一直进入recovery
系统,我们可以考虑在uboot
命令行中清理misc
分区内容。
misc
分区位于0x6000
扇区,大小为0x2000
个扇区,实际上我们只用清除偏移16k
的1088
个字节即可.
切换到SD
卡所属设备:
==> mmc list
mmc@fe2c0000: 1 (SD) # 代表SD卡
mmc@fe2e0000: 0 # 代表eMMC
==> mmc dev 1
switch to partitions #0, OK
mmc1 is current device
==> mmc info
Device: mmc@fe2c0000
Manufacturer ID: 3
OEM: 5344
Name: SD32G
Timing Interface: Legacy
Tran Speed: 52000000
Rd Block Len: 512
SD version 3.0
High Capacity: Yes
Capacity: 29.7 GiB
Bus Width: 4-bit
Erase Group Size: 512 Bytes
从misc
分区偏移16k
读取3个扇区数据:
==> mmc read 0x10000000 0x6020 3
查看这三个扇区数据:
# 查看前两个扇区数据
==> md.b 0x10000000 0x600
10000000: 62 6f 6f 74 2d 72 65 63 6f 76 65 72 79 00 00 00 boot-recovery...
10000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000040: 72 65 63 6f 76 65 72 79 0a 2d 2d 75 70 64 61 74 recovery.--updat
10000050: 65 5f 70 61 63 6b 61 67 65 3d 2f 75 73 65 72 64 e_package=/userd
10000060: 61 74 61 2f 75 70 64 61 74 65 2e 69 6d 67 0a 00 ata/update.img..
10000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
10000090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
......
10000340: 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
......
这里的数据会解析成struct bootloader_message
数据结构:
struct bootloader_message {
char command[32]; // boot-recovery
char status[32];
char recovery[768]; // recovery\n--update_package=/userdata/update.img
char needupdate[4]; // 偏移0x340 00 00 02 00 =>0x20000,即升级rootfs分区
char systemFlag[252];
};
清除这三个扇区数据:
==> mmc erase 0x6020 3
MMC erase: dev # 1, block # 24608, count 3 ... 3 blocks erased: OK
然后重启开发板看看是否可以正常进入normal
系统。
3.4.2 开机进入recovery
系统
如需开机就进入recovery
系统,我们可以向misc
分区写入启动命令;
# 切换当前设备为SD卡
==> mmc dev 1
# 清除内存0x10000000开始的16个字节
==> mw.b 0x10000000 00 0x10
# 向内存0x10000000写入8个字节
==> mw.q 0x10000000 6365722d746f6f62
# 向内存0x10000008写入8个字节
==> mw.q 0x10000008 000000797265766f
# 将内存0x10000000开始的512个字节写入删除0x6020
==> mmc write 0x10000000 0x6020 1
# 读取数据,确认写入成功
==> mmc read 0x10000000 0x6020 1
==> md.b 0x10000000 0x10
这样重启开发板就可以进入recovery
系统;
四、uboot
改造
4.1 rockchip_get_boot_mode
函数定义在arch/arm/mach-rockchip/spl_boot_mode.c
文件,rockchip_get_boot_mode
用于获取系统启动是进入normal
系统还是recovery
系统,如果是normal
系统,则从boot
分区加载内核,否则从recovery
分区加载内核。
int rockchip_get_boot_mode(struct blk_desc *dev_desc, u32 bcb_sector_offset)
{
uint32_t reg_boot_mode;
int boot_mode;
/*
* Boot mode priority
*
* Anyway, we should set download boot mode as the highest priority, so:
* reboot loader/bootloader/fastboot > misc partition "recovery" > reboot xxx.
*/
// 0xfd588080
reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
if (reg_boot_mode == BOOT_LOADER) { // 进入normal系统
printf("boot mode: loader\n");
boot_mode = BOOT_MODE_LOADER;
} else if (reg_boot_mode == BOOT_DFU) {
printf("boot mode: dfu\n");
boot_mode = BOOT_MODE_DFU;
} else if (reg_boot_mode == BOOT_FASTBOOT) {
printf("boot mode: bootloader\n");
boot_mode = BOOT_MODE_BOOTLOADER;
} else if (misc_require_recovery(dev_desc, bcb_sector_offset)) { // 进入recovery系统
printf("boot mode: recovery (misc)\n");
boot_mode = BOOT_MODE_RECOVERY;
} else {
switch (reg_boot_mode) {
case BOOT_NORMAL:
printf("boot mode: normal\n");
boot_mode = BOOT_MODE_NORMAL;
break;
case BOOT_RECOVERY:
printf("boot mode: recovery (cmd)\n");
boot_mode = BOOT_MODE_RECOVERY;
break;
case BOOT_UMS:
printf("boot mode: ums\n");
boot_mode = BOOT_MODE_UMS;
break;
case BOOT_CHARGING:
printf("boot mode: charging\n");
boot_mode = BOOT_MODE_CHARGING;
break;
case BOOT_PANIC:
printf("boot mode: panic\n");
boot_mode = BOOT_MODE_PANIC;
break;
case BOOT_WATCHDOG:
printf("boot mode: watchdog\n");
boot_mode = BOOT_MODE_WATCHDOG;
break;
default:
printf("boot mode: None\n");
boot_mode = BOOT_MODE_UNDEFINE;
}
}
return boot_mode;
}
参考文章
[1] Mini2440
之uboot
移植之源码分析start.S
(一)]
[2] Mini2440之uboot
移植之裁剪、分区与环境变量设置(五)
[3] Rockchip RK3399
- 移植linux 5.2.8
[4] Mini2440
之uboot
移植之源码分析命令解析(五)
[5] 基于rk3566
的uboot
分析 - dts
加载和dm
模型的本质