当前位置:   article > 正文

Rockchip RK3588 - 从零开始制作recovery系统

rockchip recovery

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

开发板NanoPC-T6开发板eMMC256GBLPDDR416GB
显示屏15.6英寸HDMI接口显示屏u-boot2017.09linux6.1
----------------------------------------------------------------------------------------------------------------------------

在前面的文章我们对Rockhip Linux SDK进行了深入分析,其中涉及到了SDK编译过程、编译源码,具体可以参考:

此外,我们还是深入分析了Recovery模式下的系统升级功能,具体可参考:

本节我们将尝试在NanoPC-T6开发板实现系统升级功能,当然我们还期望当根文件系统损坏时,开发板能够通过按住GPIO口进入到recovery系统恢复正常系统。

一、uboot启动方式

既然要实现在NanoPC-T6开发板实现系统升级功能,我们就需要了解uboot启动内核的方式,并制作以下分区镜像;

  • misc.imgmisc分区是一个没有文件系统的分区,用于存放一些引导配置参数;
  • recovery.img:由kernel + dtb + ramdisk组成,主要用于升级操作;

uboot会根据misc分区存放的字段来判断将要引导的系统是normal系统还是recovery系统。

1.1 系统固件

我们使用的是NanoPC-T6开发板,这里我们就去下载官方提供的固件,关于固件的下载和烧烤可以参考《Rockchip RK3588- 移植uboot 2017.09 & linux 6.1(友善之家脚本方式)》。

这里我们选择debian-bullseye-desktop-arm64-images.tgz作为测试使用的镜像文件,将debian-bullseye-desktop-arm64-images.tgz(位于"\03_分区镜像文件"目录下,以实际下载的文件为准)拷贝到/work/sambashare/rk3588/friendly/sd-fuse_rk3588目录下;

  1. root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# ll debian*
  2. -rwxrw-rw- 1 root root 1590466719 Dec 3 01:49 debian-bullseye-desktop-arm64-images.tgz*
  3. -rwxrw-rw- 1 root root 75 Nov 18 19:05 debian-bullseye-desktop-arm64-images.tgz.hash.md5*
  4. root@zhengyang:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# tar -xvzf debian-bullseye-desktop-arm64-images.tgz

解压得到debian-bullseye-desktop-arm64文件夹;

  1. root@ubuntu:/work/sambashare/rk3588/friendly/sd-fuse_rk3588# ll debian-bullseye-desktop-arm64
  2. -rw-r--r-- 1 root root 8072140 May 28 2023 boot.img
  3. -rw-r--r-- 1 root root 1424 May 28 2023 dtbo.img
  4. -rw-r--r-- 1 root root 307200 Sep 8 23:33 idbloader.img
  5. -rw-r--r-- 1 root root 64 Nov 17 10:03 info.conf
  6. -rw-r--r-- 1 root root 35551252 Nov 16 16:17 kernel.img
  7. -rw-r--r-- 1 root root 471488 Sep 8 23:33 MiniLoaderAll.bin
  8. -rw-r--r-- 1 root root 49152 May 28 2023 misc.img
  9. -rw-r--r-- 1 root root 470 Nov 17 10:03 parameter.txt
  10. -rw-r--r-- 1 root root 6227456 Nov 16 16:17 resource.img
  11. -rw-r--r-- 1 root root 3992675220 Nov 17 10:03 rootfs.img
  12. -rw-r--r-- 1 root root 4194304 Sep 8 23:33 uboot.img
  13. -rw-r--r-- 1 root root 159868 Nov 17 10:03 userdata.img

可以看到解压的文件已经包含了misc.img,但是并没有recovery.img

1.1.1 系统分区介绍

parameter.txt保存着分区信息:

  1. FIRMWARE_VER: 12.0
  2. MACHINE_MODEL: RK3588
  3. MACHINE_ID: 007
  4. MANUFACTURER: RK3588
  5. MAGIC: 0x5041524B
  6. ATAG: 0x00200800
  7. MACHINE: NanoPi6
  8. CHECK_MASK: 0x80
  9. PWR_HLD: 0,0,A,0,1
  10. TYPE: GPT
  11. CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(misc),0x00002000@0x00008000(dtbo),0x00008000@0x0000a000(resource),0x00014000@0x00012000(kernel),0x00010000@0x00026000(boot),0x00010000@0x00036000(recovery),0x007c0000@0x00046000(rootfs),-@0x00806000(userdata:grow)

解析信息如下:

Number镜像文件Start (sector)Start (sector) End (sector)SizeName
1uboot.img0x40000x5FFF4Muboot
2misc.img0x60000x7FFF4Mmisc
3dtbo.img0x80000x9FFF4Mdtbo
4resource.img0xa0000x11FFF16MBresource
5kernel.img0x120000x25FFF40MBkernel
6boot.img0x260000x35FFF32MBboot
7recovery.img0x360000x45FFF32MBrecovery
8rootfs.img0x460000x804FFF3968GBrootfs
9userdata.img0x806000-userdata

其中:

  • uboot分区:供uboot编译出来的uboot.img
  • misc分区:引导参数分区,供misc.img,给recovery使用;
  • dtbo::供kernel编译出来的dtbo.img
  • resource:资源分区,由设备树、图片资源文件组成,不包含内核;
  • boot:供kernel编译出来的boot.img(kernel + dtb,对于该类型镜像uboot需要采用distro_boo extlinux引导方式);
  • kernel:供kernel编译出来的kernel.img(由tools/mkkrnlimg工具编译内核镜像Image文件得到);
  • recovery分区:供recovery编译出的recovery.img(kernel + dtb + ramdisk);
  • rootfs分区:供buildrootdebianyocto编出来的rootfs.img
  • userdata分区:供APP临时生成文件或给最终用户使用,挂载在/userdata目录下。

从上面我们可以看到这里有两个分区时存放了内核镜像,分别是bootkernel,那问题来了,uboot启动到底使用的是哪个内核呢?

1.1.2 烧录固件

我们将固件烧录到开发板;

给开发板上电,输出的日志中有如下内容:

  1. Hit key to stop autoboot('CTRL+C'): 0
  2. ## Booting FIT Image FIT: No fit blob
  3. FIT: No FIT image
  4. ANDROID: reboot reason: "(none)"
  5. Not AVB images, AVB skip
  6. No valid android hdr
  7. Android image load failed
  8. Android boot failed, error -1.
  9. ## Booting Rockchip Format Image
  10. fdt @ 0x08300000 (0x000421c2)
  11. kernel @ 0x00400000 (0x021c7808)
  12. ramdisk @ 0x0a200000 (0x007b2bc0)
  13. Fdt Ramdisk skip relocation
  14. ## Flattened Device Tree blob at 0x08300000
  15. Booting using the fdt blob at 0x08300000
  16. Using Device Tree in place at 0000000008300000, end 00000000083451c1

日志中说我们采用的内核镜像既不是是Android,也不是FIT uImage

接着又输出

uboot命令行查看启动命令:

1.2 boot启动命令

当我们在uboot命令行执行了boot命令时,uboot会获取bootcmd环境变量的内容,然后执行bootcmd中保存的启动命令。

接下来我们来分析一下bootcmd默认配置,在默认环境变量default_environment(位于uboot-rockchip/include/env_default.h)中定义有,其内容大致如下:

  1. const uchar default_environment[] = {
  2. "bootcmd=" CONFIG_BOOTCOMMAND "\0"
  3. "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
  4. "baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
  5. "ipaddr=" __stringify(CONFIG_IPADDR) "\0"
  6. "serverip=" __stringify(CONFIG_SERVERIP) "\0"
  7. "netmask=" __stringify(CONFIG_NETMASK) "\0"
  8. ......
  9. };

默认启动命令CONFIG_BOOTCOMMAND定义在uboot-rockchip/include/configs/nanopi6.h,该文件存放着开发板配置信息,被uboot-rockchip/include/config.h文件引入。

  1. #include <configs/rk3588_common.h>
  2. /* Remove or override few declarations from rk3588-common.h */
  3. #undef CONFIG_BOOTCOMMAND
  4. #undef CONFIG_DISPLAY_BOARDINFO_LATE
  5. #undef RKIMG_DET_BOOTDEV
  6. #undef RKIMG_BOOTCOMMAND
  7. #define CONFIG_SYS_MMC_ENV_DEV 0
  8. #define CONFIG_SYS_MMC_MAX_BLK_COUNT 32768
  9. #define CONFIG_MISC_INIT_R
  10. #define CONFIG_SERIAL_TAG
  11. #ifndef CONFIG_SPL_BUILD
  12. #define ROCKCHIP_DEVICE_SETTINGS \
  13. "stdout=serial,vidconsole\0" \
  14. "stderr=serial,vidconsole\0"
  15. #define RKIMG_DET_BOOTDEV \
  16. "rkimg_bootdev=" \
  17. "if mmc dev 1 && rkimgtest mmc 1; then " \
  18. "setenv devtype mmc; setenv devnum 1; echo Boot from SDcard;" \
  19. "elif mmc dev 0; then " \
  20. "setenv devtype mmc; setenv devnum 0;" \
  21. "elif rksfc dev 1; then " \
  22. "setenv devtype spinor; setenv devnum 1;" \
  23. "fi; \0"
  24. #define RKIMG_BOOTCOMMAND \
  25. "boot_fit;" \
  26. "boot_android ${devtype} ${devnum};" \
  27. "bootrkp;" \
  28. "run distro_bootcmd;"
  29. #define CONFIG_BOOTCOMMAND RKIMG_BOOTCOMMAND
  30. #endif

这里取消了uboot-rockchip/include/configs/rockchip-common.h中定义的宏RKIMG_BOOTCOMMAND,而进行了重定义。

这里支持了4中启动方式:

  • boot_fit:从eMMCboot分区加载FIT uImage镜像文件(通常由kernel + dtb + ramdisk组成)到内存,然后启动内核 ;
  • boot_android:启动Android内核镜像;
  • bootrkp:通常用于Rockchip平台上的特定启动操作,可能用于启动特定的固件或者特殊的操作模式;
  • distro_bootcmd:运行uboot环境中定义的 distro_bootcmd,这是一个uboot环境变量,通常包含了一系列的启动命令,比如尝试从网络引导、从存储设备引导等;

其中boot_fitdistro_bootcmd启动方式我们在《 Rockchip RK3399 - 移植linux 5.2.8》中有过介绍。

1.2.1 bootrkp

bootrkp命令的实现位于uboot-rockchip/cmd/bootrkp.cuboot中使用宏U_BOOT_CMD来定义命令;

  1. U_BOOT_CMD(
  2. bootrkp, 1, 1, do_boot_rockchip,
  3. "Boot Linux Image from rockchip image type",
  4. "kernel.img: zImage/Image\n"
  5. "boot.img: ramdisk\n"
  6. "resource.img: dtb, u-boot logo, kernel logo"
  7. );

该宏展开后实际上是一个cmd_tbl_t结构体变量,命令名为bootrkp,命令处理函数为do_boot_rockchip

  1. static int boot_rockchip_image(struct blk_desc *dev_desc,
  2. disk_partition_t *boot_part)
  3. {
  4. disk_partition_t kernel_part;
  5. ulong ramdisk_addr_r;
  6. ulong kernel_addr_r;
  7. ulong fdt_addr_r;
  8. int ramdisk_size;
  9. int kernel_size;
  10. int fdt_size;
  11. int ret;
  12. printf("\n## Booting Rockchip Format Image\n");
  13. ramdisk_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0);
  14. kernel_addr_r = env_get_ulong("kernel_addr_r", 16, 0);
  15. fdt_addr_r = env_get_ulong("fdt_addr_r", 16, 0);
  16. ret = part_get_info_by_name(dev_desc, PART_KERNEL, &kernel_part);
  17. if (ret < 0) {
  18. printf("Could not find kernel partition, ret=%d\n", ret);
  19. return -EINVAL;
  20. }
  21. kernel_size = read_rockchip_image(dev_desc, &kernel_part,
  22. (void *)kernel_addr_r);
  23. if (kernel_size < 0) {
  24. printf("Failed to read kernel image, ret=%d\n", ret);
  25. return -EINVAL;
  26. }
  27. ramdisk_size = read_rockchip_image(dev_desc, boot_part,
  28. (void *)ramdisk_addr_r);
  29. if (ramdisk_size < 0)
  30. ramdisk_size = 0;
  31. if (gd->fdt_blob != (void *)fdt_addr_r) {
  32. fdt_size = rockchip_read_dtb_file((void *)fdt_addr_r);
  33. if (fdt_size < 0) {
  34. printf("Failed to read fdt, ret=%d\n", fdt_size);
  35. return -EINVAL;
  36. }
  37. }
  38. env_set("bootm-no-reloc", "y");
  39. printf("fdt @ 0x%08lx (0x%08x)\n", fdt_addr_r, fdt_totalsize(fdt_addr_r));
  40. printf("kernel @ 0x%08lx (0x%08x)\n", kernel_addr_r, kernel_size);
  41. printf("ramdisk @ 0x%08lx (0x%08x)\n", ramdisk_addr_r, ramdisk_size);
  42. #if defined(CONFIG_ARM64)
  43. char cmdbuf[64];
  44. snprintf(cmdbuf, 64, "booti 0x%lx 0x%lx:0x%x 0x%lx",
  45. kernel_addr_r, ramdisk_addr_r, ramdisk_size, fdt_addr_r);
  46. run_command(cmdbuf, 0);
  47. #else
  48. /* We asume it's always zImage on 32-bit platform */
  49. ulong kaddr_c = env_get_ulong("kernel_addr_c", 16, 0);
  50. ulong kaddr_r, kaddr, ksize;
  51. if (kernel_addr_r && !kaddr_c) {
  52. kaddr_c = kernel_addr_r;
  53. kaddr_r = CONFIG_SYS_SDRAM_BASE;
  54. }
  55. if (!sysmem_free((phys_addr_t)kaddr_c)) {
  56. kaddr = kaddr_r;
  57. ksize = kernel_size * 100 / 45 ; /* Ratio: 45% */
  58. ksize = ALIGN(ksize, dev_desc->blksz);
  59. if (!sysmem_alloc_base(MEM_UNCOMP_KERNEL,
  60. (phys_addr_t)kaddr, ksize))
  61. return -ENOMEM;
  62. }
  63. boot_lmb_init(&images);
  64. images.ep = kernel_addr_r;
  65. images.initrd_start = ramdisk_addr_r;
  66. images.initrd_end = ramdisk_addr_r + ramdisk_size;
  67. images.ft_addr = (void *)fdt_addr_r;
  68. images.ft_len = fdt_totalsize(fdt_addr_r);
  69. do_bootm_linux(0, 0, NULL, &images);
  70. #endif
  71. return 0;
  72. }

二、镜像制作

2.1 misc.img
2.2 recovery.img

本节我们将参考Rockchip Linux SDK尝试自行制作一个recovery.img系统镜像,并将其烧录到NanoPC-T6开发板,用来实现该开发板的OTA升级功能。

recovery.img系统镜像由kernel + dtb + ramdisk三部分组成。

2.2.1 Kernrl
2.2.2 dtb
2.2.3 ramdisk

参考文章

[1] Mini2440uboot移植之源码分析start.S(一)]

[2] Mini2440之uboot移植之裁剪、分区与环境变量设置(五)

[3] Rockchip RK3399 - 移植linux 5.2.8

[4] Mini2440uboot移植之源码分析命令解析(五)

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

闽ICP备14008679号