深入S5P6818 U-Boot启动流程从reset向量到main_loop的代码级解析在嵌入式系统开发中Bootloader作为硬件上电后运行的第一段程序承担着初始化硬件、加载操作系统内核的重要职责。对于基于S5P6818处理器的开发板而言U-Boot作为最常用的开源Bootloader其启动流程的深入理解是开发者进行系统移植和优化的基础。本文将带您深入S5P6818的U-Boot启动过程从reset向量开始逐步解析到main_loop的完整执行路径。1. 异常向量表与reset处理当S5P6818处理器上电或复位时会从特定的地址开始执行指令。这个地址通常指向U-Boot的异常向量表它是ARM架构规定的硬件行为。在U-Boot的启动代码start.S中我们可以看到异常向量表的定义.globl _stext _stext: b reset /* 复位向量 */ ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq这段代码定义了ARM处理器的七种异常处理入口。其中复位异常reset是最重要的它通过b reset指令跳转到reset标签处开始U-Boot的真正启动流程。reset处理的第一步是设置处理器模式。ARM处理器有多种运行模式U-Boot需要在特权模式Supervisor ModeSVC下运行reset: /* 设置CPU为SVC32模式 */ mrs r0, cpsr bic r0, r0, #0x1f /* 清除模式位 */ orr r0, r0, #0xd3 /* 设置SVC模式并禁用中断 */ msr cpsr,r0提示SVC模式是ARM处理器的特权模式之一允许执行所有指令和访问所有资源适合Bootloader的运行环境。2. 关键硬件初始化在设置完处理器模式后U-Boot需要初始化关键的硬件模块为后续操作做好准备。这包括关闭看门狗定时器防止在初始化过程中看门狗超时导致系统复位/* 禁用看门狗 */ ldr r0, 0xC0019000 /* S5P6818看门狗寄存器地址 */ mov r1, #0 str r1, [r0]禁用MMU和Cache在初始化阶段MMU和Cache可能会干扰对物理内存的直接访问bl cpu_init_cp15 /* 调用函数禁用MMU和Cache */时钟和内存控制器初始化通过cpu_init_crit函数初始化PLL和内存控制器bl cpu_init_crit /* 初始化PLL、时钟和内存 */cpu_init_crit函数最终会跳转到lowlevel_init这是与具体硬件平台相关的低级初始化代码。对于S5P6818这部分代码通常包括设置锁相环(PLL)配置确定CPU和总线时钟频率初始化内存控制器配置DRAM时序参数设置系统时钟分频器3. U-Boot的自搬移(Relocation)过程U-Boot启动时通常从非易失性存储器如NOR Flash或eMMC开始执行但为了获得更好的性能需要将自身代码搬移到RAM中运行。这个过程称为自搬移或重定位(Relocation)。在S5P6818的U-Boot中自搬移过程由relocate_to_text代码段实现relocate_to_text: adr r0, _stext /* r0 - 当前代码位置 */ ldr r1, TEXT_BASE /* r1 - 目标地址(RAM中的地址) */ cmp r0, r1 /* 比较当前地址和目标地址 */ beq clear_bss /* 如果已经在RAM中跳过搬移 */ ldr r2, _bss_start_ofs add r2, r0, r2 /* r2 - 源代码结束地址 */ copy_loop_text: ldmia r0!, {r3-r10} /* 从源地址[r0]加载8个寄存器 */ stmia r1!, {r3-r10} /* 存储到目标地址[r1] */ cmp r0, r2 /* 检查是否到达源结束地址 */ ble copy_loop_text ldr r1, TEXT_BASE /* 跳转到RAM中的新地址 */ mov pc, r1这段代码的核心是通过ldmia和stmia指令批量加载和存储数据高效地完成代码搬移。搬移完成后程序会跳转到RAM中的新地址继续执行。4. C运行环境准备在完成自搬移后U-Boot需要为后续的C代码执行准备环境主要包括清除BSS段BSS段用于存放未初始化的全局变量需要清零clear_bss: ldr r0, _bss_start_ofs ldr r1, _bss_end_ofs ldr r4, TEXT_BASE add r0, r0, r4 /* BSS段起始地址 */ add r1, r1, r4 /* BSS段结束地址 */ mov r2, #0x00000000 /* 清零值 */ clbss_l: str r2, [r0] /* 清零循环 */ add r0, r0, #4 cmp r0, r1 bne clbss_l设置栈指针C函数调用需要栈空间ldr sp, (CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, #7 /* 8字节对齐 */ sub sp, #GD_SIZE /* 为全局数据结构分配空间 */ bic sp, sp, #7 mov r9, sp /* 全局数据结构指针 */ mov r0, #0初始化全局数据结构U-Boot使用全局数据结构gd_t来维护系统状态typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; // ...其他字段 } gd_t;5. 板级初始化和main_loop在准备好C运行环境后U-Boot会依次调用两个重要的板级初始化函数board_init_f在搬移前的初始化主要完成串口初始化内存大小检测环境变量初始化为relocation计算参数board_init_r在relocation后的初始化主要完成设备树初始化如果使用设备驱动初始化环境变量加载命令行接口准备最后U-Boot进入main_loop函数这是U-Boot的最终阶段void main_loop(void) { const char *s; s bootdelay_process(); /* 处理启动延迟 */ if (cli_process_fdt(s)) /* 检查是否进入命令行 */ cli_secure_boot_cmd(s); autoboot_command(s); /* 自动启动流程 */ }在main_loop中U-Boot会检查是否有用户输入中断自动启动过程如果没有中断则加载并启动内核如果被中断则进入命令行界面等待用户输入6. 链接脚本与代码布局理解U-Boot启动流程还需要了解其内存布局这由链接脚本u-boot.lds决定。典型的S5P6818 U-Boot链接脚本包含以下关键部分.text : { *(.__image_copy_start) arch/arm/cpu/slsiap/s5p6818/start.o (.text*) arch/arm/cpu/slsiap/s5p6818/vectors.o (.text*) *(.text*) } .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } .data : { *(.data*) } . .; .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } . ALIGN(4); .__image_copy_end .; .bss_start (NOLOAD) : { KEEP(*(.__bss_start)); *(.bss*) *(COMMON) . ALIGN(4); KEEP(*(.__bss_end)); }这个链接脚本定义了代码段(.text)、只读数据段(.rodata)、可写数据段(.data)和BSS段的布局确保U-Boot的各个部分被正确加载到内存中。7. 调试与问题排查在实际开发中理解U-Boot启动流程对于调试至关重要。以下是一些常见问题及排查方法U-Boot无法启动检查复位向量是否正确跳转验证处理器模式是否设置为SVC确认看门狗是否被正确禁用Relocation失败检查TEXT_BASE定义是否正确验证源地址和目标地址计算确认内存控制器初始化是否正确BSS段清零问题检查_bss_start和_bss_end定义确认清零操作是否覆盖整个BSS段栈设置问题验证CONFIG_SYS_INIT_SP_ADDR是否在有效RAM范围内确认栈指针是否正确对齐对于S5P6818平台可以通过串口输出调试信息来跟踪启动过程。在关键代码位置添加打印语句可以帮助定位问题所在阶段。
深入S5P6818 U-Boot启动流程:从reset向量到main_loop的代码级解析
发布时间:2026/6/4 2:06:04
深入S5P6818 U-Boot启动流程从reset向量到main_loop的代码级解析在嵌入式系统开发中Bootloader作为硬件上电后运行的第一段程序承担着初始化硬件、加载操作系统内核的重要职责。对于基于S5P6818处理器的开发板而言U-Boot作为最常用的开源Bootloader其启动流程的深入理解是开发者进行系统移植和优化的基础。本文将带您深入S5P6818的U-Boot启动过程从reset向量开始逐步解析到main_loop的完整执行路径。1. 异常向量表与reset处理当S5P6818处理器上电或复位时会从特定的地址开始执行指令。这个地址通常指向U-Boot的异常向量表它是ARM架构规定的硬件行为。在U-Boot的启动代码start.S中我们可以看到异常向量表的定义.globl _stext _stext: b reset /* 复位向量 */ ldr pc, _undefined_instruction ldr pc, _software_interrupt ldr pc, _prefetch_abort ldr pc, _data_abort ldr pc, _not_used ldr pc, _irq ldr pc, _fiq这段代码定义了ARM处理器的七种异常处理入口。其中复位异常reset是最重要的它通过b reset指令跳转到reset标签处开始U-Boot的真正启动流程。reset处理的第一步是设置处理器模式。ARM处理器有多种运行模式U-Boot需要在特权模式Supervisor ModeSVC下运行reset: /* 设置CPU为SVC32模式 */ mrs r0, cpsr bic r0, r0, #0x1f /* 清除模式位 */ orr r0, r0, #0xd3 /* 设置SVC模式并禁用中断 */ msr cpsr,r0提示SVC模式是ARM处理器的特权模式之一允许执行所有指令和访问所有资源适合Bootloader的运行环境。2. 关键硬件初始化在设置完处理器模式后U-Boot需要初始化关键的硬件模块为后续操作做好准备。这包括关闭看门狗定时器防止在初始化过程中看门狗超时导致系统复位/* 禁用看门狗 */ ldr r0, 0xC0019000 /* S5P6818看门狗寄存器地址 */ mov r1, #0 str r1, [r0]禁用MMU和Cache在初始化阶段MMU和Cache可能会干扰对物理内存的直接访问bl cpu_init_cp15 /* 调用函数禁用MMU和Cache */时钟和内存控制器初始化通过cpu_init_crit函数初始化PLL和内存控制器bl cpu_init_crit /* 初始化PLL、时钟和内存 */cpu_init_crit函数最终会跳转到lowlevel_init这是与具体硬件平台相关的低级初始化代码。对于S5P6818这部分代码通常包括设置锁相环(PLL)配置确定CPU和总线时钟频率初始化内存控制器配置DRAM时序参数设置系统时钟分频器3. U-Boot的自搬移(Relocation)过程U-Boot启动时通常从非易失性存储器如NOR Flash或eMMC开始执行但为了获得更好的性能需要将自身代码搬移到RAM中运行。这个过程称为自搬移或重定位(Relocation)。在S5P6818的U-Boot中自搬移过程由relocate_to_text代码段实现relocate_to_text: adr r0, _stext /* r0 - 当前代码位置 */ ldr r1, TEXT_BASE /* r1 - 目标地址(RAM中的地址) */ cmp r0, r1 /* 比较当前地址和目标地址 */ beq clear_bss /* 如果已经在RAM中跳过搬移 */ ldr r2, _bss_start_ofs add r2, r0, r2 /* r2 - 源代码结束地址 */ copy_loop_text: ldmia r0!, {r3-r10} /* 从源地址[r0]加载8个寄存器 */ stmia r1!, {r3-r10} /* 存储到目标地址[r1] */ cmp r0, r2 /* 检查是否到达源结束地址 */ ble copy_loop_text ldr r1, TEXT_BASE /* 跳转到RAM中的新地址 */ mov pc, r1这段代码的核心是通过ldmia和stmia指令批量加载和存储数据高效地完成代码搬移。搬移完成后程序会跳转到RAM中的新地址继续执行。4. C运行环境准备在完成自搬移后U-Boot需要为后续的C代码执行准备环境主要包括清除BSS段BSS段用于存放未初始化的全局变量需要清零clear_bss: ldr r0, _bss_start_ofs ldr r1, _bss_end_ofs ldr r4, TEXT_BASE add r0, r0, r4 /* BSS段起始地址 */ add r1, r1, r4 /* BSS段结束地址 */ mov r2, #0x00000000 /* 清零值 */ clbss_l: str r2, [r0] /* 清零循环 */ add r0, r0, #4 cmp r0, r1 bne clbss_l设置栈指针C函数调用需要栈空间ldr sp, (CONFIG_SYS_INIT_SP_ADDR) bic sp, sp, #7 /* 8字节对齐 */ sub sp, #GD_SIZE /* 为全局数据结构分配空间 */ bic sp, sp, #7 mov r9, sp /* 全局数据结构指针 */ mov r0, #0初始化全局数据结构U-Boot使用全局数据结构gd_t来维护系统状态typedef struct global_data { bd_t *bd; unsigned long flags; unsigned long baudrate; // ...其他字段 } gd_t;5. 板级初始化和main_loop在准备好C运行环境后U-Boot会依次调用两个重要的板级初始化函数board_init_f在搬移前的初始化主要完成串口初始化内存大小检测环境变量初始化为relocation计算参数board_init_r在relocation后的初始化主要完成设备树初始化如果使用设备驱动初始化环境变量加载命令行接口准备最后U-Boot进入main_loop函数这是U-Boot的最终阶段void main_loop(void) { const char *s; s bootdelay_process(); /* 处理启动延迟 */ if (cli_process_fdt(s)) /* 检查是否进入命令行 */ cli_secure_boot_cmd(s); autoboot_command(s); /* 自动启动流程 */ }在main_loop中U-Boot会检查是否有用户输入中断自动启动过程如果没有中断则加载并启动内核如果被中断则进入命令行界面等待用户输入6. 链接脚本与代码布局理解U-Boot启动流程还需要了解其内存布局这由链接脚本u-boot.lds决定。典型的S5P6818 U-Boot链接脚本包含以下关键部分.text : { *(.__image_copy_start) arch/arm/cpu/slsiap/s5p6818/start.o (.text*) arch/arm/cpu/slsiap/s5p6818/vectors.o (.text*) *(.text*) } .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } .data : { *(.data*) } . .; .u_boot_list : { KEEP(*(SORT(.u_boot_list*))); } . ALIGN(4); .__image_copy_end .; .bss_start (NOLOAD) : { KEEP(*(.__bss_start)); *(.bss*) *(COMMON) . ALIGN(4); KEEP(*(.__bss_end)); }这个链接脚本定义了代码段(.text)、只读数据段(.rodata)、可写数据段(.data)和BSS段的布局确保U-Boot的各个部分被正确加载到内存中。7. 调试与问题排查在实际开发中理解U-Boot启动流程对于调试至关重要。以下是一些常见问题及排查方法U-Boot无法启动检查复位向量是否正确跳转验证处理器模式是否设置为SVC确认看门狗是否被正确禁用Relocation失败检查TEXT_BASE定义是否正确验证源地址和目标地址计算确认内存控制器初始化是否正确BSS段清零问题检查_bss_start和_bss_end定义确认清零操作是否覆盖整个BSS段栈设置问题验证CONFIG_SYS_INIT_SP_ADDR是否在有效RAM范围内确认栈指针是否正确对齐对于S5P6818平台可以通过串口输出调试信息来跟踪启动过程。在关键代码位置添加打印语句可以帮助定位问题所在阶段。