装修网站开发思路,高端制造,常州网站的优化,网站建设分金手指专业十七第一部分 bootm.c 整体呈现/* * * * - 添加了prep子命令支持* SPDX-License-Identifier: GPL-2.0* 授权标识符: GPL-2.0*/
/* 包含必要的头文件 */
#include common.h /* U-Boot通用头文件#xff0c;包含全局数据结构和基本函数声明 */
#include * 授权标识符: GPL-2.0 */ /* 包含必要的头文件 */ #include common.h /* U-Boot通用头文件包含全局数据结构和基本函数声明 */ #include command.h /* 命令处理相关头文件定义命令结构体和注册函数 */ #include image.h /* 镜像处理头文件包含各种镜像格式的定义和操作函数 */ #include u-boot/zlib.h /* zlib压缩库头文件用于内核解压 */ #include asm/byteorder.h /* 字节序处理头文件定义大小端转换函数 */ #include libfdt.h /* Flattened Device Tree库头文件用于设备树操作 */ #include mapmem.h /* 内存映射头文件提供物理地址到虚拟地址的转换函数 */ #include fdt_support.h /* 设备树支持头文件包含U-Boot特有的设备树辅助函数 */ #include asm/bootm.h /* ARM架构的bootm相关头文件包含启动特定定义 */ #include asm/secure.h /* ARM安全模式相关头文件用于TrustZone等安全功能 */ #include linux/compiler.h /* Linux编译器属性头文件包含__weak等编译器指令 */ #include bootm.h /* 通用bootm头文件包含bootm的核心数据结构 */ #include vxworks.h /* VxWorks RTOS支持头文件用于VxWorks启动 */ #ifdef CONFIG_ARMV7_NONSEC /* 如果配置了ARMv7非安全模式支持 */ #include asm/armv7.h /* ARMv7架构特定头文件包含协处理器操作函数 */ #endif /* * 声明全局数据指针 * DECLARE_GLOBAL_DATA_PTR: 声明一个指向全局数据结构的指针gd * 设计模式: 单例模式 - 全局数据指针提供对U-Boot全局状态的唯一访问点 */ DECLARE_GLOBAL_DATA_PTR; /* * 静态变量定义 * params: ATAG参数列表指针用于向Linux内核传递启动参数 * 设计模式: 享元模式 - ATAG参数结构被多个函数共享使用 */ static struct tag *params; /** * brief 获取当前堆栈指针 * * 通过内联汇编获取当前堆栈指针的值 * * return ulong 当前堆栈指针值 * * 性能分析: * - 使用内联汇编直接读取SP寄存器开销极小 * - 单条指令完成无函数调用开销 */ static ulong get_sp(void) { ulong ret; /* 返回值变量 */ asm(mov %0, sp : r(ret) : ); /* 内联汇编将堆栈指针SP的值移动到ret变量 */ return ret; /* 返回堆栈指针值 */ } /** * brief 为Linux内核预留内存区域 * * 预留内核启动所需的内存空间特别是命令行和板级信息区域 * 该区域应尽可能高在CONFIG_SYS_BOOTMAPSZ范围内 * 但位于未使用的内存中即远低于当前堆栈指针 * * param lmb 内存块管理器指针 * * 设计模式: 策略模式 - 根据不同的内存布局策略预留空间 * 性能分析: * - 调用get_sp()获取当前堆栈指针开销小 * - 计算预留区域进行边界检查 * - lmb_reserve()操作通常较快但可能涉及内存管理数据结构更新 */ void arch_lmb_reserve(struct lmb *lmb) { ulong sp; /* 堆栈指针变量 */ /* * 启动(Linux)内核镜像 * * 为命令行和板级信息分配空间 - * 地址应尽可能高在kernel可达范围内(参考CONFIG_SYS_BOOTMAPSZ设置) * 但位于未使用的内存中这意味着要远低于当前堆栈指针 */ sp get_sp(); /* 获取当前堆栈指针 */ debug(## Current stack ends at 0x%08lx , sp); /* 调试输出当前堆栈结束地址 */ /* 为安全起见将sp向下调整4KB */ sp - 4096; /* * 预留内存区域从sp到DRAM区域结束 * 参数1: lmb管理器 * 参数2: 起始地址sp * 参数3: 大小 DRAM结束地址 - sp */ lmb_reserve(lmb, sp, gd-bd-bi_dram[0].start gd-bd-bi_dram[0].size - sp); } /** * brief 打印启动消息并执行清理操作 * * 在跳转到内核前打印启动消息执行必要的清理操作 * 如断开USB连接、清理缓存等 * * param fake 非0值表示模拟运行只执行除实际启动外的所有操作 * * 设计模式: 模板方法模式 - 定义启动前准备的标准流程 * 性能分析: * - 字符串输出有I/O开销 * - bootstage标记和报告有日志记录开销 * - 清理操作可能涉及缓存刷新等耗时操作 */ static void announce_and_cleanup(int fake) { /* 打印启动信息如果是模拟运行则特别标注 */ printf(\nStarting kernel ...%s\n\n, fake ? (fake run for tracing) : ); /* 标记启动阶段启动移交阶段 */ bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, start_kernel); #ifdef CONFIG_BOOTSTAGE_FDT /* 如果配置了bootstage设备树支持 */ bootstage_fdt_add_report(); /* 将bootstage报告添加到设备树 */ #endif #ifdef CONFIG_BOOTSTAGE_REPORT /* 如果配置了bootstage报告 */ bootstage_report(); /* 生成bootstage报告 */ #endif #ifdef CONFIG_USB_DEVICE /* 如果配置了USB设备支持 */ udc_disconnect(); /* 断开USB设备连接 */ #endif cleanup_before_linux(); /* Linux启动前清理操作如缓存刷新 */ } /** * brief 设置起始标签(ATAG_CORE) * * 初始化ATAG参数列表设置核心标签 * * param bd 板级数据指针 * * 设计模式: 建造者模式 - 逐步构建ATAG参数列表 * 性能分析: * - 直接内存赋值开销极小 * - 标签指针更新操作快速 */ static void setup_start_tag (bd_t *bd) { /* 从板级数据中获取ATAG参数存储地址 */ params (struct tag *)bd-bi_boot_params; /* 设置标签头ATAG_CORE表示核心标签 */ params-hdr.tag ATAG_CORE; /* 设置标签大小使用tag_size宏计算 */ params-hdr.size tag_size (tag_core); /* 设置核心标签的具体字段 */ params-u.core.flags 0; /* 标志位清零 */ params-u.core.pagesize 0; /* 页面大小设为0由内核决定 */ params-u.core.rootdev 0; /* 根设备设为0 */ /* 移动到下一个标签位置 */ params tag_next (params); } /** * brief 设置内存标签(ATAG_MEM) * * 为每个DRAM bank设置内存标签 * * param bd 板级数据指针 * * 设计模式: 迭代器模式 - 遍历所有DRAM banks * 性能分析: * - 循环次数由CONFIG_NR_DRAM_BANKS决定通常较小(1-4) * - 每次循环执行固定次数的赋值操作开销可预测 */ static void setup_memory_tags(bd_t *bd) { int i; /* 循环计数器 */ /* 遍历所有配置的DRAM banks */ for (i 0; i CONFIG_NR_DRAM_BANKS; i) { /* 设置标签头ATAG_MEM表示内存标签 */ params-hdr.tag ATAG_MEM; /* 设置标签大小 */ params-hdr.size tag_size (tag_mem32); /* 设置内存起始地址和大小 */ params-u.mem.start bd-bi_dram[i].start; /* DRAM起始地址 */ params-u.mem.size bd-bi_dram[i].size; /* DRAM大小 */ /* 移动到下一个标签位置 */ params tag_next (params); } } /* 外部变量声明启动类型 */ extern int starttype; /** * brief 设置命令行标签(ATAG_CMDLINE) * * 将内核命令行参数打包到ATAG_CMDLINE标签中 * * param bd 板级数据指针 * param commandline 命令行字符串 * * 设计模式: 装饰器模式 - 在基础命令行上添加启动类型信息 * 性能分析: * - 字符串操作(strlen, strcpy, strcat)有O(n)复杂度 * - 命令行长度通常有限开销可控 */ static void setup_commandline_tag(bd_t *bd, char *commandline) { char *p; /* 命令行处理指针 */ char *s NULL; /* 启动类型字符串 */ if (!commandline) /* 如果命令行为空则直接返回 */ return; /* 跳过前导空白字符 */ for (p commandline; *p ; p); /* * 跳过不存在的命令行这样内核将仍然使用其默认命令行 * 同时检查starttype是否小于0特殊条件 */ if ((*p \0) (starttype 0)) return; /* 根据starttype添加相应的启动类型参数 */ if(starttype 0) s starttypemain; /* 主启动类型 */ else s starttypebackup; /* 备份启动类型 */ /* 设置标签头ATAG_CMDLINE表示命令行标签 */ params-hdr.tag ATAG_CMDLINE; /* 计算标签大小头部大小 命令行长度 启动类型字符串长度 1(终止符) 4字节对齐 */ params-hdr.size (sizeof (struct tag_header) strlen (p) strlen (s) 1 4) 2; /* 复制命令行字符串 */ strcpy (params-u.cmdline.cmdline, p); /* 追加启动类型字符串 */ strcat (params-u.cmdline.cmdline, s); /* 移动到下一个标签位置 */ params tag_next (params); } /** * brief 设置initrd标签(ATAG_INITRD2) * * 设置初始RAM磁盘的位置和大小 * * param bd 板级数据指针 * param initrd_start initrd起始地址 * param initrd_end initrd结束地址 * * 性能分析: * - 简单的算术计算和赋值操作开销极小 * - initrd_end - initrd_start计算大小快速 */ static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) { /* * ATAG_INITRD节点告诉内核压缩的ramdisk的位置 * 实际上ATAG_RDIMG是更好的名字 */ params-hdr.tag ATAG_INITRD2; /* 设置标签类型为INITRD2 */ params-hdr.size tag_size (tag_initrd); /* 设置标签大小 */ /* 设置initrd的起始地址和大小 */ params-u.initrd.start initrd_start; /* 起始地址 */ params-u.initrd.size initrd_end - initrd_start; /* 大小计算 */ params tag_next (params); /* 移动到下一个标签 */ } /** * brief 设置序列号标签(ATAG_SERIAL) * * 将板级序列号传递给内核 * * param tmp 标签指针的指针用于更新指针位置 * * 设计模式: 适配器模式 - 将板级序列号适配到ATAG格式 */ static void setup_serial_tag(struct tag **tmp) { struct tag *params *tmp; /* 获取当前标签指针 */ struct tag_serialnr serialnr; /* 序列号结构体 */ get_board_serial(serialnr); /* 获取板级序列号 */ params-hdr.tag ATAG_SERIAL; /* 设置标签类型为序列号 */ params-hdr.size tag_size (tag_serialnr); /* 设置标签大小 */ params-u.serialnr.low serialnr.low; /* 设置序列号低部分 */ params-u.serialnr.high serialnr.high; /* 设置序列号高部分 */ params tag_next (params); /* 移动到下一个标签 */ *tmp params; /* 更新外部指针 */ } /** * brief 设置版本标签(ATAG_REVISION) * * 将板级版本号传递给内核 * * param in_params 标签指针的指针 * * 设计模式: 工厂方法模式 - 创建特定类型的ATAG标签 */ static void setup_revision_tag(struct tag **in_params) { u32 rev 0; /* 版本号变量 */ rev get_board_rev(); /* 获取板级版本号 */ params-hdr.tag ATAG_REVISION; /* 设置标签类型为版本 */ params-hdr.size tag_size (tag_revision); /* 设置标签大小 */ params-u.revision.rev rev; /* 设置版本号 */ params tag_next (params); /* 移动到下一个标签 */ } /** * brief 设置结束标签(ATAG_NONE) * * 标记ATAG参数列表的结束 * * param bd 板级数据指针 * * 设计模式: 终止符模式 - 标记数据结构结束 */ static void setup_end_tag(bd_t *bd) { params-hdr.tag ATAG_NONE; /* 结束标签类型 */ params-hdr.size 0; /* 大小为0表示结束 */ } /** * brief 弱定义的板级标签设置函数 * * 允许板级代码覆盖此函数以添加自定义ATAG标签 * * param in_params 标签指针的指针 * * 设计模式: 钩子模式 - 提供扩展点供板级代码定制 */ __weak void setup_board_tags(struct tag **in_params) {} #ifdef CONFIG_ARM64 /* ARM64架构特定代码 */ /** * brief 执行非安全虚拟模式切换(ARM64) * * 在ARM64架构上切换到EL2或EL1异常级别 * * 性能分析: * - smp_kick_all_cpus()可能涉及核间通信开销较大 * - dcache_disable()刷新缓存耗时操作 * - 异常级别切换需要多个寄存器操作 */ static void do_nonsec_virt_switch(void) { smp_kick_all_cpus(); /* 唤醒所有CPU核心 */ dcache_disable(); /* 切换到EL2前刷新缓存 */ armv8_switch_to_el2(); /* 切换到EL2异常级别 */ #ifdef CONFIG_ARMV8_SWITCH_TO_EL1 /* 如果配置了切换到EL1 */ armv8_switch_to_el1(); /* 进一步切换到EL1异常级别 */ #endif } #endif /** * brief 子命令: PREP - 准备Linux内核启动 * * 根据配置准备Linux内核启动环境支持FDT和ATAGS两种方式 * * param images bootm镜像头信息 * * 设计模式: 策略模式 - 根据配置选择FDT或ATAGS策略 * 性能分析: * - FDT路径涉及设备树处理复杂度较高 * - ATAGS路径相对简单但需要设置多个标签 * - 条件编译减少不必要的代码路径 */ static void boot_prep_linux(bootm_headers_t *images) { /* 从环境变量获取内核命令行参数 */ char *commandline getenv(bootargs); /* 如果启用设备树且设备树长度不为0使用FDT方式 */ if (IMAGE_ENABLE_OF_LIBFDT images-ft_len) { #ifdef CONFIG_OF_LIBFDT debug(using: FDT\n); /* 调试输出使用FDT */ /* 设置Linux设备树失败则挂起系统 */ if (image_setup_linux(images)) { printf(FDT creation failed! hanging...); hang(); /* 挂起系统 */ } #endif } /* 如果启用ATAGS支持使用ATAGS方式 */ else if (BOOTM_ENABLE_TAGS) { debug(using: ATAGS\n); /* 调试输出使用ATAGS */ /* 设置起始标签 */ setup_start_tag(gd-bd); /* 根据配置添加各种标签 */ if (BOOTM_ENABLE_SERIAL_TAG) setup_serial_tag(params); /* 序列号标签 */ if (BOOTM_ENABLE_CMDLINE_TAG) setup_commandline_tag(gd-bd, commandline); /* 命令行标签 */ if (BOOTM_ENABLE_REVISION_TAG) setup_revision_tag(params); /* 版本标签 */ if (BOOTM_ENABLE_MEMORY_TAGS) setup_memory_tags(gd-bd); /* 内存标签 */ /* 设置initrd标签 */ if (BOOTM_ENABLE_INITRD_TAG) { /* * 在boot_ramdisk_high()中可能将ramdisk重定位到指定位置 * 并设置images-initrd_start和images-initrd_end为重定位后的地址 * 因此尽可能使用这些值而不是images-rd_start和images-rd_end */ if (images-initrd_start images-initrd_end) { setup_initrd_tag(gd-bd, images-initrd_start, images-initrd_end); } else if (images-rd_start images-rd_end) { setup_initrd_tag(gd-bd, images-rd_start, images-rd_end); } } /* 调用板级特定的标签设置 */ setup_board_tags(params); /* 设置结束标签 */ setup_end_tag(gd-bd); } /* 既不支持FDT也不支持ATAGS报错 */ else { printf(FDT and ATAGS support not compiled in - hanging\n); hang(); /* 挂起系统 */ } } /** * brief 弱定义的ARMv7非安全启动默认值 * * 返回ARMv7非安全启动的默认配置 * * return bool true表示默认非安全启动false表示默认安全启动 * * 设计模式: 模板方法模式 - 定义默认行为可被覆盖 */ __weak bool armv7_boot_nonsec_default(void) { #ifdef CONFIG_ARMV7_BOOT_SEC_DEFAULT /* 如果配置了默认安全启动 */ return false; /* 返回false表示安全启动 */ #else return true; /* 默认返回true表示非安全启动 */ #endif } #ifdef CONFIG_ARMV7_NONSEC /* ARMv7非安全模式支持 */ /** * brief 确定ARMv7是否以非安全模式启动 * * 检查环境变量bootm_boot_mode决定启动模式 * * return bool true表示非安全启动false表示安全启动 * * 设计模式: 策略模式 - 根据环境变量选择启动策略 * 性能分析: * - getenv()调用有字符串查找开销 * - strcmp()比较操作但字符串长度固定开销小 */ bool armv7_boot_nonsec(void) { /* 从环境变量获取启动模式设置 */ char *s getenv(bootm_boot_mode); /* 获取默认的非安全启动设置 */ bool nonsec armv7_boot_nonsec_default(); /* 如果环境变量设置为sec则使用安全启动 */ if (s !strcmp(s, sec)) nonsec false; /* 如果环境变量设置为nonsec则使用非安全启动 */ if (s !strcmp(s, nonsec)) nonsec true; return nonsec; /* 返回确定的启动模式 */ } #endif /** * brief 子命令: GO - 跳转到Linux内核 * * 实际跳转到Linux内核入口点执行 * * param images bootm镜像头信息 * param flag 启动标志位 * * 设计模式: 桥接模式 - 连接U-Boot和Linux内核 * 性能分析: * - ARM64和ARM32有不同实现路径 * - 环境变量解析有额外开销 * - 内核跳转是单次操作但准备阶段可能耗时 */ static void boot_jump_linux(bootm_headers_t *images, int flag) { #ifdef CONFIG_ARM64 /* ARM64实现 */ /* 定义内核入口函数指针 */ void (*kernel_entry)(void *fdt_addr, void *res0, void *res1, void *res2); /* 检查是否为模拟运行 */ int fake (flag BOOTM_STATE_OS_FAKE_GO); /* 将镜像入口点转换为函数指针 */ kernel_entry (void (*)(void *fdt_addr, void *res0, void *res1, void *res2))images-ep; /* 调试输出即将跳转到内核 */ debug(## Transferring control to Linux (at address %lx)...\n, (ulong) kernel_entry); /* 标记运行OS阶段 */ bootstage_mark(BOOTSTAGE_ID_RUN_OS); /* 执行启动前清理和通知 */ announce_and_cleanup(fake); /* 如果不是模拟运行则实际跳转 */ if (!fake) { /* 执行非安全虚拟模式切换 */ do_nonsec_virt_switch(); /* 调用内核入口函数传递设备树地址 */ kernel_entry(images-ft_addr, NULL, NULL, NULL); } #else /* ARM32实现 */ /* 获取机器ID */ unsigned long machid gd-bd-bi_arch_number; char *s; /* 环境变量字符串指针 */ /* 定义ARM32内核入口函数指针 */ void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; /* 参数寄存器2的值 */ int fake (flag BOOTM_STATE_OS_FAKE_GO); /* 检查是否为模拟运行 */ /* 将镜像入口点转换为函数指针 */ kernel_entry (void (*)(int, int, uint))images-ep; /* 从环境变量获取机器ID如果有的话 */ s getenv(machid); if (s) { /* 严格转换字符串为长整型 */ if (strict_strtoul(s, 16, machid) 0) { debug(strict_strtoul failed!\n); return; } /* 打印从环境变量获取的机器ID */ printf(Using machid 0x%lx from environment\n, machid); } /* 调试输出即将跳转到内核 */ debug(## Transferring control to Linux (at address %08lx) \ ...\n, (ulong) kernel_entry); /* 标记运行OS阶段 */ bootstage_mark(BOOTSTAGE_ID_RUN_OS); /* 执行启动前清理和通知 */ announce_and_cleanup(fake); /* 确定r2参数的值设备树地址或ATAGS参数地址 */ if (IMAGE_ENABLE_OF_LIBFDT images-ft_len) r2 (unsigned long)images-ft_addr; /* 使用设备树地址 */ else r2 gd-bd-bi_boot_params; /* 使用ATAGS参数地址 */ /* 如果不是模拟运行则实际跳转 */ if (!fake) { #ifdef CONFIG_ARMV7_NONSEC /* 如果支持ARMv7非安全模式 */ /* 检查是否以非安全模式启动 */ if (armv7_boot_nonsec()) { /* 初始化非安全模式 */ armv7_init_nonsec(); /* 安全RAM地址执行非安全入口 */ secure_ram_addr(_do_nonsec_entry)(kernel_entry, 0, machid, r2); } else #endif /* 直接调用内核入口函数 */ kernel_entry(0, machid, r2); } #endif } /** * brief ARM bootm实现的主要入口点 * * 模仿powerpc实现建模 * 不同之处如果子命令等于0则在最后调用prep和go * * param flag 启动标志位 * param argc 参数个数 * param argv 参数数组 * param images bootm镜像头信息 * return int 执行结果0成功-1失败 * * 设计模式: 状态模式 - 根据flag的不同状态执行不同操作 * 性能分析: * - 快速的状态检查位操作 * - 按需执行prep和go避免不必要的工作 * - 代码路径清晰执行效率高 */ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *images) { /* ARM上不需要这些状态 */ if (flag BOOTM_STATE_OS_BD_T || flag BOOTM_STATE_OS_CMDLINE) return -1; /* 如果是PREP状态执行准备操作 */ if (flag BOOTM_STATE_OS_PREP) { boot_prep_linux(images); return 0; } /* 如果是GO或FAKE_GO状态执行跳转操作 */ if (flag (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { boot_jump_linux(images, flag); return 0; } /* 默认情况先执行准备操作再执行跳转操作 */ boot_prep_linux(images); boot_jump_linux(images, flag); return 0; } #if defined(CONFIG_BOOTM_VXWORKS) /* VxWorks启动支持 */ /** * brief 准备VxWorks启动 * * VxWorks启动前的准备工作主要是设备树处理 * * param images bootm镜像头信息 * * 设计模式: 适配器模式 - 适配VxWorks启动的特殊需求 */ void boot_prep_vxworks(bootm_headers_t *images) { #if defined(CONFIG_OF_LIBFDT) /* 如果支持设备树 */ int off; /* 设备树节点偏移量 */ /* 如果存在设备树地址 */ if (images-ft_addr) { /* 查找内存节点 */ off fdt_path_offset(images-ft_addr, /memory); if (off 0) { /* 如果找不到内存节点 */ #ifdef CONFIG_ARCH_FIXUP_FDT /* 如果支持架构特定的设备树修复 */ /* 尝试修复设备树 */ if (arch_fixup_fdt(images-ft_addr)) puts(## WARNING: fixup memory failed!\n); #endif } } #endif /* Linux启动前清理操作也适用于VxWorks */ cleanup_before_linux(); } /** * brief 跳转到VxWorks * * 实际跳转到VxWorks入口点 * * param images bootm镜像头信息 * * 设计模式: 简单工厂模式 - 创建并执行VxWorks启动 */ void boot_jump_vxworks(bootm_headers_t *images) { /* * ARM VxWorks要求传递设备树物理地址 * 将镜像入口点转换为函数指针并调用传递设备树地址 */ ((void (*)(void *))images-ep)(images-ft_addr); } #endif设计模式综合分析1.建造者模式 (Builder Pattern)应用场景:setup_*_tag系列函数分析: 这些函数逐步构建ATAG参数列表类似于建造者模式中逐步构建复杂对象的过程2.模板方法模式 (Template Method Pattern)应用场景:announce_and_cleanup()函数分析: 定义了启动前准备的标准流程具体步骤可以通过条件编译定制3.策略模式 (Strategy Pattern)应用场景: FDT vs ATAGS 选择安全 vs 非安全启动选择分析: 根据配置和环境变量选择不同的启动策略4.状态模式 (State Pattern)应用场景:do_bootm_linux()函数中的flag处理分析: 根据不同的状态标志执行不同的操作序列5.钩子模式 (Hook Pattern)应用场景:__weak函数定义分析: 提供默认实现允许板级代码覆盖特定功能性能分析总结1.优点条件编译优化: 通过宏定义移除未使用代码路径内存访问优化: 直接操作内存减少中间拷贝流程控制优化: 清晰的状态检查避免不必要的操作2.潜在瓶颈字符串操作:strlen(),strcpy(),strcat()在长命令行时可能成为瓶颈环境变量访问:getenv()可能涉及字符串查找建议缓存结果设备树处理: FDT路径可能涉及较复杂的树遍历操作3.建议优化缓存环境变量查询结果预计算字符串长度避免重复计算对于频繁使用的标签操作可以考虑批处理设备树操作可以延迟到真正需要时执行这个实现展示了U-Boot启动Linux内核的完整流程平衡了灵活性和性能为不同硬件平台提供了良好的支持基础。第二部分 修改分析主要修改点分析1.版权信息修改/* * Copyright (C) 2011 * * - 添加了prep子命令支持 * - 重新组织源代码 - 基于powerpc版本建模 */修改原因记录了Corscience公司的贡献明确说明了两项主要修改prep子命令支持和代码重构基于PowerPC版本进行重构利用了PowerPC架构上成熟的bootm实现2.源代码重新组织原始文件通常是arch/arm/lib/bootm.c而这个版本明显进行了重构。修改内容将启动流程清晰地分为boot_prep_linux()和boot_jump_linux()两个主要函数增加了do_bootm_linux()作为统一的入口点模仿PowerPC的实现方式使ARM和PowerPC的bootm实现保持一致性修改原因代码复用PowerPC的bootm实现相对成熟借鉴其设计可以提高代码质量维护性统一的代码结构便于跨架构维护清晰度分离准备和跳转两个阶段逻辑更清晰3.添加prep子命令支持/* 如果是PREP状态执行准备操作 */ if (flag BOOTM_STATE_OS_PREP) { boot_prep_linux(images); return 0; }修改原因调试需求允许单独执行启动准备阶段便于调试模块化将复杂的启动过程分解为可独立测试的模块灵活性支持如bootm prep这样的命令可以只准备不跳转4.VxWorks启动支持#if defined(CONFIG_BOOTM_VXWORKS) void boot_prep_vxworks(bootm_headers_t *images) void boot_jump_vxworks(bootm_headers_t *images) #endif修改原因多OS支持原始U-Boot主要支持Linux这个版本增加了VxWorks RTOS支持工业应用VxWorks在工业控制领域广泛使用统一接口通过相同的bootm框架支持不同操作系统5.ARMv7非安全模式支持#ifdef CONFIG_ARMV7_NONSEC bool armv7_boot_nonsec(void) #endif修改原因安全扩展支持ARM TrustZone技术虚拟化为虚拟化环境提供支持现代ARM特性适应新一代ARM处理器的安全需求6.ARM64架构支持#ifdef CONFIG_ARM64 static void do_nonsec_virt_switch(void) #endif修改原因架构演进支持64位ARM架构异常级别ARM64使用不同的异常级别模型EL1/EL2/EL3兼容性需要为ARM64提供特定的启动切换代码7.改进的ATAG处理/* 根据starttype添加相应的启动类型参数 */ if(starttype 0) s starttypemain; /* 主启动类型 */ else s starttypebackup; /* 备份启动类型 */修改原因冗余启动支持主/备份双系统启动可靠性在主系统损坏时可以切换到备份系统工业标准符合工业控制系统的高可靠性要求8.内存布局优化/* 为安全起见将sp向下调整4KB */ sp - 4096;修改原因安全边界为堆栈保留额外的安全空间防止溢出避免内核启动时堆栈溢出对齐要求确保内存边界对齐9.增强的调试支持debug(## Current stack ends at 0x%08lx , sp); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, start_kernel); #ifdef CONFIG_BOOTSTAGE_REPORT bootstage_report(); #endif修改原因调试信息提供更详细的启动过程信息性能分析bootstage支持启动性能分析问题诊断便于定位启动过程中的问题10.灵活的启动模式选择#ifdef CONFIG_ARMV7_NONSEC bool armv7_boot_nonsec(void) { char *s getenv(bootm_boot_mode); bool nonsec armv7_boot_nonsec_default(); if (s !strcmp(s, sec)) nonsec false; if (s !strcmp(s, nonsec)) nonsec true; return nonsec; } #endif修改原因运行时配置可以通过环境变量动态选择启动模式灵活性不需要重新编译即可切换启动模式测试便利便于测试不同的安全配置设计理念的变化1.从单片代码到模块化设计原始所有启动代码在一个大函数中修改后分解为多个职责清晰的函数2.从ARM特定到跨架构统一原始ARM特有的实现方式修改后借鉴PowerPC的设计向跨架构统一迈进3.从单一OS到多OS支持原始主要支持Linux修改后支持Linux、VxWorks等多个操作系统4.从固定配置到灵活配置原始编译时确定的配置修改后支持运行时通过环境变量配置具体使用场景分析这些修改特别适合以下场景1.工业控制系统VxWorks支持冗余启动主/备份高可靠性要求2.安全敏感应用ARM TrustZone支持安全/非安全模式选择内存保护增强3.虚拟化环境ARM64支持异常级别切换多OS共存4.调试和开发详细的调试输出bootstage性能分析独立的prep子命令潜在问题与考量1.兼容性问题修改可能破坏与原始U-Boot的兼容性需要确保所有板级代码适配新的接口2.代码复杂度增加更多的条件编译分支更复杂的函数调用链需要更多的测试用例3.性能影响额外的函数调用开销环境变量查找开销更多的调试代码可能影响性能总结这个修改版本的U-Boot启动代码主要体现了以下几个设计思想模块化将复杂功能分解为独立的模块可配置性提供多种配置选项和运行时选择可扩展性易于添加对新架构和OS的支持可调试性丰富的调试信息和性能分析工具可靠性增强的错误处理和冗余机制这些修改使得U-Boot更加适合现代嵌入式系统特别是那些需要高可靠性、安全性和灵活性的工业应用场景。不过这些改进也带来了一定的复杂性和维护成本需要在具体项目中权衡利弊。