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

当你使用 go 命令时,U-Boot 就会“放手”,让 CPU 去运行另一个程序(Linux 内核)。
基本语法
go 命令的基本语法非常简单:
go <address> [argument ...]
<address>: 这是必须的参数,它指定了你想要启动的程序在内存中的起始地址,这个地址通常是之前通过loadb、loady、loadm、tftp、mmc read等命令加载到 RAM 中的程序的入口点。[argument ...]: 这是可选的参数,你可以传递一个或多个参数给正在启动的程序,这些参数通常用于向内核传递启动信息(bootargs环境变量中的内容)。
工作原理
当你执行 go <address> 时,U-Boot 内部会做以下几件事:
- 参数准备: 如果你在
go命令后跟了参数,U-Boot 会将这些参数按照特定规则(通常是 Linux 内核期望的格式)存放在内存的某个固定位置(bootargs环境变量指向的地址,或者一个特定的atag/dtb内存区域)。 - 设置 CPU 状态: 在跳转到新程序之前,CPU 的一些关键寄存器(如 ARM 架构中的
r0,r1,r2)会被设置好,以符合目标程序(如 Linux 内核)的启动约定。r0通常设置为0。r1通常指向机器类型 ID。r2指向启动参数(atag或设备树dtb)的内存地址。
- 跳转执行: U-Boot 执行一条跳转指令(ARM 中的
BX指令),将 CPU 的程序计数器 设置为你指定的<address>,从此刻起,CPU 开始执行该地址处的指令,U-Boot 的代码就不再被运行了。
常见用法示例
go 命令最常见的用途就是启动 Linux 内核,下面我们通过几个场景来看它的具体使用。

从 TFTP 服务器加载并启动内核(适用于旧版 U-Boot 或无设备树的情况)
假设你的内核镜像 uImage 已经通过 TFTP 加载到 RAM 的 0x81000000 地址。
-
加载内核
tftp 0x81000000 uImage
如果成功,你会看到数据传输的统计信息。
-
启动内核
(图片来源网络,侵删)go 0x81000000
执行此命令后,系统会尝试启动位于
0x81000000的内核,由于没有传递参数,内核可能会使用默认的bootargs或者直接报错。
启动内核并传递启动参数
更常见的情况是,你需要传递启动参数(如根文件系统位置、内核命令行等),通常我们会将这些参数保存在 bootargs 环境变量中。
-
设置启动参数
setenv bootargs 'console=ttySAC0,115200 root=/dev/mmcblk0p3 rw rootwait' saveenv
-
加载内核
tftp 0x81000000 uImage
-
启动内核并传递参数
go 0x81000000 ${bootargs}在这个例子中,
${bootargs}会被展开成'console=...'字符串,并作为参数传递给内核,U-Boot 会负责将这些参数正确地传递给内核。
启动一个简单的应用程序(如 "Hello World" 程序)
go 命令不仅可以启动内核,也可以启动任何你加载到内存中的程序,假设你有一个编译好的裸机程序 hello.bin。
-
加载应用程序
loadb 0x81000000 # 通过串口 Y-Modem 协议加载 # 或者 tftp 0x81000000 hello.bin # 通过 TFTP 加载
-
运行应用程序
go 0x81000000
系统会跳转到
hello.bin的入口点开始执行,如果这个程序只是在串口上打印 "Hello World",那么你就能在终端上看到输出。
与 bootcmd 和 bootm 的关系
初学者经常会混淆 go、bootcmd 和 bootm,它们之间的关系如下:
bootcmd: 这是一个环境变量,它包含了系统启动时自动执行的命令序列,它通常是 U-Boot 的“默认启动脚本”。go: 一个手动执行的命令,用于跳转到任意内存地址并运行程序,它功能简单直接。bootm: 这是更常用、更强大的启动命令。bootm是 "boot image" 的缩写,它专门用于启动 U-Boot 支持的特定格式的镜像文件(如uImage、zImage、FIT image)。
bootm 和 go 的关键区别:
| 特性 | go 命令 |
bootm 命令 |
|---|---|---|
| 功能 | 直接跳转执行,不关心文件格式。 | 识别并解析特定格式的镜像文件。 |
| 镜像格式 | 可以执行任何加载到内存的二进制文件(裸机程序、内核等)。 | 主要用于启动 uImage、zImage、FIT 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 是如何工作的。
