当前位置:   article > 正文

Rockchip RK3588 - Rockchip Linux Recovery rkupdate升级

Rockchip RK3588 - Rockchip Linux Recovery rkupdate升级

----------------------------------------------------------------------------------------------------------------------------

开发板ArmSoM-Sige7开发板eMMC64GBLPDDR48GB
显示屏15.6英寸HDMI接口显示屏u-boot2017.09linux5.10
----------------------------------------------------------------------------------------------------------------------------

如果对Rockchip Linux SDK不了解的前提下,请先阅读以下两篇文章:

一、rkupdate in & mk分析

接下来我们来研究《配置recovery》小节中我们添加了如下配置项究竟实现了什么功能;

  1. #rkupdate升级方式配置项
  2. BR2_PACKAGE_RKUPDATE=y

注意:本节仅仅分析rkupdate升级方式。

在为Buildroot自定义软件包时,在软件包目录下通常为引入.in.mk文件;

  1. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll package/rockchip/rkupdate/
  2. -rw-r--r-- 1 root root 704 6月 9 12:58 Config.in
  3. -rw-r--r-- 1 root root 82 6月 9 12:58 rkupdate.hash
  4. -rw-r--r-- 1 root root 1017 6月 9 12:58 rkupdate.mk
1.1 Config.in

我们首先从Config.in文件入手,该文件实际上就是定义make menuconfig支持的配置选项;

  1. config BR2_PACKAGE_RKUPDATE
  2. bool "Rockchip rkupdate for linux"
  3. depends on BR2_TOOLCHAIN_HAS_THREADS # libpthread-stubs 此配置项依赖于BR2_TOOLCHAIN_HAS_THREADS(其开启的情况下才可用)
  4. select BR2_PACKAGE_LIBPTHREAD_STUBS # 如果启动,自动选择启用以下列出的其他软件包和库
  5. select BR2_PACKAGE_UTIL_LINUX
  6. select BR2_PACKAGE_UTIL_LINUX_LIBUUID
  7. help
  8. Rockchip rkupdate for linux.
  9. if BR2_PACKAGE_RKUPDATE
  10. config BR2_PACKAGE_RKUPDATE_SINGNATURE_FW
  11. bool "update signature firmware"
  12. help
  13. update signature firmware.
  14. config BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF
  15. bool "simulate abnormal power off during updating fw"
  16. help
  17. simulate abnormal power off during updating fw.
  18. config BR2_PACKAGE_RKUPDATE_STATIC
  19. bool "Enable static"
  20. default y if BR2_STATIC_LIBS
  21. select BR2_PACKAGE_UTIL_LINUX_STATIC
  22. endif

由于我们勾选了Rockchip rkupdate for linux,因此在生成的output/rockchip_rk3588_recovery/.config配置文件会配置:

BR2_PACKAGE_RKUPDATE=y
1.2 rkupdate.mk

buildroot编译rkupdate所需要的设置rkupdate.mk,包括源码位置、安装目录、权限设置等。

  1. ################################################################################
  2. #
  3. # Rockchip rkupdate For Linux
  4. #
  5. ################################################################################
  6. RKUPDATE_VERSION = develop
  7. RKUPDATE_SITE = $(TOPDIR)/../external/rkupdate
  8. RKUPDATE_SITE_METHOD = local
  9. RKUPDATE_LICENSE = Apache V2.0
  10. RKUPDATE_LICENSE_FILES = NOTICE
  11. RKUPDATE_DEPENDENCIES = \
  12. libpthread-stubs util-linux
  13. RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid
  14. ifeq ($(BR2_PACKAGE_RKUPDATE_SINGNATURE_FW),y)
  15. RKUPDATE_CFLAGS += -DUSE_SIGNATURE_FW=ON
  16. endif
  17. ifeq ($(BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF),y)
  18. RKUPDATE_CFLAGS += -DUSE_SIMULATE_POWER_OFF=ON
  19. endif
  20. ifeq ($(BR2_PACKAGE_RKUPDATE_STATIC),y)
  21. RKUPDATE_CFLAGS += -static
  22. endif
  23. define RKUPDATE_BUILD_CMDS
  24. $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) \
  25. CXX="$(TARGET_CXX)" CFLAGS="$(RKUPDATE_CFLAGS)"
  26. endef
  27. define RKUPDATE_INSTALL_TARGET_CMDS
  28. $(INSTALL) -D -m 755 $(@D)/rkupdate $(TARGET_DIR)/usr/bin/
  29. endef
  30. $(eval $(generic-package))
1.2.1 约定配置

首先映入眼帘的是一些约定的配置:

  • RKUPDATE_VERSION:定义了源码的版本号为develop
  • RKUPDATE_SITE:定义了源码下载地址,这里指定为<SDK>/external/rkupdate
  • RKUPDATE_SITE_METHOD:定义了源码下载的方式,该处指定为本地获取(local);
  • RKUPDATE_LICENSE:设置许可证类型为Apache V2.0
  • RKUPDATE_LICENSE_FILES:设置许可证文件NOTICE
1.2.2 编译选项

接下来的是编译选项和依赖关系配置:

(1) RKUPDATE_CFLAGS:编译选项配置,包括开启线程支持、uuid等;

RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid

其中:

  • -fPICGCC和其他兼容编译器的选项,表示生成位置无关的代码,用于动态链接库。这是因为动态链接库在编译时无法确定加载地址,因此需要生成位置无关的代码;
  • -lpthread:表示链接pthread库,即POSIX线程库,用于多线程编程;
  • -luuid:表示链接uuid库,该库提供了生成和操作通用唯一标识符的函数。

这些选项通常用于构建需要多线程、uuid支持的应用程序或库。在编译时,它们告诉编译器在链接阶段需要使用这些特定的外部库。

(2) RKUPDATE_DEPENDENCIES:定义依赖项,包括libpthread-stubsutil-linux,这样在编译rkupdate软件包的时候才会构建和安装依赖包。

1.2.3 条件编译配置

紧跟着的就是一些条件编译配置项;

  1. ifeq ($(BR2_PACKAGE_RKUPDATE_SINGNATURE_FW),y)
  2. RKUPDATE_CFLAGS += -DUSE_SIGNATURE_FW=ON # 不走这里
  3. endif
  4. ifeq ($(BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF),y)
  5. RKUPDATE_CFLAGS += -DUSE_SIMULATE_POWER_OFF=ON # 不走这里
  6. endif
  7. ifeq ($(BR2_PACKAGE_RKUPDATE_STATIC),y)
  8. RKUPDATE_CFLAGS += -static # 不走这里
  9. endif

由于这些配置项我们都未开启,因此直接跳过。

1.2.4 CMD命令之BUILD

接着是定义一系列的编译命令,这些_CMD结尾的变量会在buildroot框架编译的时候执行,用于给源码的Makefile传递编译选项和链接选项,调用源码的Makefile

  1. define RKUPDATE_BUILD_CMDS
  2. $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) \
  3. CXX="$(TARGET_CXX)" CFLAGS="$(RKUPDATE_CFLAGS)"
  4. endef

RKUPDATE_BUILD_CMDSmake <pkg>build阶段被执行;

(TARGET_MAKE_ENV) $(MAKE) -C $(@D) CC="$(TARGET_CC)" CFLAGS="$(RKUPDATE_CFLAGS)"

这里同updateEngine源码分析,不再重复介绍。其中:

  • MAKE变量值被设置为make
  • CC变量值被设置为$(TARGET_CC)
  • CFLAGS变量值被设置为$(RKUPDATE_CFLAGS)

其中:

  1. TARGET_CC = <SDK>/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc
  2. RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid

我们知道buildroot软件包在编译时会将源码拷贝到output/rockchip_rk3588_recovery/build目录下,rkupdate软件包对应的目录为rkupdate-develop

  1. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588_recovery/build/rkupdate-develop/
  2. -rw-r--r-- 1 root root 860 6月 9 12:59 Android.mk
  3. -rwxr-xr-x 1 root root 832 6月 18 01:48 .build.sh*
  4. -rwxr-xr-x 1 root root 158 6月 18 01:48 .configure.sh*
  5. -rw-r--r-- 1 root root 13748 6月 9 12:59 CRC.cpp
  6. -rw-r--r-- 1 root root 7648 6月 18 01:48 CRC.o
  7. -rw-r--r-- 1 root root 9516 6月 9 12:59 DefineHeader.h
  8. -rwxr-xr-x 1 root root 795 6月 18 01:48 .deploy.sh*
  9. -rw-r--r-- 1 root root 1170 6月 9 12:59 Endian.h
  10. -rw-r--r-- 1 root root 0 6月 18 01:48 .files-list-host.txt
  11. -rw-r--r-- 1 root root 0 6月 18 01:48 .files-list-images.txt
  12. -rw-r--r-- 1 root root 0 6月 18 01:48 .files-list-staging.txt
  13. -rw-r--r-- 1 root root 19 6月 18 01:48 .files-list-target.txt
  14. -rw-r--r-- 1 root root 28 6月 18 01:48 .files-list.txt
  15. -rw-r--r-- 1 root root 5145 6月 9 12:59 gpt.h
  16. -rw-r--r-- 1 root root 1574 6月 9 12:59 LICENSE
  17. -rw-r--r-- 1 root root 1435 6月 9 12:59 main.cpp
  18. -rw-r--r-- 1 root root 3696 6月 18 01:48 main.o
  19. -rw-r--r-- 1 root root 360 6月 9 12:59 Makefile
  20. -rw-r--r-- 1 root root 25035 6月 9 12:59 MD5Checksum.cpp
  21. -rw-r--r-- 1 root root 4792 6月 9 12:59 MD5ChecksumDefines.h
  22. -rw-r--r-- 1 root root 16694 6月 9 12:59 MD5Checksum.h
  23. -rw-r--r-- 1 root root 17984 6月 18 01:48 MD5Checksum.o
  24. -rw-r--r-- 1 root root 2633 6月 9 12:59 Property.hpp
  25. -rw-r--r-- 1 root root 116700 6月 9 12:59 RKAndroidDevice.cpp
  26. -rw-r--r-- 1 root root 9743 6月 9 12:59 RKAndroidDevice.h
  27. -rw-r--r-- 1 root root 87464 6月 18 01:48 RKAndroidDevice.o
  28. -rw-r--r-- 1 root root 8826 6月 9 12:59 RKBoot.cpp
  29. -rw-r--r-- 1 root root 2879 6月 9 12:59 RKBoot.h
  30. -rw-r--r-- 1 root root 6840 6月 18 01:48 RKBoot.o
  31. -rw-r--r-- 1 root root 17886 6月 9 12:59 RKComm.cpp
  32. -rw-r--r-- 1 root root 7447 6月 9 12:59 RKComm.h
  33. -rw-r--r-- 1 root root 22200 6月 18 01:48 RKComm.o
  34. -rw-r--r-- 1 root root 18278 6月 9 12:59 RKDevice.cpp
  35. -rw-r--r-- 1 root root 6709 6月 9 12:59 RKDevice.h
  36. -rw-r--r-- 1 root root 15728 6月 18 01:48 RKDevice.o
  37. -rw-r--r-- 1 root root 10811 6月 9 12:59 RKImage.cpp
  38. -rw-r--r-- 1 root root 2494 6月 9 12:59 RKImage.h
  39. -rw-r--r-- 1 root root 14488 6月 18 01:48 RKImage.o
  40. -rw-r--r-- 1 root root 1365 6月 9 12:59 RKLog.cpp
  41. -rw-r--r-- 1 root root 586 6月 9 12:59 RKLog.h
  42. -rw-r--r-- 1 root root 6048 6月 18 01:48 RKLog.o
  43. -rwxr-xr-x 1 root root 132992 6月 18 01:48 rkupdate*
  44. -rw-r--r-- 1 root root 143360 6月 18 01:48 rkupdate-develop.tar
  45. -rw-r--r-- 1 root root 0 6月 18 01:48 .stamp_built
  46. -rw-r--r-- 1 root root 0 6月 18 01:48 .stamp_configured
  47. -rw-r--r-- 1 root root 0 6月 18 01:48 .stamp_installed
  48. -rw-r--r-- 1 root root 0 6月 18 01:48 .stamp_rsynced
  49. -rw-r--r-- 1 root root 0 6月 18 01:48 .stamp_target_installed
  50. -rwxr-xr-x 1 root root 2700 6月 18 01:48 .target_install.sh*
  51. -rwxr-xr-x 1 root root 984 6月 18 01:48 .update.sh*
  52. -rw-r--r-- 1 root root 37184 6月 9 12:59 Upgrade.cpp
  53. -rw-r--r-- 1 root root 440 6月 9 12:59 Upgrade.h
  54. -rw-r--r-- 1 root root 41432 6月 18 01:48 Upgrade.o
1.2.5 CMD命令之INSTALL
  1. define RKUPDATE_INSTALL_TARGET_CMDS
  2. $(INSTALL) -D -m 755 $(@D)/rkupdate $(TARGET_DIR)/usr/bin/
  3. endef

这行命令使用了makefile中定义的INSTALL变量,以及自动变量$(@D)和预定义变量TARGET_DIR。它的作用是将源码rkupdate编译出来的rkupdate可执行文件安装到目标系统的/usr/bin/目录下,并设置相应的权限;

因此如果在recovery软件包编译安装完成后,我们可以在<SDK>/buildroot/output/rockchip_rk3588_recovery/target/usr/bin中看到rkupdate可执行文件;

  1. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588_recovery/target/usr/bin/rkupdate
  2. -rwxr-xr-x 1 root root 106568 6月 18 01:48 output/rockchip_rk3588_recovery/target/usr/bin/rkupdate*
1.2.6 $(eval $(generic-package))

($eval$(generic-package)) 最核心的就是这个东西了,一定不能够漏了,不然源码不会被编译,这个函数就是把整个.mk构建脚本,通过Buildroot框架的方式,展开到Buildroot/目录下的Makfile中,生成的构建目标。

1.3 Makefile

经过前面对rkupdate.mk的分析,我们已经知道rkupdate的源码位于本地<SDK>/external/rkupdate目录;

  1. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ ll external/rkupdate/
  2. -rw-r--r-- 1 root root 860 6月 9 12:59 Android.mk
  3. -rw-r--r-- 1 root root 13748 6月 9 12:59 CRC.cpp
  4. -rw-r--r-- 1 root root 9516 6月 9 12:59 DefineHeader.h
  5. -rw-r--r-- 1 root root 1170 6月 9 12:59 Endian.h
  6. -rw-r--r-- 1 root root 5145 6月 9 12:59 gpt.h
  7. -rw-r--r-- 1 root root 1574 6月 9 12:59 LICENSE
  8. -rw-r--r-- 1 root root 1435 6月 9 12:59 main.cpp
  9. -rw-r--r-- 1 root root 360 6月 9 12:59 Makefile
  10. -rw-r--r-- 1 root root 25035 6月 9 12:59 MD5Checksum.cpp
  11. -rw-r--r-- 1 root root 4792 6月 9 12:59 MD5ChecksumDefines.h
  12. -rw-r--r-- 1 root root 16694 6月 9 12:59 MD5Checksum.h
  13. -rw-r--r-- 1 root root 2633 6月 9 12:59 Property.hpp
  14. -rw-r--r-- 1 root root 116700 6月 9 12:59 RKAndroidDevice.cpp
  15. -rw-r--r-- 1 root root 9743 6月 9 12:59 RKAndroidDevice.h
  16. -rw-r--r-- 1 root root 8826 6月 9 12:59 RKBoot.cpp
  17. -rw-r--r-- 1 root root 2879 6月 9 12:59 RKBoot.h
  18. -rw-r--r-- 1 root root 17886 6月 9 12:59 RKComm.cpp
  19. -rw-r--r-- 1 root root 7447 6月 9 12:59 RKComm.h
  20. -rw-r--r-- 1 root root 18278 6月 9 12:59 RKDevice.cpp
  21. -rw-r--r-- 1 root root 6709 6月 9 12:59 RKDevice.h
  22. -rw-r--r-- 1 root root 10811 6月 9 12:59 RKImage.cpp
  23. -rw-r--r-- 1 root root 2494 6月 9 12:59 RKImage.h
  24. -rw-r--r-- 1 root root 1365 6月 9 12:59 RKLog.cpp
  25. -rw-r--r-- 1 root root 586 6月 9 12:59 RKLog.h
  26. -rw-r--r-- 1 root root 37184 6月 9 12:59 Upgrade.cpp
  27. -rw-r--r-- 1 root root 440 6月 9 12:59 Upgrade.h

首先我们需要了解源码的Makefile是怎么样的,其内容如下;

点击查看代码
  1. PROJECT_DIR := $(shell pwd)
  2. PROM = rkupdate
  3. OBJ =CRC.o \
  4. MD5Checksum.o \
  5. RKAndroidDevice.o \
  6. RKBoot.o \
  7. RKComm.o \
  8. RKDevice.o \
  9. RKImage.o \
  10. RKLog.o \
  11. Upgrade.o \
  12. main.o
  13. $(PROM): $(OBJ)
  14. $(CXX) -o $(PROM) $(OBJ) $(CFLAGS)
  15. %.o: %.cpp
  16. $(CXX) -c $< -o $@ $(CFLAGS)
  17. clean:
  18. rm -rf $(OBJ) $(PROM)
  19. install:
  20. sudo install -D -m 755 $(PROJECT_DIR)/rkupdate -t $(DESTDIR)/usr/bin/

这段脚本写的比较简单,在编译rkupdate软件包的build阶段,会执行如下命令;

(TARGET_MAKE_ENV) $(MAKE) -C $(@D) CC="$(TARGET_CC)" CFLAGS="$(RKUPDATE_CFLAGS)"

其中:

  • CC<SDK>/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc
  • CFLAGS$(TARGET_CFLAGS) -fPIC -lpthread -luuid
1.3.1 变量定义

脚本开始定义了一些变量:

  • PROJECT_DIR:既时变量,值在定义时就确定,为当前工作路径;
  • PROM:延时变量,值在使用的时候才确定,这里设置为rkupdate
1.3.2 目标rkupdate

第一个目标rkupdate,是由若干个.o文件通过aarch64-buildroot-linux-gnu-gcc编译器链接生成的可执行文件。

  1. OBJ =CRC.o \
  2. MD5Checksum.o \
  3. RKAndroidDevice.o \
  4. RKBoot.o \
  5. RKComm.o \
  6. RKDevice.o \
  7. RKImage.o \
  8. RKLog.o \
  9. Upgrade.o \
  10. main.o
  11. $(PROM): $(OBJ)
  12. $(CXX) -o $(PROM) $(OBJ) $(CFLAGS)

.o文件实际上是由.c文件通过aarch64-buildroot-linux-gnu-gcc编译器编译生成的。

  1. %.o: %.cpp
  2. $(CXX) -c $< -o $@ $(CFLAGS)
1.3.3 目标clean

伪目标clean用于执行清理工作;

  1. clean:
  2. rm -rf $(OBJ) $(PROM)
1.3.4 目标install

伪目标install用于执行安装工作;

  1. install:
  2. sudo install -D -m 755 $(PROJECT_DIR)/rkupdate -t $(DESTDIR)/usr/bin/
1.4 编译

在《Rockchip RK3588 - Rockchip Linux SDK Buildroot文件系统构建》中介绍过buildroot编译命令;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8

或者使用如下命令单独编译rkupdate软件包:

  1. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make rkupdate-dirclean
  2. root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make rkupdate

其中rkupdate编译日志如下:

点击查看代码
  1. >>> rkupdate develop Syncing from source dir /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/rkupdate
  2. rsync -au --chmod=u=rwX,go=rX --exclude .svn --exclude .git --exclude .hg --exclude .bzr --exclude CVS /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/rkupdate/ /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop
  3. >>> rkupdate develop Configuring
  4. >>> rkupdate develop Building
  5. PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop CXX="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++" CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid"
  6. make[1]: 进入目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop”
  7. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c CRC.cpp -o CRC.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  8. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c MD5Checksum.cpp -o MD5Checksum.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  9. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKAndroidDevice.cpp -o RKAndroidDevice.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  10. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKBoot.cpp -o RKBoot.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  11. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKComm.cpp -o RKComm.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  12. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKDevice.cpp -o RKDevice.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  13. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKImage.cpp -o RKImage.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  14. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKLog.cpp -o RKLog.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  15. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c Upgrade.cpp -o Upgrade.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  16. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c main.cpp -o main.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  17. /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -o rkupdate CRC.o MD5Checksum.o RKAndroidDevice.o RKBoot.o RKComm.o RKDevice.o RKImage.o RKLog.o Upgrade.o main.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
  18. make[1]: 离开目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop”
  19. >>> rkupdate develop Installing to target
  20. /usr/bin/install -D -m 755 /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop/rkupdate /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/usr/bin/

在日志中输出了rkupdate软件包构建的各个阶段的信息,可以验证我们之前的分析是否正确。比如编译命令:

PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make  -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop CXX="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++" CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid"

二、rkupdate源码分析

由于rkupdate可执行文件是由 MD5Checksum.cRKAndroidDevice.cRKBoot.cRKComm.cRKDevice.cRKImage.cRKLog.cUpgrade.cmain.c文件编译而成,程序的入口为main.cpp文件。

2.1 main.cpp

main函数实现如下:

  1. FILE *cmd_pipe = NULL;
  2. int sdBootUpdate = 0;
  3. int main(int argc, char *argv[])
  4. {
  5. int status;
  6. setbuf(stdout, NULL);
  7. setbuf(stderr, NULL);
  8. if (argc != 5)
  9. {
  10. printf("unexpected number of arguments (%d)\n", argc);
  11. fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
  12. return 1;
  13. }
  14. int fd = atoi(argv[2]);
  15. cmd_pipe = fdopen(fd, "wb");
  16. setlinebuf(cmd_pipe);
  17. char *filepath = argv[3];
  18. sdBootUpdate = atoi(argv[4]);
  19. //call update
  20. bool bRet = do_rk_firmware_upgrade(filepath, (void *)handle_upgrade_callback,
  21. (void *)handle_upgrade_progress_callback);
  22. if (!bRet)
  23. {
  24. status = INSTALL_ERROR;
  25. }
  26. else
  27. {
  28. status = INSTALL_SUCCESS;
  29. }
  30. sleep(5);
  31. sync();
  32. return status;
  33. }

函数接收5个参数:

  • 第一个参数为当前可执行文件,即rkupdate
  • 第二个参数:
  • 第三个参数是文件描述符fd
  • 第四个参数为升级的固件文件filepath,比如/userdata/update.img
  • 第五个参数为sdBootUpdate:指明当前设备启动方式是否为SD启动;

main函数内部主要调用do_rk_firmware_upgrade来实现固件的升级,函数接收4个参数;

  • szFw:需要升级的固件文件路径;
  • pCallback:固件升级回调函数;
  • pProgressCallback:固件升级进度回调函数;
  • szBootDev:设备是否是SD卡启动;
2.2 Upgrade.cpp

do_rk_firmware_upgrade函数位于Upgrade.cpp文件;

  1. UpgradeCallbackFunc g_callback = NULL;
  2. UpgradeProgressCallbackFunc g_progress_callback = NULL;
  3. extern int sdBootUpdate;
  4. bool do_rk_firmware_upgrade(char *szFw, void *pCallback, void *pProgressCallback, char *szBootDev)
  5. {
  6. bool bSuccess = false, bRet = false, bLock;
  7. int iRet;
  8. CRKImage *pImage = NULL;
  9. CRKLog *pLog = NULL;
  10. CRKAndroidDevice *pDevice = NULL;
  11. CRKComm *pComm = NULL;
  12. STRUCT_RKDEVICE_DESC device;
  13. BYTE key[514];
  14. UINT nKeySize = 514;
  15. BYTE uid[RKDEVICE_UID_LEN];
  16. tstring strFw = szFw;
  17. tstring strUid;
  18. bool bUpdateLoader = true;
  19. // 1. 设置了全局的回调函数,并立即调用进度回调函数报告0.1的进度和10秒的耗时。
  20. g_callback = (UpgradeCallbackFunc)pCallback;
  21. g_progress_callback = (UpgradeProgressCallbackFunc)pProgressCallback;
  22. if (g_progress_callback)
  23. {
  24. g_progress_callback(0.1, 10);
  25. }
  26. // 2. 初始化日志对象pLog用于记录升级过程中的信息
  27. pLog = new CRKLog();
  28. if (!pLog)
  29. {
  30. goto EXIT_UPGRADE;
  31. }
  32. pLog->Record("Start to upgrade firmware...");
  33. // 3. 创建固件镜像对象pImage
  34. pImage = new CRKImage(strFw, bRet);
  35. if (!bRet)
  36. {
  37. pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKImage failed!");
  38. goto EXIT_UPGRADE;
  39. }
  40. // 4. 创建通信对象pComm用于后续的设备交互
  41. pComm = new CRKUsbComm(pLog);
  42. if (!pComm)
  43. {
  44. pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKComm failed!");
  45. goto EXIT_UPGRADE;
  46. }
  47. // 5. 创建设备对象pDevice
  48. pDevice = new CRKAndroidDevice(device);
  49. if (!pDevice)
  50. {
  51. pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKAndroidDevice failed!");
  52. goto EXIT_UPGRADE;
  53. }
  54. pDevice->SetObject(pImage, pComm, pLog);
  55. // 6. 如果设备不是eMMC闪存,则生成并记录UUID。
  56. if (!pComm->RKU_IsEmmcFlash()) //chad.ma if is Emmc flash don't create UUID.
  57. {
  58. if (CreateUid(uid))
  59. {
  60. pDevice->Uid = uid;
  61. pLog->PrintBuffer(strUid, uid, RKDEVICE_UID_LEN);
  62. pLog->Record("uid:%s", strUid.c_str());
  63. }
  64. }
  65. // 7. 获取闪存信息
  66. pDevice->m_pCallback = (UpgradeCallbackFunc)pCallback;
  67. pDevice->m_pProcessCallback = (UpgradeProgressCallbackFunc)pProgressCallback;
  68. pLog->Record("Get FlashInfo...");
  69. bRet = pDevice->GetFlashInfo();
  70. if (!bRet)
  71. {
  72. pLog->Record("ERROR:do_rk_firmware_upgrade-->GetFlashInfo failed!");
  73. goto EXIT_UPGRADE;
  74. }
  75. // 8. 判断升级的固件是否存在bootloader
  76. bUpdateLoader = pDevice->IsExistBootloaderInFw();
  77. if (IsRK3308_Platform() && Compatible_rk3308bs_loader())
  78. {
  79. // rk3308 才会进入
  80. .......
  81. }
  82. #ifndef USE_SIGNATURE_FW // 未定义进入
  83. if (bUpdateLoader) // 更新bootloader
  84. {
  85. printf("############### update bootloader start ############\n");
  86. pLog->Record("IDBlock Preparing...");
  87. printf("\t\t############### IDBlock Preparing...\n");
  88. iRet = pDevice->PrepareIDB();
  89. if (iRet != ERR_SUCCESS)
  90. {
  91. pLog->Record("ERROR:do_rk_firmware_upgrade-->PrepareIDB failed!");
  92. goto EXIT_UPGRADE;
  93. }
  94. pLog->Record("IDBlock Writing...");
  95. printf("\t\t############### IDBlock Writing...\n");
  96. iRet = pDevice->DownloadIDBlock();
  97. if (iRet != ERR_SUCCESS)
  98. {
  99. pLog->Record("ERROR:do_rk_firmware_upgrade-->DownloadIDBlock failed!");
  100. goto EXIT_UPGRADE;
  101. }
  102. printf("############### update bootloader Success############\n");
  103. if (strFw.find(_T(".bin")) != tstring::npos)
  104. {
  105. pLog->Record("INFO:do_rk_firmware_upgrade-->Download loader only success!");
  106. bSuccess = true;
  107. return bSuccess;
  108. }
  109. }
  110. // 9. 下载固件
  111. iRet = pDevice->DownloadImage();
  112. if (iRet != ERR_SUCCESS)
  113. {
  114. pLog->Record("ERROR:do_rk_firmware_upgrade-->DownloadImage failed!");
  115. goto EXIT_UPGRADE;
  116. }
  117. #else // 不会进入
  118. printf("use signature firmware to update.\n");
  119. ......
  120. #endif
  121. bSuccess = true;
  122. EXIT_UPGRADE:
  123. if (bSuccess)
  124. {
  125. pLog->Record("Finish to upgrade firmware.");
  126. }
  127. else
  128. {
  129. pLog->Record("Fail to upgrade firmware!");
  130. }
  131. if (pLog)
  132. {
  133. delete pLog;
  134. pLog = NULL;
  135. }
  136. if (pImage)
  137. {
  138. delete pImage;
  139. pImage = NULL;
  140. }
  141. if (pDevice)
  142. {
  143. delete pDevice;
  144. pDevice = NULL;
  145. }
  146. else
  147. {
  148. if (pComm)
  149. {
  150. delete pComm;
  151. pComm = NULL;
  152. }
  153. }
  154. return bSuccess;
  155. }

三、系统升级测试

3.1 buildroot系统升级

首先我们需要将我们制作的统一固件update.img(这里采用的buildroot系统)烧录到开发板eMMC中,具体烧录步骤可以参考《Rockchip RK3588 - Rockchip Linux SDK编译》。

需要注意的是:我们烧录的buildroot文件系统要按照本篇博客第一节的配置进行编译,即编译出来的rootfs.imgrecovery.img包含用于升级的updateEnginerkupdate可执行文件;

  1. root@rk3588-buildroot:~# ls /usr/bin/updateEngine -l
  2. -rwxr-xr-x 1 root root 80544 Jun 17 17:48 /usr/bin/updateEngine
  3. root@rk3588-buildroot:~# ls /usr/bin/rkupdate -l
  4. -rwxr-xr-x 1 root root 106568 Jun 17 17:48 /usr/bin/rkupdate
3.1.1 制作升级固件

按照正常的固件编译流程,制作用于升级的update.img固件,可以参考《Rockchip RK3588 - Rockchip Linux SDK编译》。

升级固件不一定要全分区升级,可修改 package-file 文件,将不要升级的分区去掉,这样可以减少升级包的大小。

例如,执行如下命令(可参考文件tools/linux/Linux_Pack_Firmware/rockdev/rk3588-package-file):

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh edit-package-file

rootfs的相对路径改为 RESERVED,这样就不会打包根文件系统,即不升级根文件系统分区。

  1. # NAME PATH
  2. package-file package-file
  3. parameter parameter.txt
  4. bootloader MiniLoaderAll.bin
  5. uboot uboot.img
  6. misc misc.img
  7. boot boot.img
  8. recovery recovery.img
  9. backup RESERVED
  10. rootfs rootfs.img
  11. oem oem.img
  12. userdata RESERVED

注意: 若将升级固件放至设备的/userdata/目录,则不要打包userdata.img,需要将image/userdata.img改为RESERVED

执行如下命令生成统一固件;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh updateimg

将制作好的升级固件拷贝到U盘、TF卡或者开发版的/userdata/目录下。

我们可以将统一镜像复制到/work/tftpwork目录下:

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ cp ./rockdev/update.img /work/tftpboot/
3.1.2 rkupdate升级测试

rkupdate升级流程如下:

  • 将升级固件update.img放在SD卡或U盘根目录或者设备的/userdata目录下;
  • normal系统下执行升级程序update ota /xxx/update.img
  • 升级recovery分区;
  • 重启;
  • 设备将会进入recovery模式,并进行升级;
  • 升级成功后会reboot到正常的normal系统;

可使用的路径如下:

  • U盘的挂载路径:/udisk
  • sdcard的挂载路径:/mnt/sdcard//sdcard
  • eMMC的挂载路径:/userdata/

升级流程图如下:

接下来我们进行测试,开发板从ubuntu tftp服务器下载统一镜像:

root@rk3588-buildroot:/userdata# tftp -g -l update.img 192.168.0.200

然后执行rkupdate升级命令:

root@rk3588-buildroot:/userdata# update ota /userdata/update.img

等待升级完成,升级成功后开发版会重新启动进入系统。

3.2 debian/ubuntu系统升级

Buildroot recovery升级一样,该Recovery OTA升级方案也支持DebianUbuntu系统下的升级。

由于Recovery模式下升级需要通过设备各个分区节点来识别并写入不同设备分区节点的固件数据,Buildroot系统是通过udev中的别名方式(by-name)来对设备分区节点做了通用的易识别的处理。

DebianUbuntu系统中因为缺少这样的方式,导致了实际中Recovery不能正常运行的情况,所以只需要将DebianUbuntu系统中设备分区的节点也跟Buildroot系统下可通过by-name别名方式标识出来,Recovery即可正常工作。

具体修改方式如下:

  1. buildroot/output/rockchip_rkxxxx/target/lib/udev/rules.d/61-partition-init.rules
  2. 或者
  3. buildroot/output/rockchip_rkxxxx_recovery/target/lib/udev/rules.d/61-partitioninit.rules

拷贝到DebianUbuntu系统下相关的位置,如rootfs/overlay-debug/lib/udev/rules.d/下。此处rkxxxx为具体某一rk芯片平台(RK3308RK3328RK3399RK3326等)。修改的目的就是开机启动后可以将Debian系统或Ubuntu系统中各个分区节点形如/dev/mmcblk0p0/dev/mmcblk0p1/dev/mmcblk0p2/dev/mmcblk0p3 ... 修改为/dev/block/byname/uboot /dev/block/by-name/misc/dev/block/by-name/boot/dev/block/byname/ rootfs ...等。

若还是出现如下类似设备节点:

  1. root@linaro-alip:~# ls /dev/block/
  2. 179:0 179:3 179:5 179:7 179:96 7:0 7:3 7:6
  3. 179:1 179:32 179:6 179:8 1:0 7:1 7:4 7:7
  4. 179:2 179:4 179:64 179:9 254:0 7:2 7:5

可尝试将61-partition-init.rules放在DebianUbuntu /etc/udev/rules.d/lib/udev/rules.d/

参考文章

[1] Rockchip Linux updateEngine升级方案介绍

[2] Rockchip Linux Recovery升级开发指南

[3] 嵌入式Linux开发之Makefile

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/767522
推荐阅读
相关标签
  

闽ICP备14008679号