RK3588 U-Boot到Linux内核参数传递机制详解 目录 概述 参数传递方式总览 设备树(FDT)传递机制 Rockchip ATAGS传递机制 bootm命令执行流程 RK3588平台特定实现 参数传递完整流程图 概述 在RK3588平台上,U-Boot向Linux内核传递参数是系统启动过程中的关键环节。RK3588作为ARM64架构的SoC,主要使用设备树(Flattened Device Tree, FDT)作为参数传递方式,同时Rockchip自定义了一套 ATAGS机制 用于内部bootloader阶段间的参数传递。
关键源文件位置 功能模块 主要源文件 bootm命令核心 common/bootm.c ARM架构特定 arch/arm/lib/bootm.c FDT处理 common/image-fdt.c FDT支持函数 common/fdt_support.c Rockchip ATAGS arch/arm/mach-rockchip/rk_atags.c RK3588平台 arch/arm/mach-rockchip/rk3588/rk3588.c 参数解析 arch/arm/mach-rockchip/param.c
参数传递方式总览 1. 主要参数传递方式 ┌─────────────────────────────────────────────────────────────────┐ │ U-Boot 参数传递架构 │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Rockchip │ │ 标准ARM64 │ │ │ │ ATAGS机制 │ │ FDT机制 │ │ │ │ (内部使用) │ │ (传给内核) │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────────────────────────────┐ │ │ │ 参数数据结构 │ │ │ │ - DDR内存信息 │ │ │ │ - ATF/OPTEE内存区域 │ │ │ │ - 启动设备信息 │ │ │ │ - 串口配置 │ │ │ │ - 固件版本信息 │ │ │ └─────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘2. ATAGS vs FDT对比 特性 Rockchip ATAGS 设备树(FDT) 用途 Rockchip内部bootloader间通信 向Linux内核传递硬件配置 位置 DDR基地址 + 2M - 8K 内核指定的内存地址 大小 最大8KB 可扩展,受限于内存 标准 Rockchip私有标准 ARM官方标准 数据格式 Tag列表结构 扁平化二进制树结构 内核识别 不直接识别 完全支持
设备树(FDT)传递机制 1. FDT在bootm命令中的处理流程 // common/bootm.c int do_bootm_states ( cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[ ] , int states, bootm_headers_t * images, int boot_progress) { // 状态机处理bootm的各个阶段 if ( states& BOOTM_STATE_START) ret= bootm_start ( cmdtp, flag, argc, argv) ; if ( ! ret&& ( states& BOOTM_STATE_FINDOS) ) ret= bootm_find_os ( cmdtp, flag, argc, argv) ; if ( ! ret&& ( states& BOOTM_STATE_FINDOTHER) ) ret= bootm_find_other ( cmdtp, flag, argc, argv) ; // ... 其他状态处理 } 2. FDT的获取与加载 // common/image-fdt.c int boot_get_fdt ( int flag, int argc, char * const argv[ ] , uint8_t arch, bootm_headers_t * images, char * * of_flat_tree, ulong* of_size) { // 从多个来源获取FDT: // 1. FIT镜像中的fdt节点 // 2. 独立的dtb文件 // 3. Legacy多组件镜像中的fdt部分 switch ( genimg_get_format ( buf) ) { case IMAGE_FORMAT_FIT: // FIT格式处理 if ( fit_check_format ( buf) ) { fdt_noffset= boot_get_fdt_fit ( images, fdt_addr, & fit_uname_fdt, & fit_uname_config, arch, & load, & len) ; } break ; // ... 其他格式 } } 3. FDT的重定位 // common/image-fdt.c int boot_relocate_fdt ( struct lmb * lmb, char * * of_flat_tree, ulong* of_size) { void * fdt_blob= * of_flat_tree; void * of_start= NULL ; char * fdt_high; ulong of_len= 0 ; // 考虑fdt_high环境变量 fdt_high= env_get ( "fdt_high" ) ; if ( fdt_high) { void * desired_addr= ( void * ) simple_strtoul ( fdt_high, NULL , 16 ) ; if ( ( ( ulong) desired_addr) == ~ 0UL ) { /* 0xFFFFFFFF表示使用原地fdt,不重定位 */ of_start= fdt_blob; } else if ( desired_addr) { /* 使用指定地址 */ of_start= ( void * ) ( ulong) lmb_alloc_base ( lmb, of_len, 0x1000 , ( ulong) desired_addr) ; } } // 使用fdt_open_into进行重定位 err= fdt_open_into ( fdt_blob, of_start, of_len) ; * of_flat_tree= of_start; * of_size= of_len; return 0 ; } 4. FDT的内容修复(fdt_fixup) // common/fdt_support.c int fdt_chosen ( void * fdt) { int nodeoffset; /* 查找或创建/chosen节点 */ nodeoffset= fdt_find_or_add_subnode ( fdt, 0 , "chosen" ) ; /* 设置bootargs */ str= board_fdt_chosen_bootargs ( fdt) ; if ( str) { err= fdt_setprop ( fdt, nodeoffset, "bootargs" , str, strlen ( str) + 1 ) ; } /* 设置stdout路径 */ return fdt_fixup_stdout ( fdt, nodeoffset) ; } int fdt_initrd ( void * fdt, ulong initrd_start, ulong initrd_end) { int nodeoffset; /* 找到/chosen节点 */ nodeoffset= fdt_find_or_add_subnode ( fdt, 0 , "chosen" ) ; /* 添加内存保留区域 */ fdt_add_mem_rsv ( fdt, initrd_start, initrd_end- initrd_start) ; /* 设置initrd起始和结束地址 */ is_u64= ( fdt_address_cells ( fdt, 0 ) == 2 ) ; fdt_setprop_uxx ( fdt, nodeoffset, "linux,initrd-start" , ( uint64_t ) initrd_start, is_u64) ; fdt_setprop_uxx ( fdt, nodeoffset, "linux,initrd-end" , ( uint64_t ) initrd_end, is_u64) ; return 0 ; } 5. ARM64架构的内核跳转 // arch/arm/lib/bootm.c static void boot_jump_linux ( bootm_headers_t * images, int flag) { # ifdef CONFIG_ARM64 void ( * kernel_entry) ( void