基于RK3568打包TPL,SPL,UBoot镜像并运行:实战角度(持续更新)
1 RK3568框图boot流程上电ROM-32KB重映射到物理地址0xFFFF0000CPU从0xFFFF0000读取第一条指令并执行CPU开始运行BootROM中芯片原厂固化的启动逻辑从可用的存储设备中读取ID BLOCK数据并校验合法性存储设备访问顺序SPI Nor FlashSPI Nand FlashNand FlasheMMC FlashSD卡USB OTG注意这里的SPI Flash是FSPIFlash SPI是专用于SPI Flash启动通道的SPI不是普通通用的SPI0/SPI1/SPI2Nor/Nand Flash都是挂载在FSP上先使用Nor协议探测探测失败尝试Nand Flash注意RK3568有3个SDMMC接口使用dw-mshc一个EMMC控制器使用dwcmshcBootROM启动的时候检测的是eMMC上挂载是eMMC存储芯片还是SD卡。校验通过则从对应的存储设备中加载TPL(内存初始化程序到SRAM-64KB中执行完成DDR初始化DDR内存初始化完成后依次加载SPL-UBoot-Kernel到DDR内存中运行2 编译构建环境介绍2.1 源码目录rk3568_linux_sdk/ ├── Makefile # 顶层构建入口调用 build.sh 执行编译 ├── build.sh # 主构建脚本驱动整个 SDK 的编译流程 ├── rkflash.sh # 固件烧录脚本用于将镜像烧写到设备 ├── README.md # 项目说明文档 │ ├── app/ # 应用程序源码 ├── buildroot/ # Buildroot 构建系统轻量级嵌入式 Linux 构建框架 ├── common/ # 公共资源与脚本 ├── debian/ # Debian 根文件系统构建相关 ├── device/ # 设备相关配置 │ └── rockchip/ # Rockchip 平台特定配置板级配置、分区表等 ├── docs/ # 开发文档 ├── external/ # 外部第三方库/组件 ├── kernel/ # Linux 内核源码基于 Rockchip 分支 ├── output/ # 编译输出目录镜像、目标文件等 ├── prebuilts/ # 存放交叉编译工具链 ├── rkbin/ # Rockchip 闭源二进制文件DDR 初始化、BL31/ATF、M0 固件等 ├── rockdev/ # Rockchip 设备镜像打包与分区布局存放编译输出固件编译SDK后才会生成该文件夹 ├── tools/ # 主机端开发工具打包、签名、调试工具等 ├── u-boot/ # U-Boot 引导加载程序 └── yocto/ # Yocto 构建系统用于复杂嵌入式 Linux 发行版构建2.2 编译环境编译工具安装makecmakelibncurses-dev: 用于生成内核配置菜单bison 和 flex: 语法分析器生成工具编译配置SDK/device/rockchip/rk3566_rk3568/ alientek_rk3568_defconfig rockchip_defconfig rockchip_rk3568_evb1_ddr4_v10_32bit_defconfig rockchip_rk3568_evb1_ddr4_v10_defconfig rockchip_rk3568_evb8_lp4_v10_32bit_defconfig rockchip_rk3568_evb8_lp4_v10_defconfig rockchip_rk3568_uvc_evb1_ddr4_v10_defconfig 维度 内存差异DDR4 vs LPDDR4 架构位宽64位 vs 32_bit 板级定制差异官方EVB系列 vs Alientek(正点原子) UVC针对USB视频类应用编译参数./build.sh lunch选择板级配置文件 ./build.sh uboot编译u-boot ./build.sh kernel编译kernel ./build.sh modules编译内核模块 ./build.sh rootfs编译根文件系统 ./build.sh buildroot编译buildroot根文件系统 ./build.sh debian编译Debian根文件系统 ./build.sh recovery编译recovery ./build.sh all编译整个SDK包括 uboot、kernel、rootfs、recovery ./build.sh cleanall清理整个SDK ./build.sh firmware将镜像打包到rockdev目录 ./build.sh updateimg将所有镜像打包成一个update.img固件编译脚本SDK\device\rockchip\common\scripts\编译ubootmk-loader.sh → u-boot/make.sh → make all。产出u-boot 二进制 打包uboot镜像mk-loader.sh → u-boot/make.sh → pack_uboot/trust/loader_image。产出uboot.img, trust.img, *_loader_*.bin 编译kernelmk-kernel.sh → kernel/make.sh。产出vmlinux, modules, dtb 打包kernel镜像mk-kernel.sh, mk-ramdisk.sh, mk-fitimage.sh → boot.img 生成 。产出boot.img (或FIT格式) 打包recovery镜像mk-recovery.sh, mk-buildroot.sh, mk-ramdisk.sh → Buildroot编译 → ramdisk打包。产出recovery.img 打包misc镜像mk-misc.sh, mk-firmware.sh → 生成48KB misc.img misc.img 打包rootfs镜像mk-rootfs.sh, mk-buildroot.sh, mk-image.sh → Buildroot/Debian/Yocto编译。产出rootfs.img / rootfs.ext4 打包userdata镜像mk-firmware.sh, mk-image.sh, partition-helper → 遍历参数表 → 创建镜像。产出userdata.img执行编译选择配置./build.sh lunch选择alientek_rk3568_defconfig执行编译./build.sh uboot2.3 UBoot编译打包跟踪./build.sh uboot调用链./build.sh uboot └─ main(uboot) [build.sh:254-541] ├─ 环境变量初始化 (SCRIPTS_DIR, SDK_DIR, RK_OUTDIR等) ├─ run_build_hooks(init, uboot) [第427行] │ └─ run_hooks($RK_BUILD_HOOK_DIR, init, uboot) │ └─ 执行所有 init hook初始化配置、加载defconfig等 ├─ source $RK_CONFIG [第439行] ← 加载output/.config ├─ source $PARTITION_HELPER [第481行] ├─ run_build_hooks(pre-build, uboot) [第526行] ← pre-build阶段 ├─ run_build_hooks(build, uboot) [第533行] ← ★核心构建阶段 │ └─ run_hooks($RK_BUILD_HOOK_DIR, build, uboot) │ └─ 查找并执行 build hook 脚本 │ └─ device/rockchip/common/scripts/mk-loader.sh │ └─ build_hook uboot │ ├─ 导出 UMAKE./make.sh CROSS_COMPILE$RK_UBOOT_TOOLCHAIN │ ├─ TARGETuboot │ └─ build_uboot() │ ├─ cd u-boot/ │ ├─ 组装 UARGS │ ├─ $UMAKE $RK_UBOOT_CFG $RK_UBOOT_CFG_FRAGMENTS $UARGS │ │ └─ u-boot/make.sh defconfig [options] │ │ ├─ process_args() ← 解析参数/配置 │ │ ├─ prepare() ← 校验rkbin路径 │ │ ├─ select_toolchain() ← 选择交叉编译器 │ │ ├─ select_chip_info() ← 从.config识别芯片型号 │ │ ├─ fixup_platform_configure() │ │ ├─ select_ini_file() ← 选择RKBOOT/RKTRUST INI文件 │ │ ├─ sub_commands() ← 如果是uboot/loader/trust则打包 │ │ ├─ clean_files() │ │ ├─ make all --jobsN ← ★ U-Boot本身编译 │ │ └─ pack_images() │ │ ├─ pack_uboot_image() ← 打包uboot.img │ │ │ └─ scripts/uboot.sh │ │ ├─ pack_trust_image() ← 打包trust.img │ │ │ └─ scripts/atf.sh 或 scripts/tos.sh │ │ └─ pack_loader_image() ← 打包Loader.bin │ │ └─ scripts/loader.sh │ ├─ cd .. │ ├─ ln -rsf *_loader_*.bin → $RK_FIRMWARE_DIR/MiniLoaderAll.bin │ ├─ ln -rsf uboot.img → $RK_FIRMWARE_DIR/uboot.img │ ├─ ln -rsf trust.img → $RK_FIRMWARE_DIR/trust.img ← 如存在 │ └─ finish_build └─ run_build_hooks(post-build, uboot) [第540行] ← post-build阶段打包firmware输出成果物SDK/u-boot/uboot.imgU-Boot主镜像SDK/u-boot/trust.imgTrustATF/OP-TEE镜像SDK/u-boot/rk3568_loader_v*.binMiniLoader引导加载器。TPLddr.binRK私有闭源 SPLRK闭源或SPL开源2.3.1 ./build.sh uboot详细分析device\rockchip\common\scripts\build.shmain()run_build_hooks init $OPTIONS解析deconfig加载配置run_build_hooks pre-build $OPTIONS各模块检查配置、生成 .configrun_build_hooks build $OPTIONS匹配执行编译run_build_hooks post-build $OPTIONS编译产物打包为固件run_build_hooks根据参数查找指定目录下的.sh脚本对脚本进行排序按照顺序依次执行脚本执行成功则继续执行下一个脚本否则直接退出编译配置直接修改.config中的配置是没有作用的因为在解析deconfig和加载配置之后.config就会被覆盖掉TPLSPL打包script/loader.sh --ini rkbin/RKBOOT/RK3568MINIALL.initools/boot_merger RK3568MINIALL.iniRK3568MINIALL.ini描述TPL的路径和文件名描述SPL的路径和文件名描述usb下载插件的路径和文件名3 TPL闭源SPL闭源启动日志3.1 启动信息闭源TPL闭源SPL启动顺序TPL → SPL → U-Boot → ATF/OPTEE → KernelTPLSPL存储位置从启动日志可以看到SPL从0x4000扇区读取uboot镜像所以TPLSPL的存储区域不在0x4000扇区结合之前doc/README.rockchip一级tools/rksd.crknand.crkspi.c的实现对于不同的存储器TPLSPL存储在不同的位置eMMC/SD卡存储在0x40扇区SPI Flash从起始位置0x0读取。此时Flash接入的是FSPINAND从page0位置读取3.1.1 TPLDDR初始化物质基础DDR颗粒DDR ControllerDDR PHY基础参数BW32 Col10 Bk8 CS0 Row16 CS1 Row16 CS2 Die BW16 Size4096MB BW32DDR控制器总线位宽32bit Col10列地址宽度10bit2^10 1024列 Bk8Bank数量8个Bank CS0 Rw16行地址宽度16bit CS1 Row16行地址宽度16iit CS2片选信号数量2个片选CS0CS1 Die BW16单颗DDR颗粒DIE位宽16bit Size4096MB总DDR容量4GB时钟训练1560MHzchange to: 324MHz PHY drv:clk:36,ca:36,DQ:29,odt:0 vrefinner:24%, vrefout:41% dram drv:40,odt:0 clk skew:0x65 change to: 528MHz ... clk skew:0x58 change to: 780MHz ... clk skew:0x58 change to: 1560MHz(final freq) ... vref_ca:00000071 clk skew:0x30DDR PHY训练本质寻找 DQ 数据相对于 DQS 选通时钟的有效采样窗口Eye Diagram 眼图窗口每一组 DQS 管理 4 根 DQ 信号LPDDR4X4 DQS Lane每 Lane 4bit DQ16bit/CScs0 / cs1 对应两个 DDR 片选独立训练互不干扰所有数值单位PHY 内部延迟步长delay taptap 值tap 越大代表相位偏移越大Read Training读训练SoC 接收 DDR 发来的数据调节 DQS 采样时钟相位在窗口中间位置采样 DQDQS0:0x32, DQS1:0x32, DQS2:0x32, DQS3:0x2eDQS0~DQS3 四组差分选通信号各自独立最优相位min/mid/max/rang含义单根 DQ 的眼图扫描结果range代表有效眼图窗口宽度窗口越大信号裕量越大高低温、电压波动下越稳定Wirte Training写训练SoC 发送数据给 DDR 颗粒调节 DQ 数据相对于 DQS 随路时钟的发送相位保证 DDR 颗粒端满足建立 / 保持时间DQS0:0x27, DQS1:0x19, DQS2:0x19, DQS3:0xamin/mid/max/rang含义单根 DQ 的眼图扫描结果range代表有效眼图窗口宽度窗口越大信号裕量越大高低温、电压波动下越稳定DDR PHY训练日志cs 0: the read training result: DQS0:0x32, DQS1:0x32, DQS2:0x32, DQS3:0x2e, min : 0xb 0xd ... mid :0x26 0x29 ... max :0x42 0x45 ... range:0x37 0x38 ... the write training result: DQS0:0x27, DQS1:0x19, DQS2:0x19, DQS3:0xa, min :0x6a 0x70 ... mid :0x87 0x8b ... max :0xa4 0xa6 ... range:0x3a 0x36 ... cs 1: the read training result: DQS0:0x33, DQS1:0x33, DQS2:0x33, DQS3:0x30, min : 0xb 0xd ... mid :0x26 0x29 ... max :0x42 0x45 ... range:0x37 0x38 ... the write training result: DQS0:0x27, DQS1:0x19, DQS2:0x19, DQS3:0xa, min :0x6b 0x71 ... mid :0x88 0x8c ... max :0xa6 0xa8 ... range:0x3b 0x37 ...CA训练Command/Address 地址命令总线本质针对地址命令通路保证 DDR 颗粒能够正确采样 SoC 发出的地址与命令原理SoC DDR PHY 不断调整 CA 信号相对于 DDR CLK 时钟的输出相位来回扫描相位相位太超前 → DDR 无法正确采样命令报错相位太滞后 → DDR 同样采样失败找到【能够稳定识别地址命令】的相位区间 [min, max]。PHY 最终选用 mid 中点位置输出 CA 信号建立充足的建立 / 保持时间CA训练日志CA Training result: cs:0 min :0x51 0x4d 0x47 0x40 0x47 0x40 0x4b ,0x4b 0x46 0x42 0x3a 0x3f 0x3b 0x4b , cs:0 mid :0x8d 0x8c 0x84 0x81 0x84 0x7f 0x7b ,0x88 0x86 0x7f 0x79 0x7c 0x7b 0x7a , cs:0 max :0xc9 0xcb 0xc2 0xc2 0xc2 0xbe 0xac ,0xc6 0xc7 0xbc 0xb8 0xb9 0xbb 0xaa , cs:0 range:0x78 0x7e 0x7b 0x82 0x7b 0x7e 0x61 ,0x7b 0x81 0x7a 0x7e 0x7a 0x80 0x5f , cs:1 min :0x4f 0x56 0x47 0x47 0x48 0x45 0x4d ,0x4c 0x4d 0x43 0x43 0x40 0x44 0x4c , cs:1 mid :0x90 0x91 0x86 0x84 0x88 0x81 0x7f ,0x8c 0x89 0x83 0x7d 0x7f 0x80 0x7c , cs:1 max :0xd1 0xcc 0xc6 0xc2 0xc8 0xbe 0xb1 ,0xcd 0xc6 0xc3 0xb8 0xbf 0xbd 0xad , cs:1 range:0x82 0x76 0x7f 0x7b 0x80 0x79 0x64 ,0x81 0x79 0x80 0x75 0x7f 0x79 0x61 ,3.1.2 SPL初始化启动顺序SPL → ATF (BL31 EL3) → OPTEE (BL32) → U-Boot (BL33 Normal World)镜像加载日志U-Boot SPL board init U-Boot SPL 2017.09-gaaca6ffec1-211203 #zzz (Dec 03 2021 - 18:42:16) unknown raw ID phN unrecognized JEDEC id bytes: 00, 00, 00 //从MMC2启动 Trying to boot from MMC2 MMC error: The cmd index is 1, ret is -110 Card did not respond to voltage select! mmc_init: -95, time 10 spl: mmc init failed with error: -95 //从MMC1启动 Trying to boot from MMC1 SPL: A/B-slot: _a, successful: 0, tries-remain: 7 Trying fit image at 0x4000 sector ## Verified-boot: 0 ## Checking atf-1 0x00040000 ... sha256(6204b6f381...) OK ## Checking uboot 0x00a00000 ... sha256(d4bf748090...) OK ## Checking fdt 0x00b45ed8 ... sha256(036cca5880...) OK ## Checking atf-2 0xfdcc1000 ... sha256(5563d929da...) OK ## Checking atf-3 0x0006a000 ... sha256(b04372ab0f...) OK ## Checking atf-4 0xfdcce000 ... sha256(2f8839c803...) OK ## Checking atf-5 0xfdcd0000 ... sha256(b46eaa95b8...) OK ## Checking atf-6 0x00068000 ... sha256(6e9d32ba23...) OK ## Checking optee 0x08400000 ... sha256(66bbd17352...) OK Jumping to U-Boot(0x00a00000) via ARM Trusted Firmware(0x00040000) Total: 236.477 ms //跳转到ARM Trusted Firmware执行 INFO: Preloader serial: 2 NOTICE: BL31: v2.3():v2.3-365-gae7c295ca:derrick.huang NOTICE: BL31: Built : 15:37:13, May 17 2022 INFO: GICv3 without legacy support detected. INFO: ARM GICv3 driver initialized in EL3 INFO: pmu v1 is valid 220114 INFO: dfs DDR fsp_param[0].freq_mhz 1560MHz INFO: dfs DDR fsp_param[1].freq_mhz 324MHz INFO: dfs DDR fsp_param[2].freq_mhz 528MHz INFO: dfs DDR fsp_param[3].freq_mhz 780MHz INFO: Using opteed sec cpu_context! INFO: boot cpu mask: 0 INFO: BL31: Initializing runtime services INFO: BL31: Initializing BL32 //OP-TEE程序执行 I/TC: I/TC: OP-TEE version: 3.13.0-641-g4167319d3 #hisping.lin (gcc version 10.2.1 20201103 (GNU Toolchain for the A-profile Architecture 10.2-2020.11 (arm-10.16))) #8 Wed Mar 16 15:14:56 CST 2022 aarch64 I/TC: Primary CPU initializing I/TC: Primary CPU switching to normal world boot INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address 0xa00000 INFO: SPSR 0x3c9镜像加载MMC2/MMC1A/B-soltSPL分别从MMC2SD卡和MMC1eMMC启动最终MMC1启动成功如何理解MMC2和MMC1它们分别对应什么SoC上的什么硬件IPRK A/B 分区机制当前启动槽位为slot_a本次启动成功标记为 0尚未完成成功计数剩余重试次数 7 次升级失败时依靠重试计数实现回滚从eMMC的0x4000扇区读取FIT打包镜像trust分区内fit镜像包含ATF、OP-TEE、U-Boot、DTB0x4000是uboot.img镜像烧录的位置uboot.img镜像打包的规则是什么镜像校验和加载到DDR校验顺序ATF-1ubootfdtATF-2ATF-3ATF-4ATF-5ATF-6OP-TEE说明镜像打包顺序大概也是如此镜像加载到DDRatf-1 0x00040000uboot 0x00a00000fdt 0x00b45ed8atf-2 0xfdcc1000atf-3 0x0006a000atf-4 0xfdcce000atf-5 0xfdcd0000atf-6 0x00068000optee 0x08400000SPL跳转ATFJumping to U-Boot(0x00a00000) via ARM Trusted Firmware(0x00040000)ATF BL31EL3安全世界OP-TEE BL32启动3.2 关键概念理解3.2.1 ARM安全世界Exception Levels异常等级EL0无特权执行用于运行普通的应用程序无法访问任何系统配置寄存器所有对系统资源的访问都受到严格限制EL1操作系统内核可以访问管理内存管理单元MMU、处理中断等所需的系统寄存器EL2虚拟机监视器提供对虚拟化的支持可以访问控制第二级地址翻译Stage 2 MMU的寄存器用于管理多个虚拟机EL3安全监视器等级最高可以访问所有系统控制资源ATF的核心部分就运行在EL3负责安全世界和普通世界之间的切换异常切换单行道规则向上切换通过异常请求更高级的服务。EL0-EL1SVC(Supervisor Call)EL1-EL2HVC(Hypervisor Call)EL2-EL3SMC(Secure Monitor Call)向下切换通过异常返回回到低特权等级EL0-EL3需要硬件授权SCR_EL3.SMDEL1-EL3架构允许EL0-EL2架构允许。Secure World和Normal WorldSecure World运行一个可信操作系统如OP-TEE专门处理指纹、支付等敏感任务Normal World运行Linux/Android等富操作系统功能丰富但不被信任处理敏感信息两个世界在同一颗CPU核心上分时运行通过运行在EL3的ATF进行安全切换TurstZone隔离出安全内存外设中断是贯穿整个SoC系统级芯片的系统级安全架构这样一个架构由哪些关键模块组成核心思想硬件强制隔离给硬件打上Secure World的标签只有来自Secure World的请求才能访问硬件如何隔离CPU内存存储器电源时钟中断寄存器物质基础NS(Non-Secure Bit)AXI系统总线在每个读写信道增加一个额外的NS控制信号。CPU在Normal World执行时发出的所有内存访问请求NS都会被硬件强制设为1相反在Secure World发出的请求NS位为0。总线上从设备会检查请求的NS位如果非安全请求视图访问被标记为安全的内存区域硬件会直接拒绝这次访问地址空间控制器(TZASC)TZASC是一个硬件过滤器位于总线与内存之间。他将物理内存划分为安全区域和非安全区域。只有Secure World的请求才能访问安全内存区域安全外设与中断通过AXI-to-APB桥等硬件逻辑可以配置某些外设如键盘、加解密引擎为“安全外设”通过通用中断控制器GIC可以将中断配置为安全或非安全ATFARM Trusted Firmware运行在EL3管理安全世界的物质配置TZASC配置GIC管理CPU上下文Secure World和Normal World切换时ATF需要保存和恢复CPU的寄存器状态通过SMC调用提供ATF服务Normal World需要ATF的服务会执行一条**SMCSecure Monitor Call**指令指令产生一个异常将CPU控制器交给EL3的ATFATF根据SMC的ID执行相应服务然后返回结果ATF都提供了哪些服务如何获取这些服务PSCI电源状态协调接口用于管理CPU的开关、休眠等OP-TEE为可信应用Trusted Application提供以下安全运行环境强大的隔离性通过硬件TrustZone将TA与普通实际的所有软件彻底隔离。即使普通世界被攻破也无法访问TA的代码和数据安全的执行环境确保TA执行时的上下文不被普通世界或其他TA窥探或修改可信的通信通道定义标准API确保普通世界的CA与TA的每一次通信都是安全可控的安全的存储服务提供加密存储服务TA可在此安全地存储密钥等敏感数据防止被普通世界读取硬件信任根BL1 - BL2 - BL31 - BL32 - BL33Boot Loader信任链逐级验证下一级软件的签名任何一级验证失败启动过程都会停无信任链系统不加验证地执行任何代码一旦引导程序被恶意替换整个系统就会被攻击者完全控制BL1BootROM信任根。加载并验证下一个镜像BL2的完整性和签名BL2TPLSPL。可信启动固件运行安全世界完成DDR初始化BL31EL3 Runtime Firmware。BL32Secure-EL1 Playlaod如OP-TEE。通常是一个可信执行环境TEE 的操作系统。运行在安全世界为可信应用TA 提供安全的运行环境BL33Non-trusted Firmware如U-Boot。职责是加载并启动操作系统32位和64位架构差异32位没有ATF可以选择集成OP-TEEBL1 - BL2 - BL32 - BL3364位完整信任链BL1 - BL2 - BL31 - BL32 - BL333.3.2 OP-TEE详解是什么OP-TEE是运行在安全世界的软件TrustZone是它的物质基础OP-TEE OS运行在安全世界的EL1特权级是TEE的操作系统OP-TEE与TAs(Trusted Applications)相辅相成OP-TEE通过GlobalPlatform TEE Internal Core API向TAs提供服务OP-TEE Client运行在Normal World提供TEE Client API库libteec.so供普通客户但应用开源网站OP-TEE操作系统https://github.com/OP-TEE/optee_os运行在安全世界Secure World的可信操作系统TEE OS 核心OP-TEE客户端https://github.com/OP-TEE/optee_client运行在普通世界Normal World用户空间的客户端库提供TEE Client APIOP-TEE Linux驱动https://github.com/OP-TEE/optee_linuxdriver运行在Linux内核空间的设备驱动处理普通世界与安全世界间的通信OP-TEE 示例应用https://github.com/linaro-swg/optee_examples包含示例性质的客户端应用CA和可信应用TAOP-TEE 测试套件https://github.com/OP-TEE/optee_testxtest测试套件用于验证OP-TEE的功能和API一致性应用场景OP-TEE已被广泛应用于全盘加密、安全存储密钥、区块链钱包3.3.3 A/B分区A/B分区是什么A/B System即把系统固件分为两份系统可以从其中一个slot上启动当一份启动失败后可以从另一份上启动升级时可以直接将固件拷贝到另一个slot上而无需进入系统升级模式把带升级的镜像直接写入备份slot下次启动的标记从新的系统启动A/B分区启动的三个物质层面编译配置支持A/B分区检测分区表在制作存储器镜像的时候预留两个分区用来存储系统固件启动代码检测分区固件选择从某个分区启动Preloader A/B分区物质基础对于preloader也就是TPLSPL。这里就需要给uboot.img准备两份分区来存放uboot.imguboot A/B分区物质基础对于uboot去启动kernel。内核镜像需备份//uboot配置 CONFIG_AVB_LIBAVBy CONFIG_AVB_LIBAVB_ABy CONFIG_AVB_LIBAVB_ATXy CONFIG_AVB_LIBAVB_USERy CONFIG_RK_AVB_LIBAVB_USERy CONFIG_ANDROID_ABy //分区表的分区必须增加后缀_a 和_b FIRMWARE_VER:8.1 MACHINE_MODEL:RK3326 MACHINE_ID:007 MANUFACTURER: RK3326 MAGIC: 0x5041524B ATAG: 0x00200800 MACHINE: 3326 CHECK_MASK: 0x80 PWR_HLD: 0,0,A,0,1 TYPE: GPT CMDLINE: mtdpartsrk29xxnand:0x000020000x00004000(uboot_a),0x000020000x00006000(uboot_b) ,0x000020000x00008000(trust_a),0x000020000x0000a000(trust_b),0x000010000x0000c 000(misc),0x000010000x0000d000(vbmeta_a),0x000010000x0000e000(vbmeta_b),0x00020 0000x0000e000(boot_a),0x000200000x0002e000(boot_b),0x001000000x0004e000(system _a),0x003000000x0032e000(system_b),0x001000000x0062e000(vendor_a),0x001000000x 0072e000(vendor_b),0x000020000x0082e000(oem_a),0x000020000x00830000(oem_b),0x00 100000x00832000(factory),0x000080000x842000(factory_bootloader),0x000800000x00 8ca000(oem),-0x0094a000(userdata)3.3.4 DDR内存物质基础组成存储单元本质是电子开关电容DDR芯片Bank组成。每个Bank由多个Row组成每个Row由多个Column组成信号DQ(数据线)DQS(数据选通)CA(命令/地址)CK(时钟)DDR初始化对抗物理差异时钟频率选择CA粗调使用默认延迟值。通常由PCB等长布线保证MRS配置Mode Register Set。配置模式寄存器告诉DRAM芯片CAS延迟是多少突出长度是多少写延迟是多少ZQ校准控制器通过MRS命令触发DRAM内部的ZQ校准单元。DRAM会调整其DQ引脚的输出驱动强度和ODT(片上终端电阻)读训练控制器依赖CA粗调发送读命令从阵列中读出已知数据PHY逐步调整读DQS的延迟扫描出DQ数据稳定的串口选取中心点写训练依赖读路径已完成校准。采用写-回读-校验的方式调整写DQ相对写DQS的发送延迟CA训练对CA信号线进行精细校准时钟频率选择CLK是DDR芯片内部的全局心跳和时间基准驱动内部时钟树CLK进入DDR芯片内部通过内部时钟树分布到命令解码器、地址锁存器、模式寄存器等所有同步逻辑逻辑电路的触发器中命令/地址的采样基准DQS采样训练DQS用于DQ总线在极高频率下信号从控制器到DRAM需要时间。CLK无法准确预测数据何时到达DQS和DQ从控制器同时出发经过相同额物理路ing延迟伴随数据一起达到接收端DQS训练的目的就是让DQS和DQ的信号保持同步避免相位延迟导致数据采样错误4 开源SPL实战4.1 SPL功能SPL相关内容读取FIT镜像并校验跳转ATF执行跳转OP-TEE执行实战项目内容掌握SPL镜像打包方式增加FIT镜像校验——能否增加自定义校验掌握ATF集成方法和应用场景掌握OP-TEE集成方法和应用场景掌握A/B分区烧录和跳转策略结合实际使用场景进行SPL特化问题锚点TPL中是否包含二进制设备树若存在打包规则是如何定义的SPL中是否包含二进制设备树若存在打包规则是如何定义的4.2 TPL(闭源)SPL(开源)项目规划SPL编译打包流程验证开启SPL相关的编译生成修改TPLSPL打包规则使用开源SPLrkbin/RKBOOT/RK3568MINIALL.ini下载TPLSPL MiniLoaderAll.bin查看日志进行验证SPL功能控制仅针对我想实现的功能进行修改镜像加载和校验跟踪校验了镜像HASH值源码尝试增加身份签名校验A/B分区通过直接在代码中控制读取A或B分区实现代码控制再修改代码实现A/B分区自主选择镜像跳转目前镜像转交给了ATF由ATF跳转到OP-TEE再跳转到U-Boot执行尝试能否自定义编译ATF尝试能否自定义编译OP-TEE尝试能否跳过ATF直接进入OP-TEE尝试能否跳过OP-TEE直接进入U-Boot尝试跳过ATF和OP-TEE直接进入U-Boot4.3 项目实战SPL流程MVP4.4 项目实战SPL镜像加载和校验4.5 项目实战A/B分区备份UBoot4.6 项目实战镜像跳转5 U-Boot打包运行实战

相关新闻

电商系统技术栈选型:Spring Boot+微服务+Kafka实战

电商系统技术栈选型:Spring Boot+微服务+Kafka实战

1. 电商场景下的技术栈选型逻辑在电商系统的技术面试中,面试官最关注的是候选人能否理解技术选型背后的业务考量。以我参与过的多个电商平台重构经验来看,Spring Boot 微服务 Kafka的组合绝非偶然,而是经过多重验证的黄金方案。电商业务的典…

2026/10/15 22:27:57 阅读更多 →
BQ27Z846 ManufacturerAccess命令实战:从安全监控到电池寿命分析

BQ27Z846 ManufacturerAccess命令实战:从安全监控到电池寿命分析

1. 项目概述:深入BQ27Z846的“后门”命令如果你正在开发或维护基于德州仪器(TI)BQ27Z846芯片的电池管理系统(BMS),那么你一定绕不开一个核心话题:ManufacturerAccess命令。这可不是普通的SMBus标…

2026/10/15 17:40:06 阅读更多 →
C语言分支与循环语句(一)

C语言分支与循环语句(一)

一、内容提要 C语言是结构化的程序设计语言,这里的结构指的是顺序结构、选择结构、循环结构。生活中的常见的事物都可以拆分为这三种结构或者是这三种结构的组合。C语言可以通过if、switch实现分支结构(顺序结构、选择结构),通过f…

2026/10/15 21:01:20 阅读更多 →

最新新闻

SpringBoot+Vue党员教育管理系统设计与实现:从需求分析到部署排坑

SpringBoot+Vue党员教育管理系统设计与实现:从需求分析到部署排坑

最近刚把一个计算机毕业设计项目完整跑通,用的是 SpringBoot Vue 的组合,题目是“党员教育和管理系统”,也可以理解成一套党校线上指导平台。如果你正好在选毕业设计题目,或者公司内部需要做一套线上学习培训系统,这个…

2026/10/15 22:27:31 阅读更多 →
CC Switch 多环境切换实战:把 Claude Code 的 endpoint 改到 TaoToken

CC Switch 多环境切换实战:把 Claude Code 的 endpoint 改到 TaoToken

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:27:31 阅读更多 →
基于SSM+Vue的景区容灾管理系统设计与实现

基于SSM+Vue的景区容灾管理系统设计与实现

又到一年毕业设计的季节,后台私信里很多同学都在问差不多的一个问题:SSM Vue 到底做什么题目比较稳?既要工作量够,又要技术栈主流,还得好写论文、好答辩。今天想拆解的,正是这类题目里很有代表性的一类——…

2026/10/15 22:27:31 阅读更多 →
Vue看板娘教程详细版:用TaoToken统一Key接入Live2D交互组件

Vue看板娘教程详细版:用TaoToken统一Key接入Live2D交互组件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 22:27:31 阅读更多 →
中文短文本场景下可调试的Transformer Encoder实战

中文短文本场景下可调试的Transformer Encoder实战

1. 这不是又一篇“Transformer原理科普”,而是一份NLP工程师的实战手记你点开这个标题,大概率是刚学完《Attention Is All You Need》那篇论文,或者被BERT、GPT这些词轰炸得有点晕,想找个能真正上手、能调参、能看懂模型内部在“想…

2026/10/15 22:27:31 阅读更多 →
wow.js滚动触发动画原理与实战:IntersectionObserver轻量封装

wow.js滚动触发动画原理与实战:IntersectionObserver轻量封装

简介:这是一份轻量级网页滚动动画实现方案,面向前端初学者与网页设计师,解决网站静态内容缺乏视觉动效、用户交互体验平淡的问题。资源基于流行的wow.js库封装,通过CSS类绑定实现元素进入视口时的自动动画触发,支持淡入…

2026/10/15 22:26:22 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →