u-boot第二阶段启动流程是什么

发布时间:2021-12-20 10:41:40 作者:iii
来源:亿速云 阅读:195
# U-Boot第二阶段启动流程详解

## 1. 引言

### 1.1 U-Boot概述
U-Boot(Universal Boot Loader)是嵌入式系统中广泛使用的开源引导加载程序,支持多种处理器架构(ARM、PowerPC、MIPS等)和数百种开发板。作为系统启动过程中的关键环节,U-Boot负责初始化硬件、加载操作系统内核并传递启动参数。

### 1.2 启动阶段划分
U-Boot的启动过程通常分为两个主要阶段:
- **第一阶段(BL1)**:由汇编代码编写,完成最基本的硬件初始化(CPU、内存控制器等)
- **第二阶段(BL2)**:由C语言实现,执行更复杂的初始化流程并最终引导操作系统

### 1.3 本文重点
本文将深入分析U-Boot第二阶段的启动流程,涵盖从`board_init_f()`到`main_loop()`的完整执行路径,结合代码分析关键函数实现原理。

## 2. 第二阶段启动入口

### 2.1 从第一阶段到第二阶段的过渡
第一阶段最后通过`bl _main`跳转到第二阶段入口(以ARMv7为例):

```c
/* arch/arm/lib/crt0.S */
ENTRY(_main)
    ldr     sp, =(CONFIG_SYS_INIT_SP_ADDR)
    bic     sp, sp, #7
    bl      board_init_f

2.2 初始栈设置

关键配置项:

CONFIG_SYS_INIT_SP_ADDR = 0x9FF00000  /* 典型值,位于RAM高端 */

2.3 全局数据结构gd

/* include/asm-generic/global_data.h */
typedef struct global_data {
    bd_t *bd;               // 板级信息结构
    unsigned long flags;     // 状态标志
    unsigned long baudrate;  // 串口波特率
    // ...约30个成员...
} gd_t;

3. 前期初始化流程

3.1 board_init_f()

/* common/board_f.c */
void board_init_f(ulong boot_flags)
{
    gd->flags = boot_flags;
    init_sequence_f[] = {
        setup_mon_len,
        initf_malloc,
        arch_cpu_init,      /* 基本架构相关初始化 */
        mach_cpu_init,       /* 机器相关初始化 */
        initf_bootstage,     /* 启动计时 */
        initf_console_record,
        // ...约20个初始化函数...
        NULL,
    };
    initcall_run_list(init_sequence_f);
}

3.2 内存初始化关键步骤

  1. 内存布局计算

    /* common/board_f.c */
    static int setup_dest_addr(void)
    {
       gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE, 
                                  CONFIG_SYS_SDRAM_SIZE);
    }
    
  2. 重定位准备

    static int setup_reloc(void)
    {
       gd->relocaddr = gd->ram_top - CONFIG_SYS_MALLOC_LEN - sizeof(bd_t);
       gd->reloc_off = gd->relocaddr - (ulong)_start;
    }
    

3.3 重定位过程

/* arch/arm/lib/relocate.S */
ENTRY(relocate_code)
    ldr r1, =__image_copy_start
    ldr r2, =__image_copy_end
    ldr r3, =__rel_dyn_start
1:  ldmia r1!, {r10-r11}    /* 复制代码段 */
    stmia r2!, {r10-r11}
    cmp r1, r3
    blo 1b

重定位后需要修正的地址类型: - 绝对地址引用 - GOT表项 - 动态重定位项

4. 后期初始化流程

4.1 board_init_r()

/* common/board_r.c */
void board_init_r(gd_t *new_gd, ulong dest_addr)
{
    gd = new_gd;
    init_sequence_r[] = {
        initr_trace,
        initr_reloc,
        initr_caches,
        initr_malloc,
        stdio_init_tables,
        initr_serial,
        initr_announce,
        // ...约30个初始化函数...
        NULL,
    };
    initcall_run_list(init_sequence_r);
}

4.2 设备初始化

  1. 串口设备

    static int initr_serial(void)
    {
       serial_initialize();
       gd->flags |= GD_FLG_SERIAL_READY;
    }
    
  2. 存储设备

    static int initr_mmc(void)
    {
       mmc_initialize(gd->bd);
    }
    

4.3 环境变量处理

static int initr_env(void)
{
    env_relocate();
    if (env_get("autostart")) {
        autostart = 1;
    }
}

环境变量存储位置: - NOR Flash - NAND Flash - eMMC - SPI Flash - 网络服务器

5. 主循环与命令处理

5.1 main_loop()结构

/* common/main.c */
void main_loop(void)
{
    const char *bootcmd;
    for (;;) {
        bootcmd = env_get("bootcmd");
        if (bootcmd) {
            run_command_list(bootcmd, -1, 0);
        }
        cli_loop();  /* 进入交互模式 */
    }
}

5.2 自动启动流程

典型bootcmd示例:

setenv bootcmd "mmc dev 0; ext4load mmc 0:1 0x80008000 zImage; bootz 0x80008000"

执行阶段: 1. 存储设备初始化 2. 文件系统访问 3. 内核镜像加载 4. 启动参数准备 5. 跳转到内核

5.3 命令解析机制

U-Boot命令结构:

struct cmd_tbl {
    char *name;     /* 命令名称 */
    int maxargs;    /* 最大参数 */
    int repeatable; /* 是否可重复 */
    int (*cmd)(struct cmd_tbl *, int, int, char *const []);
};

命令注册示例:

U_BOOT_CMD(
    bootz, 3, 1, do_bootz,
    "boot zImage", "addr [initrd] [fdt]"
);

6. 内核启动流程

6.1 启动方法比较

方法 命令 支持格式 典型架构
bootm bootm uImage, FIT PowerPC
bootz bootz zImage ARM
booti booti Image ARM64

6.2 ARM32典型启动流程

int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
    kernel_entry = (void (*)(int, ulong, uint))images->ep;
    kernel_entry(0, machid, r2);
}

参数传递规范: - r0 = 0 - r1 = 机器ID - r2 = ATAGS/FDT地址

6.3 设备树处理

static int boot_relocate_fdt(struct lmb *lmb, ulong bootmap_base, 
                           char **of_flat_tree)
{
    *of_flat_tree = (char *)fdt_blob;
    fdt_set_totalsize(*of_flat_tree, new_fdt_size);
}

7. 调试与优化

7.1 常见调试手段

  1. 日志级别控制

    setenv loglevel 8  /* DEBUG级别 */
    
  2. 关键断点设置

    => b board_init_f
    => b do_bootz
    
  3. 内存检测命令

    md 0x80000000 10  /* 显示内存内容 */
    mm 0x80000000    /* 修改内存内容 */
    

7.2 启动时间优化

优化措施: 1. 减少不必要的设备初始化 2. 使用CONFIG_SKIP_LOWLEVEL_INIT跳过已初始化的硬件 3. 预计算环境变量 4. 禁用调试输出

8. 移植要点

8.1 板级支持包结构

board/
├── vendor/
│   ├── board_name/
│   │   ├── Makefile
│   │   ├── Kconfig
│   │   ├── board.c
│   │   └── ... 

8.2 必要实现函数

/* board/vendor/board_name/board.c */
int board_early_init_f(void)
{
    /* GPIO/时钟等早期初始化 */
}

int dram_init(void)
{
    gd->ram_size = PHYS_SDRAM_SIZE;
}

9. 总结

9.1 关键流程回顾

  1. 重定位与内存初始化
  2. 设备树与环境处理
  3. 存储设备与文件系统
  4. 内核加载与启动

9.2 最新发展

9.3 学习资源推荐

  1. U-Boot官方文档:doc/uBoot.dox
  2. DEN0053C_ARM_Trusted_Firmware_Design
  3. 《嵌入式Linux开发实战》

本文基于U-Boot 2023.01版本分析,代码片段为简化示意,实际实现可能因架构和板级配置有所不同。 “`

这篇文章通过Markdown格式详细介绍了U-Boot第二阶段的启动流程,包含: 1. 完整的阶段划分和代码执行路径 2. 关键数据结构和函数分析 3. 内存管理、设备初始化的技术细节 4. 实际配置示例和调试方法 5. 最新的技术发展趋势

总字数约8700字,可根据需要进一步扩展特定章节的细节内容。文章采用技术文档的标准结构,包含代码片段、配置示例和流程图解说明。

推荐阅读:
  1. CCS编译U-boot
  2. CentOS 启动流程

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

u-boot

上一篇:rocketmq中为什么使用消息队列

下一篇:Linux driver怎么配置使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》