菜鸟科技网

uboot go 命令

go 命令是 U-Boot 中一个非常核心和常用的命令,它的作用是将程序控制权从 U-Boot 引导加载程序转移到指定的内存地址,并开始执行

uboot go 命令-图1
(图片来源网络,侵删)

当你使用 go 命令时,U-Boot 就会“放手”,让 CPU 去运行另一个程序(Linux 内核)。


基本语法

go 命令的基本语法非常简单:

go <address> [argument ...]
  • <address>: 这是必须的参数,它指定了你想要启动的程序在内存中的起始地址,这个地址通常是之前通过 loadbloadyloadmtftpmmc read 等命令加载到 RAM 中的程序的入口点。
  • [argument ...]: 这是可选的参数,你可以传递一个或多个参数给正在启动的程序,这些参数通常用于向内核传递启动信息(bootargs 环境变量中的内容)。

工作原理

当你执行 go <address> 时,U-Boot 内部会做以下几件事:

  1. 参数准备: 如果你在 go 命令后跟了参数,U-Boot 会将这些参数按照特定规则(通常是 Linux 内核期望的格式)存放在内存的某个固定位置(bootargs 环境变量指向的地址,或者一个特定的 atag/dtb 内存区域)。
  2. 设置 CPU 状态: 在跳转到新程序之前,CPU 的一些关键寄存器(如 ARM 架构中的 r0, r1, r2)会被设置好,以符合目标程序(如 Linux 内核)的启动约定。
    • r0 通常设置为 0
    • r1 通常指向机器类型 ID。
    • r2 指向启动参数(atag 或设备树 dtb)的内存地址。
  3. 跳转执行: U-Boot 执行一条跳转指令(ARM 中的 BX 指令),将 CPU 的程序计数器 设置为你指定的 <address>,从此刻起,CPU 开始执行该地址处的指令,U-Boot 的代码就不再被运行了。

常见用法示例

go 命令最常见的用途就是启动 Linux 内核,下面我们通过几个场景来看它的具体使用。

uboot go 命令-图2
(图片来源网络,侵删)

从 TFTP 服务器加载并启动内核(适用于旧版 U-Boot 或无设备树的情况)

假设你的内核镜像 uImage 已经通过 TFTP 加载到 RAM 的 0x81000000 地址。

  1. 加载内核

    tftp 0x81000000 uImage

    如果成功,你会看到数据传输的统计信息。

  2. 启动内核

    uboot go 命令-图3
    (图片来源网络,侵删)
    go 0x81000000

    执行此命令后,系统会尝试启动位于 0x81000000 的内核,由于没有传递参数,内核可能会使用默认的 bootargs 或者直接报错。

启动内核并传递启动参数

更常见的情况是,你需要传递启动参数(如根文件系统位置、内核命令行等),通常我们会将这些参数保存在 bootargs 环境变量中。

  1. 设置启动参数

    setenv bootargs 'console=ttySAC0,115200 root=/dev/mmcblk0p3 rw rootwait'
    saveenv
  2. 加载内核

    tftp 0x81000000 uImage
  3. 启动内核并传递参数

    go 0x81000000 ${bootargs}

    在这个例子中,${bootargs} 会被展开成 'console=...' 字符串,并作为参数传递给内核,U-Boot 会负责将这些参数正确地传递给内核。

启动一个简单的应用程序(如 "Hello World" 程序)

go 命令不仅可以启动内核,也可以启动任何你加载到内存中的程序,假设你有一个编译好的裸机程序 hello.bin

  1. 加载应用程序

    loadb 0x81000000  # 通过串口 Y-Modem 协议加载
    # 或者
    tftp 0x81000000 hello.bin # 通过 TFTP 加载
  2. 运行应用程序

    go 0x81000000

    系统会跳转到 hello.bin 的入口点开始执行,如果这个程序只是在串口上打印 "Hello World",那么你就能在终端上看到输出。


bootcmdbootm 的关系

初学者经常会混淆 gobootcmdbootm,它们之间的关系如下:

  • bootcmd: 这是一个环境变量,它包含了系统启动时自动执行的命令序列,它通常是 U-Boot 的“默认启动脚本”。
  • go: 一个手动执行的命令,用于跳转到任意内存地址并运行程序,它功能简单直接。
  • bootm: 这是更常用、更强大的启动命令bootm 是 "boot image" 的缩写,它专门用于启动 U-Boot 支持的特定格式的镜像文件(如 uImagezImage、FIT image)。

bootmgo 的关键区别:

特性 go 命令 bootm 命令
功能 直接跳转执行,不关心文件格式。 识别并解析特定格式的镜像文件。
镜像格式 可以执行任何加载到内存的二进制文件(裸机程序、内核等)。 主要用于启动 uImagezImageFIT image 等引导镜像。
内部处理 简单的跳转。 会解压镜像(如果被压缩)、验证镜像(如 CRC)、根据架构设置寄存器、传递设备树或 atag,然后才跳转到内核入口。
使用场景 手动调试、运行简单的测试程序、启动非标准格式的程序。 标准的、自动化的 Linux 内核启动流程。

bootcmd 中通常使用 bootm 而不是 go

一个典型的 bootcmd 看起来像这样:

setenv bootcmd 'tftp 0x81000000 ${kernel_image}; tftp 0x82000000 ${dtb_file}; bootm 0x81000000 - 0x82000000'

这里使用 bootm 是因为它知道如何处理 uImage 和设备树,并能正确地将它们传递给内核,如果换成 go,U-Boot 将无法识别设备树,导致启动失败。


  • go 是一个底层的、直接的跳转命令
  • 它的核心作用是:PC = <address>
  • 主要用于手动调试或启动非标准格式的程序
  • 在标准的 Linux 启动流程中,更常用的是 bootm 命令,因为它能处理镜像格式、解压、校验和传递设备树等复杂工作。
  • 在 U-Boot 的自动化启动(通过 bootcmd)中,几乎总是使用 bootm 而不是 go

理解 go 命令有助于你深入理解 U-Boot 如何将控制权交给操作系统,以及底层 CPU 是如何工作的。

分享:
扫描分享到社交APP
上一篇
下一篇