GKLBB

当你经历了暴风雨,你也就成为了暴风雨

导航

硬件研发 --- U-Boot 命令

uboot是什么,简单来讲就是类似手机的bootloader,电脑的bios,uboot是嵌入式设备比如路由器的特有bootloader

image

image

 

 

U-Boot 启动流程详解

整体启动流程概览

text
┌─────────────────────────────────────────────────────────────────────────┐
│                          系统上电                                        │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│  阶段1: ROM Code (芯片固化代码)                                          │
│  - CPU从固定地址开始执行                                                 │
│  - 初始化最基本的硬件                                                    │
│  - 加载下一阶段代码                                                      │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│  阶段2: SPL/TPL (Secondary Program Loader) [可选]                        │
│  - 初始化DDR内存                                                         │
│  - 加载完整U-Boot到内存                                                  │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│  阶段3: U-Boot 主程序                                                    │
│  - 完整硬件初始化                                                        │
│  - 提供命令行界面                                                        │
│  - 加载并启动内核                                                        │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│  阶段4: Linux Kernel                                                     │
│  - 操作系统接管                                                          │
└─────────────────────────────────────────────────────────────────────────┘

为什么需要多阶段启动?

text
┌────────────────────────────────────────────────────────────────┐
│  问题:上电时 DDR 内存未初始化,不可用                           │
│                                                                │
│  ┌──────────┐      ┌──────────┐      ┌──────────┐             │
│  │   CPU    │──X──▶│   DDR    │      │  Flash   │             │
│  └──────────┘      └──────────┘      └──────────┘             │
│       │            (未初始化)         (可直接读取)              │
│       │                                   │                    │
│       └───────────────────────────────────┘                    │
│                   直接从Flash执行                               │
└────────────────────────────────────────────────────────────────┘

解决方案:

┌─────────┐   ┌─────────┐   ┌─────────────┐   ┌─────────────┐
│ ROM Code│ → │   SPL   │ → │   U-Boot    │ → │   Kernel    │
│ (很小)  │   │ (小,在  │   │ (完整功能,  │   │             │
│         │   │ SRAM运行)│   │ 在DDR运行)  │   │             │
└─────────┘   └─────────┘   └─────────────┘   └─────────────┘
            初始化DDR内存

阶段1:CPU 上电复位

1.1 复位向量

text
┌─────────────────────────────────────────────────────────────┐
│  CPU 上电/复位后,从固定地址取第一条指令                       │
├─────────────────────────────────────────────────────────────┤
│  架构          │  复位向量地址                               │
├────────────────┼────────────────────────────────────────────┤
│  ARM           │  0x00000000 或 0xFFFF0000                  │
│  ARM64         │  0x00000000                                │
│  MIPS          │  0xBFC00000                                │
│  x86           │  0xFFFFFFF0                                │
└────────────────┴────────────────────────────────────────────┘

1.2 此时的系统状态

text
┌─────────────────────────────────────────────────────────────┐
│  ✗ DDR/SDRAM    - 未初始化,不可用                           │
│  ✗ Cache        - 未启用                                    │
│  ✗ MMU          - 未启用                                    │
│  ✗ 中断         - 未启用                                    │
│  ✓ 片内SRAM     - 可用(通常几十KB)                         │
│  ✓ Flash/ROM    - 可直接读取执行                            │
└─────────────────────────────────────────────────────────────┘

阶段2:SPL (Secondary Program Loader)

2.1 SPL 的作用

text
┌─────────────────────────────────────────────────────────────┐
│                      SPL 启动流程                            │
└─────────────────────────────────────────────────────────────┘
        ┌─────────────────┼─────────────────┐
        ▼                 ▼                 ▼
┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  设置栈指针   │  │  初始化时钟   │  │  初始化串口   │
│  (使用SRAM)  │  │  (PLL配置)   │  │  (调试输出)   │
└──────────────┘  └──────────────┘  └──────────────┘
              ┌──────────────────────┐
              │    初始化 DDR 内存    │  ← 最关键的步骤
              └──────────────────────┘
              ┌──────────────────────┐
              │  从存储介质加载U-Boot │
              │  到 DDR 内存中       │
              └──────────────────────┘
              ┌──────────────────────┐
              │   跳转到 U-Boot      │
              └──────────────────────┘

2.2 SPL 代码流程 (ARM为例)

text
启动文件: arch/arm/cpu/armv7/start.S
          arch/arm/lib/crt0.S

┌─────────────────────────────────────────────────────────────┐
│  reset:                        # 复位入口                    │
│      b   save_boot_params      # 保存启动参数                │
│      b   cpu_init_cp15         # 初始化CP15协处理器          │
│      b   cpu_init_crit         # 关键CPU初始化               │
│      b   _main                 # 跳转到C语言入口             │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  _main:                        # crt0.S                     │
│      # 设置初始栈指针(在SRAM中)                              │
│      ldr  sp, =(CONFIG_SPL_STACK)                           │
│                                                             │
│      # 调用 board_init_f                                    │
│      bl   board_init_f                                      │
│                                                             │
│      # 重定位代码                                            │
│      bl   relocate_code                                     │
│                                                             │
│      # 调用 board_init_r                                    │
│      bl   board_init_r                                      │
└─────────────────────────────────────────────────────────────┘

2.3 SPL 关键函数

C
// common/spl/spl.c

void board_init_f(ulong dummy)
{
    /* 清零全局数据结构 */
    memset(gd, 0, sizeof(*gd));
    
    /* 初始化串口,用于调试输出 */
    preloader_console_init();
    
    /* 打印 SPL 版本信息 */
    debug("U-Boot SPL started\n");
}

void board_init_r(gd_t *dummy1, ulong dummy2)
{
    /* 初始化 DDR 内存 */
    dram_init();
    
    /* 从存储介质加载 U-Boot */
    spl_load_image();
    
    /* 跳转到 U-Boot */
    jump_to_image();
    
    /* 不会返回 */
}

阶段3:U-Boot 主程序

3.1 U-Boot 启动流程图

text
┌─────────────────────────────────────────────────────────────────────┐
│                        U-Boot 主程序启动流程                         │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 1. 汇编阶段 (start.S)                                               │
│    - 设置异常向量表                                                  │
│    - 设置CPU模式(SVC模式)                                           │
│    - 关闭中断、MMU、Cache                                           │
│    - 设置栈指针                                                      │
│    - 跳转到 _main                                                   │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 2. board_init_f() - 重定位前初始化                                   │
│    - initf_malloc()     - 初始化早期malloc                          │
│    - arch_cpu_init()    - CPU架构初始化                             │
│    - serial_init()      - 串口初始化                                │
│    - dram_init()        - DRAM初始化/检测                           │
│    - 计算重定位地址                                                  │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 3. relocate_code() - 代码重定位                                      │
│    - 将U-Boot从Flash复制到DDR高端地址                               │
│    - 修正指针和跳转地址                                              │
│    - 跳转到新地址继续执行                                            │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 4. board_init_r() - 重定位后初始化                                   │
│    - initr_caches()     - 启用Cache                                 │
│    - initr_malloc()     - 初始化完整malloc                          │
│    - initr_dm()         - 初始化设备模型                            │
│    - initr_mmc()        - 初始化MMC/SD                              │
│    - initr_env()        - 加载环境变量                              │
│    - initr_net()        - 初始化网络                                │
│    - run_main_loop()    - 进入主循环                                │
└─────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ 5. main_loop() - 主循环                                             │
│    - 等待 bootdelay 超时或用户按键                                   │
│    - 执行 bootcmd 或进入命令行                                       │
└─────────────────────────────────────────────────────────────────────┘

3.2 初始化序列详解 (init_sequence_f)

C
// common/board_f.c

static const init_fnc_t init_sequence_f[] = {
    setup_mon_len,           /* 计算U-Boot代码长度 */
    fdtdec_setup,            /* 设置设备树 */
    initf_malloc,            /* 早期内存分配器 */
    log_init,                /* 初始化日志系统 */
    initf_bootstage,         /* 启动阶段记录 */
    arch_cpu_init,           /* CPU架构初始化 */
    mach_cpu_init,           /* 机器级CPU初始化 */
    initf_dm,                /* 早期设备模型 */
    arch_cpu_init_dm,        /* DM相关CPU初始化 */
    timer_init,              /* 定时器初始化 */
    env_init,                /* 环境变量初始化 */
    init_baud_rate,          /* 设置波特率 */
    serial_init,             /* 串口初始化 ★ 此后可打印 */
    console_init_f,          /* 控制台初始化 */
    display_options,         /* 显示版本信息 */
    display_text_info,       /* 显示代码段信息 */
    announce_dram_init,      /* 打印DRAM初始化信息 */
    dram_init,               /* DRAM初始化 ★ */
    setup_dest_addr,         /* 设置目标地址 */
    reserve_round_4k,        /* 4K对齐 */
    reserve_mmu,             /* 预留MMU表空间 */
    reserve_video,           /* 预留显存 */
    reserve_malloc,          /* 预留malloc空间 */
    reserve_board_buf,       /* 预留板级缓冲 */
    reserve_global_data,     /* 预留全局数据 */
    reserve_fdt,             /* 预留设备树空间 */
    reserve_stacks,          /* 预留栈空间 */
    dram_init_banksize,      /* DRAM bank大小 */
    setup_dram_config,       /* DRAM配置 */
    display_new_sp,          /* 显示新栈指针 */
    reloc_fdt,               /* 重定位设备树 */
    setup_reloc,             /* 设置重定位参数 */
    NULL,
};

3.3 内存布局(重定位后)

text
┌─────────────────────────────────────────┐ ← DDR顶部
│              U-Boot 代码                │
├─────────────────────────────────────────┤
│              U-Boot BSS                 │
├─────────────────────────────────────────┤
│            Global Data (gd)             │
├─────────────────────────────────────────┤
│             Device Tree                 │
├─────────────────────────────────────────┤
│           malloc 区域                   │
├─────────────────────────────────────────┤
│              栈空间                     │
├─────────────────────────────────────────┤
│                                         │
│              空闲区域                   │
│        (用于加载内核等)                 │
│                                         │
├─────────────────────────────────────────┤ ← DDR底部
│          可能的保留区域                 │
└─────────────────────────────────────────┘ ← 0x80000000 (示例)

3.4 重定位后初始化序列 (init_sequence_r)

C
// common/board_r.c

static init_fnc_t init_sequence_r[] = {
    initr_trace,             /* 跟踪初始化 */
    initr_reloc,             /* 设置重定位完成标志 */
    initr_caches,            /* 启用Cache ★ */
    initr_reloc_global_data, /* 重定位全局数据 */
    initr_malloc,            /* 初始化malloc ★ */
    log_init,                /* 日志初始化 */
    initr_dm,                /* 设备模型初始化 ★ */
    initr_bootstage,         /* 启动阶段 */
    board_init,              /* 板级初始化 ★ */
    set_cpu_clk_info,        /* CPU时钟信息 */
    efi_memory_init,         /* EFI内存初始化 */
    stdio_init_tables,       /* stdio表 */
    serial_initialize,       /* 串口 */
    initr_announce,          /* 宣告重定位完成 */
    power_init_board,        /* 电源管理 */
    initr_flash,             /* Flash初始化 */
    initr_nand,              /* NAND初始化 */
    initr_mmc,               /* MMC/SD初始化 ★ */
    initr_env,               /* 环境变量 ★ */
    initr_secondary_cpu,     /* 次级CPU */
    stdio_add_devices,       /* 添加stdio设备 */
    initr_jumptable,         /* 跳转表 */
    console_init_r,          /* 完整控制台 */
    interrupt_init,          /* 中断初始化 */
    initr_enable_interrupts, /* 启用中断 */
    initr_ethaddr,           /* 以太网地址 */
    board_late_init,         /* 板级晚期初始化 */
    initr_net,               /* 网络初始化 ★ */
    run_main_loop,           /* 主循环 ★ */
    NULL,
};

阶段4:主循环与启动内核

4.1 main_loop() 流程

C
// common/main.c

void main_loop(void)
{
    const char *s;

    bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop");

    /* 自动启动倒计时 */
    s = bootdelay_process();
    if (cli_process_fdt(&s))
        cli_secure_boot_cmd(s);

    /* 执行预启动命令 */
    autoboot_command(s);

    /* 如果没有自动启动,进入命令行 */
    cli_loop();
}

4.2 自动启动流程

text
┌─────────────────────────────────────────────────────────────────┐
│                       main_loop()                               │
└─────────────────────────────────────────────────────────────────┘
               ┌──────────────────────────┐
               │  bootdelay_process()     │
               │  读取 bootdelay 环境变量  │
               └──────────────────────────┘
               ┌──────────────────────────┐
               │  打印倒计时              │
               │  Hit any key to stop     │
               │  autoboot: 3... 2... 1.. │
               └──────────────────────────┘
            ┌─────────────────┴─────────────────┐
            │                                   │
            ▼                                   ▼
    ┌───────────────┐                  ┌───────────────┐
    │  用户按键      │                  │   超时        │
    │  中断自动启动  │                  │   无用户输入  │
    └───────────────┘                  └───────────────┘
            │                                   │
            ▼                                   ▼
    ┌───────────────┐                  ┌───────────────┐
    │  cli_loop()   │                  │ run_command() │
    │  进入命令行   │                  │ 执行 bootcmd  │
    └───────────────┘                  └───────────────┘
            │                                   │
            ▼                                   ▼
    ┌───────────────┐                  ┌───────────────┐
    │ 等待用户输入  │                  │ bootm 命令    │
    │ => _          │                  │ 启动内核      │
    └───────────────┘                  └───────────────┘

4.3 bootm 启动内核流程

text
┌─────────────────────────────────────────────────────────────────┐
│  bootm 0xBF020000                                               │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 1. 解析镜像头 (bootm_find_os)                                   │
│    - 验证 Magic Number (0x27051956)                             │
│    - 读取镜像信息(类型、压缩方式、加载地址等)                    │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 2. 验证校验和 (image_check_hcrc, image_check_dcrc)              │
│    - 验证头部CRC                                                │
│    - 验证数据CRC                                                │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 3. 加载镜像 (bootm_load_os)                                     │
│    - 解压内核(如果是压缩镜像)                                  │
│    - 复制到 Load Address                                        │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 4. 准备启动参数 (boot_prep_linux)                               │
│    - 设置 bootargs                                              │
│    - 准备设备树或ATAG                                           │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 5. 跳转到内核 (boot_jump_linux)                                 │
│    - 关闭中断                                                   │
│    - 关闭Cache和MMU                                             │
│    - 跳转到 Entry Point                                         │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ 6. Linux 内核开始执行                                           │
│    - 不再返回U-Boot                                             │
└─────────────────────────────────────────────────────────────────┘

串口输出示例

text
# ==================== 完整启动日志示例 ====================

# ROM/SPL阶段(部分芯片可见)
U-Boot SPL 2021.04 (Apr 01 2021 - 12:00:00 +0800)
Trying to boot from MMC1

# U-Boot 主程序阶段
U-Boot 2021.04 (Apr 01 2021 - 12:00:00 +0800)

CPU:   ARM Cortex-A7 @ 1008MHz
Model: Example Board
DRAM:  512 MiB
MMC:   mmc@1c0f000: 0, mmc@1c11000: 1
Loading Environment from FAT... OK
In:    serial
Out:   serial
Err:   serial
Net:   eth0: ethernet@1c30000
Hit any key to stop autoboot:  3... 2... 1... 0

# 自动执行 bootcmd
=> bootm 0x42000000

## Booting kernel from Legacy Image at 42000000 ...
   Image Name:   Linux-5.10.0
   Image Type:   ARM Linux Kernel Image (uncompressed)
   Data Size:    4567890 Bytes = 4.4 MiB
   Load Address: 40008000
   Entry Point:  40008000
   Verifying Checksum ... OK
   Loading Kernel Image
   
Starting kernel ...

[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 5.10.0 ...
...

关键数据结构

global_data (gd)

C
// include/asm-generic/global_data.h

typedef struct global_data {
    bd_t *bd;                    /* 板级信息 */
    unsigned long flags;          /* 标志位 */
    unsigned int baudrate;        /* 波特率 */
    unsigned long cpu_clk;        /* CPU时钟 */
    unsigned long bus_clk;        /* 总线时钟 */
    unsigned long ram_base;       /* RAM基地址 */
    unsigned long ram_size;       /* RAM大小 */
    unsigned long ram_top;        /* RAM顶部 */
    unsigned long relocaddr;      /* 重定位地址 */
    unsigned long reloc_off;      /* 重定位偏移 */
    unsigned long new_gd;         /* 新的gd地址 */
    struct udevice *dm_root;      /* 设备模型根节点 */
    const void *fdt_blob;         /* 设备树指针 */
    void *env_buf;                /* 环境变量缓冲 */
    /* ... 更多字段 ... */
} gd_t;

源码目录结构

text
u-boot/
├── arch/                    # 架构相关代码
│   ├── arm/
│   │   ├── cpu/
│   │   │   └── armv7/
│   │   │       └── start.S      # ★ ARM启动汇编
│   │   └── lib/
│   │       └── crt0.S           # ★ C运行时启动
│   └── mips/
│       └── cpu/
│           └── start.S          # MIPS启动汇编
├── board/                   # 板级代码
│   └── <vendor>/
│       └── <board>/
│           └── board.c          # 板级初始化
├── common/                  # 通用代码
│   ├── board_f.c               # ★ board_init_f
│   ├── board_r.c               # ★ board_init_r  
│   ├── main.c                  # ★ main_loop
│   └── spl/
│       └── spl.c               # SPL通用代码
├── cmd/                     # 命令实现
│   ├── bootm.c                 # bootm命令
│   └── ...
├── drivers/                 # 驱动程序
│   ├── serial/
│   ├── mmc/
│   └── net/
└── include/                 # 头文件
    └── configs/
        └── <board>.h           # 板级配置

启动流程时间线

text
时间 ──────────────────────────────────────────────────────────────▶

│ ROM    │     SPL      │           U-Boot           │   Kernel
│        │              │                            │
│ 10ms   │    100ms     │          500ms             │
│◀──────▶│◀────────────▶│◀──────────────────────────▶│◀─────────
│        │              │                            │
│ 加载   │ 初始化DDR   │ 硬件初始化 │ 等待用户 │启动│ 内核启动
│ SPL    │ 加载U-Boot  │ 加载环境  │ bootdelay│内核│
│        │              │           │ 3秒...   │    │

调试启动流程的方法

1. 增加调试输出

C
// 在关键位置添加
debug("Reached %s\n", __func__);
printf("DEBUG: value = 0x%x\n", value);

2. 使用 bootstage

Bash
# 在U-Boot命令行
bootstage report

3. 串口抓取完整日志

Bash
picocom -b 115200 --log-file boot_log.txt /dev/ttyUSB0

总结

text
┌─────────────────────────────────────────────────────────────────┐
│                     U-Boot 启动流程总结                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. CPU复位 → 执行ROM/SPL                                       │
│        ↓                                                        │
│  2. 初始化DDR内存                                               │
│        ↓                                                        │
│  3. 加载U-Boot到DDR                                             │
│        ↓                                                        │
│  4. board_init_f() → 重定位前初始化                             │
│        ↓                                                        │
│  5. relocate_code() → 代码重定位到DDR高端                       │
│        ↓                                                        │
│  6. board_init_r() → 完整硬件初始化                             │
│        ↓                                                        │
│  7. main_loop() → 等待用户或自动启动                            │
│        ↓                                                        │
│  8. bootm → 加载并启动Linux内核                                 │
│        ↓                                                        │
│  9. Linux接管系统                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
 
 

一、信息查看类命令

help / ? - 查看帮助

# 查看所有命令列表
help

# 查看特定命令的详细用法
help md
help printenv

# 简写形式
?
? md

version - 查看U-Boot版本

Bash
version

输出示例:

text
U-Boot 1.1.4 (Oct 15 2018 - 14:32:05)

bdinfo - 查看板级信息

Bash
bdinfo

输出示例:

text
boot_params = 0x80000100
memstart    = 0x80000000
memsize     = 0x04000000      # 内存大小 64MB
flashstart  = 0xBF000000      # Flash起始地址 ★重要
flashsize   = 0x00800000      # Flash大小 8MB ★重要
flashoffset = 0x00000000
ethaddr     = 00:11:22:33:44:55
ip_addr     = 192.168.1.1
baudrate    = 115200

应用场景:提取固件前必须查看Flash地址和大小


flinfo - 查看Flash信息

Bash
flinfo

输出示例:

text
Bank # 1: CFI conformant FLASH (16 x 16)  Size: 8 MB in 128 Sectors
  Sector Start Addresses:
  BF000000  BF010000  BF020000  BF030000  BF040000
  BF050000  BF060000  BF070000  BF080000  BF090000
  ...

应用场景:了解Flash分区布局


coninfo - 查看控制台信息

Bash
coninfo

输出示例:

text
List of available devices:
serial   80000003 SIO stdin stdout stderr

二、环境变量类命令

printenv - 打印环境变量

Bash
# 打印所有环境变量
printenv

# 打印特定变量
printenv bootcmd
printenv bootargs
printenv ipaddr

输出示例:

text
bootdelay=3
baudrate=115200
ethaddr=00:11:22:33:44:55
ipaddr=192.168.1.1
serverip=192.168.1.100
bootcmd=bootm 0xBF020000
bootargs=console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs

★ 关键变量说明:

变量说明示例值
bootcmd 自动启动命令 bootm 0xBF020000
bootargs 内核启动参数 console=ttyS0,115200 root=/dev/mtdblock2
bootdelay 启动延时(秒) 3
ipaddr 本机IP 192.168.1.1
serverip TFTP服务器IP 192.168.1.100
ethaddr MAC地址 00:11:22:33:44:55

setenv - 设置环境变量

Bash
# 基本语法
setenv <变量名> <值>

# 设置IP地址
setenv ipaddr 192.168.1.1

# 设置TFTP服务器地址
setenv serverip 192.168.1.100

# 设置启动延时为5秒
setenv bootdelay 5

# 设置启动参数(注意引号)
setenv bootargs 'console=ttyS0,115200 root=/dev/mtdblock2'

# 修改自动启动命令
setenv bootcmd 'tftp 0x80000000 firmware.bin; bootm 0x80000000'

# 删除变量(不带值)
setenv myvar

saveenv - 保存环境变量

Bash
# 将当前环境变量保存到Flash
saveenv

输出示例:

text
Saving Environment to Flash...
Erasing Flash...
Writing to Flash... done

⚠️ 警告:saveenv会写入Flash,确保修改正确再保存


环境变量实战示例

Bash
# 场景:配置网络启动

# 1. 设置网络参数
setenv ipaddr 192.168.1.1
setenv serverip 192.168.1.100
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0

# 2. 设置TFTP启动命令
setenv bootcmd_tftp 'tftp 0x80000000 uImage; bootm 0x80000000'

# 3. 保存
saveenv

三、内存操作类命令

md - 显示内存内容(Memory Display)

Bash
# 基本语法
md[.b|.w|.l] <地址> [数量]

# .b = byte (1字节)
# .w = word (2字节)  
# .l = long (4字节,默认)

# 示例:从0xBF000000开始读取16个长字(64字节)
md 0xBF000000 10

# 按字节显示
md.b 0xBF000000 20

# 按双字节显示
md.w 0xBF000000 10

输出示例:

text
bf000000: 27051956 70a33200 5a8e4f18 00158e80    '..Vp.2.Z.O.....
bf000010: 80000000 80000000 9fc56c38 00000000    ..........l8....
bf000020: 4c5a4d41 05055658 00000000 00000000    LZMA..VX........
bf000030: 00000000 00000000 00000000 00000000    ................

固件提取实战

Bash
# 步骤1:查看Flash信息
bdinfo
# 得到 flashstart=0xBF000000, flashsize=0x800000

# 步骤2:计算读取数量
# 0x800000 / 4 = 0x200000 (按长字计算)

# 步骤3:完整转储Flash
md 0xBF000000 0x200000

# 如果只想看前1KB
md 0xBF000000 0x100

mw - 写入内存(Memory Write)

Bash
# 基本语法
mw[.b|.w|.l] <地址> <值> [数量]

# 在0x80000000写入单个值0x12345678
mw 0x80000000 0x12345678

# 在0x80000000开始填充100个0x00
mw 0x80000000 0x00 100

# 按字节写入
mw.b 0x80000000 0xFF 0x100

mm - 交互式修改内存

Bash
# 基本语法
mm[.b|.w|.l] <地址>

# 交互式修改内存(地址自动递增)
mm 0x80000000

操作示例:

text
80000000: 12345678 ? AABBCCDD    # 输入新值
80000004: 00000000 ? 11223344    # 自动跳到下一地址
80000008: 00000000 ? .           # 输入 . 退出

nm - 修改固定地址内存

Bash
# 基本语法
nm[.b|.w|.l] <地址>

# 反复修改同一地址(用于调试硬件寄存器)
nm 0x80000000

操作示例:

text
80000000: 12345678 ? AABBCCDD    # 修改
80000000: AABBCCDD ? 11111111    # 还是同一地址
80000000: 11111111 ? .           # 输入 . 退出

cp - 内存复制

Bash
# 基本语法
cp[.b|.w|.l] <源地址> <目标地址> <数量>

# 从Flash复制到RAM
cp 0xBF000000 0x80000000 0x10000

# 示例:复制64KB数据
cp.b 0xBF000000 0x80000000 0x10000

cmp - 内存比较

Bash
# 基本语法
cmp[.b|.w|.l] <地址1> <地址2> <数量>

# 比较两段内存是否相同
cmp 0x80000000 0x80100000 0x100

输出示例:

text
# 相同时
Total of 256 word(s) were the same

# 不同时
word at 0x80000010 (0x12345678) != word at 0x80100010 (0x00000000)

crc32 - 计算校验和

Bash
# 基本语法
crc32 <地址> <长度> [存储地址]

# 计算0x80000000开始,长度0x100000的CRC32
crc32 0x80000000 0x100000

# 将结果存储到指定地址
crc32 0x80000000 0x100000 0x80200000

输出示例:

text
CRC32 for 80000000 ... 800fffff ==> 1a2b3c4d

应用场景:验证数据传输/写入是否正确


mtest - 内存测试

Bash
# 基本语法
mtest [起始地址] [结束地址] [模式]

# 测试一段内存
mtest 0x80000000 0x81000000

# 使用特定模式测试
mtest 0x80000000 0x81000000 0xAAAA5555

⚠️ 警告:会破坏指定范围内的数据


四、启动类命令

常见应用场景

bootelf  执行一个elf文件
┌─────────────────────────────────────────────────────────────────┐
│                    bootelf 典型应用场景                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  1. 裸机程序开发调试                                            │
│     - 不需要 Linux,直接运行简单程序                            │
│     - 快速测试硬件驱动                                          │
│                                                                 │
│  2. VxWorks 实时操作系统                                        │
│     - VxWorks 常用 ELF 格式                                     │
│     - 工业控制、航空航天领域                                    │
│                                                                 │
│  3. 固件开发测试                                                │
│     - 编译器直接输出 ELF                                        │
│     - 无需额外转换为 uImage                                     │
│                                                                 │
│  4. 调试工具                                                    │
│     - 内存测试程序                                              │
│     - 硬件诊断程序                                              │
│                                                                 │
│  5. 多核启动                                                    │
│     - 为从核加载独立程序                                        │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

示例1:从内存地址启动 ELF

Bash
# 假设 ELF 文件已经加载到内存 0x80000000

# 查看内存确认是 ELF 文件
=> md 0x80000000 4
80000000: 464c457f 00010101 00000000 00000000    .ELF............
#         ^^^^^^^
#         7F 'E' 'L' 'F' = ELF魔数

# 启动 ELF 镜像
=> bootelf 0x80000000

## Starting application at 0x80001000 ...
Hello from ELF program!

 

 

bootm - 从内存启动镜像

# 基本语法
bootm [镜像地址] [ramdisk地址] [设备树地址]

# 从Flash直接启动内核
bootm 0xBF020000

# 从RAM启动(先用tftp加载)
tftp 0x80000000 uImage
bootm 0x80000000

# 带设备树启动
bootm 0x80000000 - 0x80F00000

boot / bootd - 执行默认启动命令

printenv bootcmd  # 查看 bootcmd 环境变量
输出示例:bootcmd=bootm 0xBF020000 boot  # 方式1:使用 boot 命令 bootd  # 方式2:使用 bootd 命令 run bootcmd  # 方式3:手动 run bootcmd bootm 0xBF020000  # 方式4:直接输入 bootcmd 的内容 以上四种方式完全等价,都会执行 bootm 0xBF020000

go - 跳转执行

Bash
# 基本语法
go <地址> [参数...]

# 跳转到指定地址执行代码
go 0x80000000

# 带参数
go 0x80000000 arg1 arg2

与bootm的区别:

  • bootm:解析镜像头,设置启动参数
  • go:直接跳转执行,不做任何处理

run - 运行环境变量中的命令

Bash
# 基本语法
run <变量名>

# 执行bootcmd
run bootcmd

# 自定义命令序列
setenv myboot 'tftp 0x80000000 uImage; bootm 0x80000000'
run myboot

# 执行多个变量
run cmd1 cmd2 cmd3

reset - 重启系统

Bash
reset

五、网络类命令

网络配置

Bash
# 设置本机IP
setenv ipaddr 192.168.1.1

# 设置服务器IP(TFTP服务器)
setenv serverip 192.168.1.100

# 设置网关
setenv gatewayip 192.168.1.1

# 设置子网掩码
setenv netmask 255.255.255.0

# 设置MAC地址
setenv ethaddr 00:11:22:33:44:55

tftpboot - TFTP下载并启动

Bash
# 基本语法
tftpboot [加载地址] [文件名]

# 下载文件到RAM
tftpboot 0x80000000 uImage

# 下载后启动
tftpboot 0x80000000 uImage; bootm 0x80000000

# 下载固件用于刷写
tftpboot 0x80000000 firmware.bin

TFTP服务器设置(Linux端):

Bash
# 安装TFTP服务器
sudo apt install tftpd-hpa

# 配置文件 /etc/default/tftpd-hpa
TFTP_DIRECTORY="/tftpboot"
TFTP_OPTIONS="--secure --create"

# 放置文件
sudo cp uImage /tftpboot/
sudo chmod 644 /tftpboot/uImage

# 启动服务
sudo systemctl restart tftpd-hpa

bootp - BOOTP/DHCP获取IP

Bash
# 通过DHCP获取IP地址
bootp

rarpboot - RARP启动

Bash
# 通过RARP获取IP并启动
rarpboot

六、Flash操作类命令

erase - 擦除Flash

Bash
# 基本语法
erase <起始地址> <结束地址>
erase <起始地址> +<长度>

# 擦除整个Flash
erase all

# 擦除指定范围
erase 0xBF000000 0xBF00FFFF

# 擦除指定长度
erase 0xBF000000 +0x10000

# 擦除指定扇区
erase 1:0-2    # Bank 1, 扇区0到2

⚠️ 警告:擦除后数据不可恢复!


protect - Flash写保护

Bash
# 基本语法
protect on/off <起始地址> <结束地址>
protect on/off all

# 关闭写保护(刷写前必须)
protect off all

# 关闭指定范围保护
protect off 0xBF000000 0xBF0FFFFF

# 开启保护
protect on all

Flash刷写完整流程

Bash
# ★★★ 刷写固件完整示例 ★★★

# 步骤1:配置网络
setenv ipaddr 192.168.1.1
setenv serverip 192.168.1.100

# 步骤2:下载固件到RAM
tftpboot 0x80000000 firmware.bin

# 步骤3:关闭Flash写保护
protect off all

# 步骤4:擦除Flash(根据固件大小调整范围)
erase 0xBF000000 +0x800000

# 步骤5:将RAM中的数据写入Flash
cp.b 0x80000000 0xBF000000 0x800000

# 步骤6:校验
crc32 0x80000000 0x800000
crc32 0xBF000000 0x800000
# 两个CRC32值应该相同

# 步骤7:重启
reset

七、其他实用命令

echo - 打印信息

Bash
# 打印文本
echo "Hello U-Boot"

# 打印变量值
echo $ipaddr
echo "IP is: $ipaddr"

sleep - 延时

Bash
# 延时N秒
sleep 5

# 在脚本中使用
setenv mytest 'echo Starting; sleep 2; echo Done'
run mytest

loop - 无限循环读取

Bash
# 基本语法
loop <地址> <长度>

# 无限循环读取(用于调试)
loop 0x80000000 0x10
# Ctrl+C 退出

itest - 整数比较

Bash
# 基本语法
itest[.b|.w|.l] <值1> <操作符> <值2>

# 操作符: -eq, -ne, -lt, -gt, -le, -ge, ==, !=, <, >, <=, >=

# 示例:比较并条件执行
itest 1 -lt 2 && echo "1 < 2"
itest $filesize -gt 0x10000 && echo "File > 64KB"

base - 设置地址偏移

Bash
# 查看当前基地址
base

# 设置基地址偏移
base 0x80000000

# 之后的地址都会加上这个偏移
md 0x100    # 实际读取 0x80000100

loadb - 串口传输文件(Kermit协议)

Bash
# 通过串口接收文件到指定地址
loadb 0x80000000

# 然后在电脑端用kermit发送文件

loads - 串口传输S-Record

Bash
# 通过串口接收S-Record格式文件
loads

# 或指定偏移地址
loads 0x80000000

八、实战命令组合

场景1:固件备份

Bash
# 设置日志记录(在电脑端picocom)
picocom -b 115200 --log-file backup.txt /dev/ttyUSB0

# 在U-Boot中执行
bdinfo                           # 查看flash地址和大小
md 0xBF000000 0x200000          # 转储整个Flash

场景2:TFTP刷机

Bash
# 网络配置
setenv ipaddr 192.168.1.1
setenv serverip 192.168.1.100

# 下载并刷写
tftpboot 0x80000000 openwrt.bin
protect off all
erase 0xBF020000 +0x7E0000
cp.b 0x80000000 0xBF020000 $filesize
reset

场景3:救砖 - 刷写Bootloader

Bash
# ⚠️ 危险操作!错误会导致彻底变砖

# 下载新U-Boot
tftpboot 0x80000000 uboot.bin

# 刷写(假设U-Boot在前64KB)
protect off 0xBF000000 0xBF00FFFF
erase 0xBF000000 0xBF00FFFF
cp.b 0x80000000 0xBF000000 0x10000

# 不要立即重启,先验证
crc32 0x80000000 0x10000
crc32 0xBF000000 0x10000
# 确认相同后再重启
reset

场景4:修改启动参数

Bash
# 查看当前参数
printenv bootargs

# 修改为单用户模式(绕过密码)
setenv bootargs 'console=ttyS0,115200 root=/dev/mtdblock2 init=/bin/sh'
boot

# 添加调试输出
setenv bootargs 'console=ttyS0,115200 root=/dev/mtdblock2 debug'
boot

命令速查表

类别命令用途
信息 bdinfo 查看板级信息
信息 flinfo 查看Flash信息
信息 printenv 查看环境变量
内存 md 显示内存
内存 mw 写入内存
内存 cp 复制内存
内存 crc32 校验和
变量 setenv 设置变量
变量 saveenv 保存变量
网络 tftpboot TFTP下载
Flash erase 擦除Flash
Flash protect 写保护
启动 bootm 启动镜像
启动 reset 重启
# ============ 实际操作过程 ============ # 1. 首先查看 bootcmd 内容 => printenv bootcmd bootcmd=bootm 0xBF020000 # 2. 执行 boot 命令 => boot # 3. 实际发生的事情(等同于手动输入): => bootm 0xBF020000 ## Booting image at bf020000 ... Image Name: Linux Kernel Image Image Type: MIPS Linux Kernel Image (lzma compressed) Data Size: 1048576 Bytes = 1 MB Load Address: 80000000 Entry Point: 80000000 Verifying Checksum ... OK Uncompressing Kernel Image ... OK Starting kernel ... [ 0.000000] Linux version 4.14.90 ... [ 0.000000] bootconsole [early0] enabled ...

posted on 2026-01-02 10:41  GKLBB  阅读(3)  评论(0)    收藏  举报