想省掉U-Boot Proper让SPL直接进内核?——Falcon模式配置与限制

电子说

1.4w人已加入

描述

问题场景

从按下电源键到显示开机画面,正常启动链要走BootROM→TPL→SPL→U-Boot→Kernel,光U-Boot Proper就要跑300ms。如果能让SPL加载完ATF后直接跳内核,把U-Boot Proper整个跳过,就可以大幅缩短启动时间。Falcon模式(CONFIG_SPL_KERNEL_BOOT)就是干这个的。本文对照RK3576源码,厘清Falcon模式的触发条件、跳转实现和必须注意的限制。

勘误说明:本文已对照RK3576 SDK实际代码审核修正。主要修正:spl_next_stage() 的实际实现与文章此前版本有较大差异——使用 goto out 模式而非 force_uboot 变量,使用 spl_rockchip_dnl_key_pressed() 而非 spl_key_pressed();spl_invoke_atf() 的Falcon分支在 common/spl/spl_atf.c 中而非 mach-rockchip/spl.c;Falcon模式下FIT的 firmware=atf 其实与非Falcon模式相同,差异在于loadables列表。

一、正常模式 vs Falcon模式

两种启动模式的完整对比:

u-boot

时间节省的主要来源

阶段 正常模式 Falcon模式 节省时间
BootROM ~100ms ~100ms
TPL ~200ms ~200ms
SPL加载FIT ~250ms ~250ms
U-Boot Proper ~300ms 跳过 300ms
Linux内核 ~2s ~2s
合计 ~2850ms ~2550ms ~300ms

对于用户感知而言,300ms是从"按下电源键"到"显示logo/闪灯"的体验分水岭。Falcon模式抢出的这300ms恰好覆盖了这个临界点。

二、Falcon模式的触发逻辑

SPL在 spl_next_stage() 中决定是否启用Falcon模式:

 

// arch/arm/mach-rockchip/spl.c — RK3576实际实现// 注意:CONFIG_SPL_KERNEL_BOOT 的保护范围从398行开始void spl_next_stage(struct spl_image_info *spl){    const char *reason[] = { "Recovery key", "Ctrl+c", "LowPwr", "Other" };    uint32_t reg_boot_mode;    int i = 0;
    // ── 条件1: 音量键(Recovery按键) ──    if (spl_rockchip_dnl_key_pressed()) {        i = 0;        spl->next_stage = SPL_NEXT_STAGE_UBOOT;        goto out;    }
    // ── 条件2: Ctrl+C 中断 ──    if (gd->console_evt == 0x03) {        i = 1;        spl->next_stage = SPL_NEXT_STAGE_UBOOT;        goto out;    }
    // ── 条件3: 低电量(CONFIG_SPL_DM_FUEL_GAUGE) ──    if (spl_is_low_power()) {        i = 2;        spl->next_stage = SPL_NEXT_STAGE_UBOOT;        goto out;    }
    // ── 条件4: boot_mode寄存器特殊值 ──    reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);    switch (reg_boot_mode) {    case BOOT_LOADER:    case BOOT_FASTBOOT:    case BOOT_CHARGING:    case BOOT_UMS:    case BOOT_DFU:        i = 3;        spl->next_stage = SPL_NEXT_STAGE_UBOOT;        break;    default:        // ★ 无任何条件命中 → Falcon模式启用        spl->next_stage = SPL_NEXT_STAGE_KERNEL;    }
out:    if (spl->next_stage == SPL_NEXT_STAGE_UBOOT)        printf("Enter uboot reason: %sn", reason[i]);}

 

关键点对比

实际代码中没有 force_uboot 布尔变量,而是使用 goto out 模式

实际代码中没有 spl_adc_key_pressed() 独立调用——ADC按键通过 spl_rockchip_dnl_key_pressed() 判定(对应 KEY_VOLUMEUP)

实际代码中没有 CONFIG_SPL_AB 分支——AB系统不修改 next_stage

三、Falcon模式启动决策树

u-boot

四、Falcon模式下的FIT加载差异

在Falcon模式下,SPL对FIT的加载行为有所不同:

u-boot

Falcon模式下的FIT差异

需要注意的是,firmware = "atf" 在正常模式和Falcon模式下是一样的——RK3576的FIT中firmware始终指向ATF。Falcon模式的真正差异在于:

loadables 列表中用 kernel 替换了 uboot

SPL在遍历loadables时遇到 os_type == IH_OS_U_BOOT 会 continue 跳过(spl_fit.c line 779-781)

内核的entry point设置为 0x40400000(与 kernel_addr_r 一致)

 

// Falcon模式的FIT:用kernel替换ubootimages {    kernel {        description = "Linux Kernel";        data = /incbin/("Image.lz4");        type = "kernel";        arch = "arm64";        compression = "lz4";        load = <0x40400000>;        entry = <0x40400000>;    };
    atf { /* 不变,仍为firmware */ };    tee { /* 不变 */ };    fdt { /* 不变 */ };};
configurations {    default = "config-1";    config-1 {        description = "RK3576 Falcon";        firmware = "atf";          // ★ 与正常模式相同        loadables = "kernel", "tee"; // kernel替换了uboot        fdt = "fdt";    };};

 

五、Falcon模式跳转实现

跳转到内核通过ATF间接完成:SPL先跳转ATF(BL31),ATF通过 entry_point_bl33 决定跳转到U-Boot还是Kernel:

 

// common/spl/spl.c — board_init_r 中的跳转决策switch (spl_image.os) {case IH_OS_ARM_TRUSTED_FIRMWARE:    // ★ spl_image.next_stage 决定了BL33的入口    printf("Jumping to %s via ATFn",           spl_image.next_stage == SPL_NEXT_STAGE_UBOOT ? "U-Boot" :           spl_image.next_stage == SPL_NEXT_STAGE_KERNEL ? "Kernel" :           "Unknown");    spl_invoke_atf(&spl_image);    break;}
// common/spl/spl_atf.c — spl_invoke_atf通用实现// 设置bl33_entry为spl_image->entry_point_bl33// 在Falcon模式下,entry_point_bl33被设为内核入口0x40400000// ATF通过smc返回后直接跳转到bl33_entry

 

核心机制

spl_fit.c 中遍历loadables时,U-Boot的 os_type == IH_OS_U_BOOT 被跳过(spl_fit.c:779-781)

剩下的kernel(os_type == IH_OS_LINUX 或未指定)被正常加载

kernel的load地址赋值给 spl_image->entry_point_bl33

ATF启动后检查 entry_point_bl33,发现不是U-Boot地址,跳转到内核入口

六、Falcon模式的应用场景

u-boot

七、Falcon模式配置

 

# RK3576 Falcon模式配置CONFIG_SPL_KERNEL_BOOT=y           # 启用Falcon模式CONFIG_SPL_INPUT=y                 # 输入检测(Ctrl+C等)CONFIG_SPL_ADC_KEY=y               # ADC物理按键CONFIG_SPL_DM_FUEL_GAUGE=y         # 电量检测(仅平板等设备)CONFIG_SPL_AB=y                    # AB系统(与Falcon共存)
# 内核镜像相关CONFIG_SPL_LOAD_FIT=y              # FIT加载CONFIG_SPL_LOAD_FIT_ADDRESS=0x42000000  # FIT缓冲地址CONFIG_SYS_SPL_MALLOC_SIZE=0x800000     # SPL堆大小(8MB)
 

 

审核编辑 黄宇

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分