# bootloader 使用说明

## bootloader 简介

在嵌入式 Linux 系统中， Bootloader（引导加载程序）是至关重要的组件，承担着硬件初始化、操作系统加载和安全验证等关键任务。其主要功能包括：

1. **硬件初始化**：配置 CPU 时钟频率、内存控制器等基础硬件设置，确保系统在启动时进入稳定的工作状态。

2. **操作系统加载**：从存储介质（如 NAND Flash、eMMC、SD 卡等）加载 Linux 内核映像（通常为压缩格式），并将控制权交给内核入口点。

3. **安全验证**：通过 CRC 校验、数字签名或哈希算法（如 SHA-256）验证固件的完整性和合法性，防止恶意代码的注入。

4. **传递启动参数**：Bootloader 会将必要的启动参数（如内存大小、CPU 架构信息和内核命令行参数）传递给 Linux 内核，确保内核能够顺利启动并运行。

[U-Boot (Universal Bootloader)](https://docs.u-boot.org/en/latest/) 是嵌入式 Linux 中最广泛使用的 Bootloader，它提供了高度灵活的配置选项，支持多种硬件平台和存储介质。

**注意**：在本系统中，整个 Bootloader 分为下面几个阶段：

- **BL1**： Bootloader Level 1，它是存储在芯片 IROM 中的一段程序，也可称之为 **Bootrom**，主要负责初始化基本硬件功能。
- **BL2**： Bootloader Level 2，bootloader 的阶段二，主要负责硬件初始化以及安全校验。
- **BL31**： Bootloader Level 3_1，主要执行与安全有关的操作。
- **BL33/U-Boot**： Bootloader Level 3_3，在本系统中 BL33 即为的广义 [U-Boot](https://docs.u-boot.org/en/latest/)。

这样的启动流程是 ​ARM **Trusted Firmware** （TF，可信固件） 架构中的典型多阶段引导设计，这样可以实现安全启动和硬件隔离。

**特别说明：**
本文中出现的 `bootloader` 指整个 **引导加载程序**，`U-Boot` 指 bootloader 流程中 **BL33** 阶段，即 **U-Boot**。

### bootloader 配置与编译

本系统中，对于 bootloader 配置的相关内容，用户一般只需关注 U-Boot 阶段的配置，具体可以参考 [配置 U-Boot 选项参数](../0-Configure_Kernel_And_Uboot.html#span-id-config-uboot-uboot) 章节。

完成配置后，可以使用下面命令完成 bootloader 镜像的编译与清理：

```bash
# 单独编译 uboot
./bd.sh uboot
# 单独 clean uboot
./bd.sh uboot clean
# 单独 distclean uboot
./bd.sh uboot distclean
```

关于镜像编译的详细介绍可以参考 [编译过程及命令](../../bsp_develop.html#span-id-compilation-process) 章节。

### bootloader 关键文件

下面介绍 BSP 源码包中 bootloader 的关键文件。

#### 配置文件

```bash
# 配置文件目录
uboot/configs
# X5 相关配置文件
hobot_x5_auto_defconfig
hobot_x5_evb_nand_defconfig
hobot_x5_fpga_defconfig
hobot_x5_soc_defconfig
hobot_x5_svb_defconfig
hobot_x5_svb_nand_defconfig
```

在板级配置文件 `device/horizon/x5/board_xxx_config.mk` 会指定 U-Boot 使用的选项配置文件，关于板级配置文件的详细介绍可以参考 [U-Boot 选项配置](../../board_bring_up.html#span-id-uboot-option-config-u-boot) 章节。

#### 设备树文件

```bash
# 设备树文件目录
uboot/arch/arm/dts/x5.dtsi/
# X5 相关设备树文件
hobot-x5.dts
x5-fpga.dtsi
x5-soc.dtsi
x5-svb.dtsi
x5.dtsi
x5-rdk.dtsi
pinmux-func.dtsi
```

U-Boot 下新增设备树文件的具体方法可以参考 [新增 U-Boot 下的设备树](../../board_bring_up.html#span-id-new-uboot-dts-u-boot) 章节。

#### 平台专属文件

```bash
# 平台芯片硬件抽象层目录
uboot/arch/arm/mach-horizon
# 包括下面文件
├── Kconfig
├── Makefile
├── lowlevel_init.S
└── x5
    ├── Kconfig
    ├── Makefile
    ├── boot_info.c
    ├── cpu.c
    ├── fdt_setup.c
    ├── x5_board.c
    ├── x5_efuse.c
    ├── x5_ion_setup.c
    └── x5_rpmb.c
```

其中 `uboot/arch/arm/mach-horizon/x5` 目录包含了针对 X5 芯片的硬件抽象层文件，其中的代码主要用于直接操作芯片的内部寄存器，属于启动过程中的最早执行模块，确保芯片硬件资源的正确初始化。

```bash
# 平台硬件配置文件目录
uboot/board/horizon/
# 包括下面文件
├── common
│   ├── Makefile
│   ├── hb_sdhc_boot.c
│   └── horizon_dfu.c
└── x5
    ├── MAINTAINERS
    ├── Makefile
    ├── spi.c
    ├── x5-aarch32.its
    ├── x5.c
    └── x5.its
```

其中 `uboot/board/horizon/x5` 目录包含 X5 芯片的硬件配置文件，负责板级支持，包括维护信息、构建配置、 SPI 驱动、板级初始化代码，以及生成引导镜像所需的配置文件。

## bootloader 启动流程

### bootloader 启动流程分析

X5 平台的 bootloader 启动流程如下：

![bootloader_startup_process](../_static/_images/bootloader_user_guide/bootloader_startup_process.png)

**bootloader 启动过程概述**：

1. **BL1 阶段 (Bootloader Level 1)**：  
   该阶段负责初始化基本硬件功能，检查 eMMC 配置，并加载 BL2 的配置文件。在此过程中， BL1 对 BL2 的签名和哈希值进行验证，确保固件的完整性和来源。成功验证后， BL1 解密并启动 BL2 。

2. **BL2 阶段 (Bootloader Level 2)**：  
   BL2 继续完成硬件初始化，尤其是 DDR 的配置，并加载 DDR 配置文件，同时进行哈希值验证。在 DDR 初始化完成后， BL2 加载并验证 BL31 配置文件的签名和哈希值，确保其安全性。验证通过后， BL2 启动 BL31 。  
   **进入安全世界**： BL2 启动 BL31 后，系统进入 **安全世界** (Secure World)，准备执行安全相关的初始化任务。

3. **BL31 阶段 (Bootloader Level 31)**：  
   BL31 负责初始化安全功能，并启动 **[OP-TEE](https://optee.readthedocs.io/en/latest/)**（ Open Portable Trusted Execution Environment，开放可信执行环境）。在 OP-TEE 完成安全环境初始化后，控制权返回 BL31 ，并通过 [PTA](https://optee.readthedocs.io/en/latest/architecture/trusted_applications.html#pseudo-trusted-applications) (Pseudo Trusted Application) 和 [ETA](https://optee.readthedocs.io/en/latest/architecture/trusted_applications.html#early-ta) (Early Trusted Application, Early TA) 执行安全相关任务。  
   **安全世界操作**： BL31 和 OP-TEE 的运行都在安全世界中完成，确保整个启动过程的安全性。

4. **OP-TEE 阶段**：  
   此阶段加载 OP-TEE 的 PTA 和 Early TA，提供加密、密钥管理等安全服务。这些操作均在安全世界中执行，确保安全任务的隔离性和安全性。

5. **切换到普通世界**：  
   在 BL31 完成安全任务后，系统准备切换到 **普通世界** (Normal World)。 BL31 将控制权交给 U-Boot，完成从安全世界到普通世界的切换。这一过程通过 TrustZone 提供的机制实现，确保安全世界和普通世界之间的隔离。

6. **U-Boot 阶段**：  
   在 BL31 完成工作后，控制权交给 U-Boot。 U-Boot 的主要职责是加载和验证 Linux 操作系统，并初始化用户空间环境，包括硬件初始化和用户交互界面的准备。完成 Linux 系统分区挂载后， U-Boot 开始执行用户空间代码。  
   **普通世界操作**： U-Boot 和后续的 Linux 内核运行在普通世界中，负责系统的常规功能和用户交互。

7. **Linux 内核启动**：  
   最终， U-Boot 引导 Linux 内核启动，完成系统的启动过程。 Linux 内核运行在普通世界中，负责管理系统的资源和执行用户应用程序。

### bootloader 启动流程关键函数分析

#### 入口函数 _start

`_start` 位于 `uboot/arch/arm/cpu/armv8/start.S`，是硬件启动后执行的第一段汇编代码，负责底层初始化：

- **代码段与 BSS 段配置**：初始化 `.text`（代码段）、`.data`（数据段），清零 `.bss` 段（未初始化的全局变量区）。
- **异常向量表设置**：定义 ARMv8 架构的中断向量表，确保异常发生时能跳转到正确处理程序。
- **CPU 模式切换**：从 BootROM 默认的异常模式（如 EL3/EL2）切换到操作系统运行的权限模式（如 EL1）。

`_start` 函数主要流程如下：

```bash
_start
├─> reset
│    ├─> save_boot_params（板级）
│    ├─> PIC Fixup（位置无关处理）
│    ├─> 设置 VBAR（异常向量）
│    ├─> EL 级别配置（启用 FP/SIMD/ 中断）
│    ├─> SMPEN/ 勘误处理
│    ├─> lowlevel_init
│    │    ├─> GIC 初始化（主核）
│    │    └─> 多核唤醒 / 等待逻辑
│    └─> 跳转到 _main（ C 入口）
└─> 从核逻辑 (slave_cpu)
     └─> wfe 循环直到主核释放
```

### _main

`_main` 函数位于 `uboot/arch/arm/lib/crt0_64.S` ，`crt0_64.S` 是 U-Boot 用于 AArch64 架构的启动代码，负责设置 C 运行时环境，并跳入到 C 函数 `board_init_f` 和 `board_init_r` 中完成不同阶段的初始化流程。

`_main` 函数主要负责：

1. 设置初始运行时环境，准备栈以及初始化全局数据 (GD)。
2. 调用 `board_init_f()` 初始化硬件。
3. 支持调试串口（可选）。
4. 设置中间环境并进行代码重定位（仅限 U-Boot，非 SPL）。
5. 准备最终环境并调用 `board_init_r()`。

`_main` 函数的执行过程如下图所示：

![_main_Timing](../_static/_images/bootloader_user_guide/_main_Timing.png)

具体说明如下：

1. **入口 (`_main Entry`)**：
   - `_main` 函数的入口点，开始整个启动流程。

2. **初始环境设置 (`Initial Environment Setup`)**：
   - 设置初始栈和全局数据结构 (GD)，为调用 `board_init_f()` 准备环境。

3. **调用 `board_init_f()`**：
   - 调用 `board_init_f()` 函数，准备硬件环境，为后续在系统 RAM 中运行做准备。

4. **中间环境设置 (`Intermediate Environment Setup`)**：
   - 根据 `board_init_f()` 的结果，更新栈和全局数据结构 (GD)。

5. **代码重定位 (`Code Relocation`)**：
   - 如果是 U-Boot（而非 SPL），调用 `relocate_code()` 将 U-Boot 代码迁移到目标地址。

6. **最终环境设置 (`Final Environment Setup`)**：
   - 设置最终运行环境，包括初始化 BSS 和非常量数据。

7. **调用 `board_init_r()`**：
   - 跳转到 `board_init_r()`，进入下一阶段。

**分支说明**：

- **U-Boot 和 SPL 的区别**：
  - 如果是 U-Boot，会执行代码重定位。
  - 如果是 [SPL](https://docs.u-boot.org/en/latest/develop/spl.html#u-boot-boot-phases) (Secondary Program Loader)，跳过重定位，直接进入最终环境设置。

#### board_init_f

`board_init_f` 函数位于 `uboot/common/board_f.c`，依次执行 `init_sequence_f` 数组中定义的函数，在此只列出一些重要的函数：

```bash
static const init_fnc_t init_sequence_f[] = {
	initf_malloc,		/* 早期堆的初始化 */
	arch_cpu_init,		/* 各架构的 soc 初始化 */
	board_early_init_f 	/* 板级 early 初始化函数 */
	serial_init,		/* 串口初始化 */
	dram_init,		/* 配置 ddr 的 size */
	reserve_round_4k,	/* reserve 各个区域，为 relocate 做准备 */
	arch_reserve_mmu,
	reserve_video,
	reserve_trace,
	reserve_uboot,
	reserve_malloc,
	reserve_board,
	reserve_global_data,
	reserve_fdt,
	reserve_bootstage,
	reserve_bloblist,
	reserve_arch,
	reserve_stacks,
	dram_init_banksize,	/* 初始化 global data 中各个 bank 的 size */
	show_dram_config,
	INIT_FUNC_WATCHDOG_RESET
	setup_bdinfo,
	display_new_sp,
	INIT_FUNC_WATCHDOG_RESET
	reloc_fdt,
	reloc_bootstage,
	reloc_bloblist,
	setup_reloc,		/* 确定 relocate 的地址 */
	clear_bss,
	NULL,
};
```

完成这些函数的执行后，前期硬件配置和内存保留流程便顺利就绪。

#### board_init_r

  `board_init_r` 函数位于 common/board_r.c 中，依次执行 `init_sequence_r` 的各个函数，只列出重要部分：

```bash
static init_fnc_t init_sequence_r[] = {
	initr_caches,		/* 初始化 cache 和 MMU */
	initr_malloc,		/* 初始化堆区域 */
	initr_of_live,
	initr_dm,		/* 初始化 dm 框架 */

	board_init,		/* 板级初始化函数 */
	initr_watchdog,		/* 初始化 watchdog */
	last_stage_init,	/* 进入 main_loop 之前最后一个阶段的初始化，这里判断了各类启动模式，设置了相应的唤醒变量 */
	run_main_loop,		/* 进入最后的 loop 阶段，进入命令行模式，或执行 boot 命令 */
};
```

**关键子函数功能说明**：

- **`initr_caches`**：启用 CPU 缓存和 MMU（内存管理单元），提升执行效率与内存保护。
- **`initr_dm`**：初始化设备模型 (Driver Model)，扫描设备树 (DTB)，加载匹配的驱动程序。
- **`board_init`**：板级外设初始化（如 GPIO、以太网 PHY、存储介质接口）。
- **`last_stage_init`**：根据环境变量或硬件引脚状态判断启动模式（如正常启动、恢复模式、网络启动），设 `bootcmd` 执行目标。
- **`run_main_loop`**：进入 U-Boot 命令行或自动执行 `bootcmd`（如加载内核、启动操作系统）。

完成这些函数的执行后，**后期高级功能初始化** 流程也随之结束，系统便具备了进入主循环的条件。

## Secure Boot 流程简介

安全启动 (Secure Boot) 是确保系统启动过程中固件和软件的完整性和可信性的重要机制。在 bootloader 整体启动流程中，系统的安全启动会基于信任根 (Root of Trust)，逐级验证启动镜像，实现固件可信加载。

本系统中 Secure Boot 流程如下图所示：

![secure_boot](../_static/_images/bootloader_user_guide/secure_boot.png)

- 关于安全开发相关的内容可以参考本手册中 [信息安全开发指南](../../system_component_development/security_development/index.html) 系列文档。
- 关于 Secure Boot 的详细介绍可以参考文档 [X5 安全启动概述](../../system_component_development/security_development/secure_boot/secure_boot.html)。

### BootROM 阶段

**验证机制**：

- **签名验证**： RSA-4096 （基于公钥证书）
  - BootROM 使用 RSA-4096 位公钥算法对固件（如 BL2）的签名进行验证。 RSA-4096 是目前较为常见的强加密算法，足以保证验证过程的安全性。通过签名验证，可以确保固件内容未被篡改，且其来源可信。

- **解密算法**： AES-128 （用于 BL2 镜像解密）
  - AES-128 （高级加密标准）被用来解密 BL2 镜像。 AES-128 是一种对称加密算法，具有较高的安全性和性能。在启动过程中， AES-128 解密算法可以用来保护固件的机密性，防止固件在传输过程中被篡改或泄露。

- **证书/密钥**：
  - **根公钥**：根公钥存储在 [eFuse](../../system_component_development/security_development/efuse/efuse_update.html#x5-efuse)（电子熔丝） 中，通常是一个不可修改的硬件存储区域。通过根公钥， BootROM 可以验证 BL2 的数字签名。使用预置根公钥，可以确保只有受信任的固件才会通过验证。
  - **AES 解密密钥**： AES 解密密钥也可能通过 eFuse 存储或硬件固化，以增强密钥的保护。这样可以确保密钥的安全性，防止恶意程序获取密钥从而破解固件。

- **默认状态**：
  - 签名验证和解密 **默认开启**，无需客户干预。

### BL2 阶段

BL2 阶段涉及的证书和密钥信息如下表所示：

| 镜像         | 验证方       | 证书来源               | 默认状态       |
|--------------|--------------|------------------------|----------------|
| BL31         | D-Robotics   | D-Robotics 预置公钥证书 | 默认开启       |
| OP-TEE       | D-Robotics   | D-Robotics 预置公钥证书 | 默认开启       |
| DDR Firmware | D-Robotics   | D-Robotics 预置公钥证书 | 默认开启       |
| U-Boot       | 客户         | 客户自定义公钥证书     | 默认关闭       |
| BL2 Config   | 客户         | 客户自定义公钥证书     | 默认关闭       |

BL2 阶段的主要任务是验证固件镜像的完整性和可信性，确保在启动过程中不会加载恶意代码。所有镜像都采用 RSA 签名验证机制，通过使用预置公钥证书来验证固件镜像的合法性。

- **验证机制**：所有镜像均采用 RSA 签名验证

  - **证书/密钥**：
    - 使用上表中的证书 / 密钥进行验证。

  - **默认状态**：
    - **默认关闭**， U-Boot 和 BL2 Config 的验证需要客户通过烧写 eFuse 来启用自定义公钥。

  - **关键操作**：
  在加载 BL31 和 OP-TEE 前，进行哈希验证 (verify_hash)，确保镜像的完整性。

  - 关于 U-Boot 和 BL2 Config 的验证的详细内容可以参考 [U-Boot& BL2 CFG 验证](../../system_component_development/security_development/secure_boot/secure_boot.html#span-id-uboot-bl2-cfg-verify-uboot-bl2-cfg) 章节。

**证书与密钥管理**：

- 在 BL2 阶段， D-Robotics 提供了预置公钥证书用于验证 **BL31、OP-TEE 和 DDR Firmware** 镜像的完整性。
  - 默认情况下，这些镜像的验证功能是开启的，确保了这些关键组件的可信性。
  - 系统在启动时会自动对这些镜像进行验证，确保它们没有被篡改。
- 对于 **U-Boot** 和 **BL2 Config** 镜像，默认情况下验证是关闭的。客户可以根据自己的需求通过烧写 eFuse 来启用自定义公钥证书验证。
- 关于证书 / 秘钥相关的详细内容可以参考 [密钥管理](../../system_component_development/security_development/secure_boot/secure_boot.html#span-id-key-management) 章节。

**RSA 签名验证**：

- 所有固件镜像（包括 BL31 、 OP-TEE、 DDR Firmware、 U-Boot 和 BL2 Config）都采用 RSA 签名验证机制。
  - 这一机制通过数字签名验证固件镜像的完整性和可信性，确保只有未被篡改的镜像才能被加载执行。
  - 通过 RSA 签名，任何对固件的非法修改都能在启动过程中被及时检测到，防止恶意代码的注入。

**镜像完整性验证**：

- 在加载 **BL31** 和 **OP-TEE** 镜像之前，系统会执行哈希验证（`verify hash`），确保加载的镜像文件没有被篡改。
- 这个验证环节是 BL2 阶段的重要组成部分，确保了镜像的完整性，并进一步增强了系统的安全性。

### U-Boot 阶段

**验证机制**： Android Verified Boot (AVB)

- **工具/算法**：
  - 使用 AVB 2.0 协议验证内核镜像的哈希和签名。
  - 支持 RSA-2048/4096 或 SHA-256 哈希树。

- **证书/密钥**：
  - 验证链基于客户烧录在 eFuse 中的 AVB 公钥。

- **默认状态**：
  - **默认关闭**，需客户烧写 eFuse 启用 AVB 验证。

- 关于 U-Boot 加密相关的详细内容可以参考 [boot 加密介绍](../../system_component_development/security_development/boot_encrypt/boot_encrypt.html) 文档。

### Linux 内核阶段

**验证机制**： DM-Verity (Device-Mapper Verity)

- **功能**：对 `system` 分区进行完整性验证（防篡改）。

- **配置依赖**：
  - **默认关闭**，需客户烧写 eFuse 启用 DM-Verity。

- **实现方式**：
  - 内核启动后加载 DM-Verity 元数据（哈希树和签名）。
  - 使用预置在内核密钥环（`system_trusted_keyring`）中的公钥验证签名。

- 关于 `AVB` 和 `DM-Verity` 的详细内容可以参考 [Kernel & rootfs 验证](../../system_component_development/security_development/secure_boot/secure_boot.html#span-id-boot-system-verify-kernel-rootfs) 章节。

### 安全配置总结

| 阶段          | 验证工具 / 算法       | 证书 / 密钥来源       | 默认状态       | 启用条件              |
|---------------|---------------------|---------------------|----------------|-----------------------|
| **BootROM**   | RSA-4096 + AES-128  | eFuse 根公钥           | 开启           | 固化不可更改          |
| **BL2**       | RSA 签名             | D-Robotics/ 客户证书 | 部分开启       | 客户烧写 eFuse         |
| **U-Boot**    | AVB 2.0             | 客户 AVB 公钥         | 关闭           | 客户烧写 eFuse         |
| **Kernel**    | DM-Verity           | 内核内置 X.509 证书   | 关闭           | 客户烧写 eFuse         |

**补充说明**:

- **BL2阶段的分级验证**： D-Robotics 的公钥用于保障基础固件 (BL31 、 OP-TEE、 DDR FW) 的可信性，客户公钥用于业务相关模块 (U-Boot、 BL2 Config)，实现责任分离。
- **AVB 与 FIT Image 的关系**： U-Boot 同时支持 [FIT](https://docs.u-boot.org/en/latest/usage/fit/index.html#flat-image-tree-fit) (Flat Image Tree) Image 验证（传统方式）和 AVB 验证，需在编译时配置优先使用 AVB 流程。

## <span id="auto_set_uboot_ion"/>U-Boot 动态配置内核 ION 预留内存大小功能使用说明

ION 是 Linux 内核中的内存管理框架，用于提供高效的内存池和内存切分机制，特别适用于图形、视频等多媒体处理。关于 ION 的详细内容可以参考 [默认的 ION 预留内存](../memory_layout.html#span-id-default-ion-ion) 章节。

X5 平台的 U-Boot 实现了根据 U-Boot 内环境变量来动态修改**内核** ION 预留内存大小的功能。以下列表说明了支持修改的内核 ION 预留内存区域和对应的环境变量：

|U-Boot 环境变量名 | 修改的内核 ION 区域的 dts 标签 | 修改的 ION 区域的 dts compatible 字符串 |
|----------|----------|----------|
|ion_reserved_size|ion_reserved|ion-pool|
|ion_carveout_size|ion_carveout|ion-carveout|
|ion_cma_size|ion_cma|ion-cma|

上述节点定义在内核设备树文件 `kernel/arch/arm64/boot/dts/hobot/x5-memory.dtsi` 中。

使用方法：
进入 U-Boot 命令行后，使用命令：

```bash
# 修改 ION 环境变量
setenv ion_reserved_size 0x40000000
# 若需要重启保持环境变量
saveenv
# 启动 Linux 内核
boot
# 内核中查看 ION 内存
cd /app/platform_samples/sysinfopro/
./sysinfopro -m
```

上述命令将 `ion_reserved_size` 环境变量设置为 0x40000000 ，即修改对应的 ION 区域的大小为 1GB。其中：

- `ion_reserved_size` 是需要修改的目标 ION 区域对应的 U-Boot 环境变量名；
- `0x40000000` 是需要修改的目标 ION 区域的目标大小。

示例：

```bash
#  U-Boot 下执行
Hobot>setenv ion_reserved_size 0x40000000
Hobot>boot
# 等待内核启动后查看 ION 内存信息
root@buildroot:~# cd /app/platform_samples/sysinfopro/
root@buildroot:/app/platform_samples/sysinfopro# ./sysinfopro -m

[Memory Info]:
        [Total Memory]:         1.28 GB
        [Used Memory]:          0.21 GB
        [Free Memory]:          1.02 GB

        [NOTE] What is displayed is the memory available to the system,
        which is the actual physical memory capacity minus ION and system reserved memory.
        (The content is consistent with "free -h")

[ION Memory Info]:
        [ION CMA Memory Size]:          0.50 GB
        [ION Carveout Memory Size]:     1.00 GB
        [ION Reserved Memory Size]:     1.00 GB
```

可以看到 `ION Reserved Memory Size` 是 1GB。

<font color=red> 注意事项：</font>

- **内存大小限制**：当配置的 ION 区域的总大小（`ion_reserved_size + ion_carveout_size + ion_cma_size`）加上 ION 起始地址和默认内核 HEAP 大小（`DEFAULT_KERNEL_MIN_HEAP`）超过可用 DDR 总大小时， U-Boot 会发出告警并自动缩小这三个区域的大小。缩小的单位为 16MiB（一次总共缩小 48MiB），直到 ION 区域能够适配可用 DDR 大小为止。
  - 如果所有区域的大小都缩小到 `ION_MIN_SIZE`（默认 64MiB）后仍然无法容纳， U-Boot 会提示错误，但启动过程不会停止。
  - `ION_MIN_SIZE` 和 `DEFAULT_KERNEL_MIN_HEAP`（默认 64MiB）的值定义在 `arch/arm/mach-horizon/x5/x5_ion_setup.c` 文件内。

- **十六进制数值要求**： U-Boot 环境变量只能使用十六进制数字，如果配置的值不是有效的十六进制数字，可能导致启动异常。

## U-Boot 使用 dtb overlay 使用说明

`DTS Overlay` 是一种机制，允许在运行时动态修改设备树，以支持硬件配置的变化。

X5 平台的 U-Boot 实现了根据 U-Boot 内环境变量来给内核 DTS 进行 Overlay 操作的功能，用户可以通过设置环境变量来指定 overlay 文件。（详细可以参考 [Linux 内核的 Overlay 文件编写说明](https://www.kernel.org/doc/html/v6.1/devicetree/overlay-notes.html)）。

**注意：** 链接内的 DTS Overlay 格式需要 dtc 工具 **V1.5** 版本及以上才可以支持。

### 通用规则

- **启用条件**：只有在配置了 `dtbo_file_path` 环境变量时， DTS overlay 功能才会被启用。
- **文件限制**：当前只支持单个 dtbo 文件进行 overlay 操作。
- **默认行为**：默认情况下， overlay 只在当前启动中生效一次。如果需要在后续启动中保持有效，可以通过以下三种方式实现：
  - 使用 `saveenv` 命令保存当前环境变量。
  - 在编译 U-Boot 时，直接在 `./include/configs/x5.h` 文件中设置 `dtbo_file_path` 环境变量。
  - 参考 [U-Bootfit 镜像 DTS Overlay 说明](https://docs.u-boot.org/en/latest/usage/fit/overlay-fdt-boot.html)。
- **路径说明**：文中提到的路径为分区内路径。例如，如果分区挂载到 `/userdata`，则 `/userdata/test.dtbo` 的分区内路径为 `/test.dtbo`。

### 从固定位置获取 overlay 文件

- **默认位置**： X5 平台默认从 mmc0 的第 12 个分区（格式必须为 ext4）获取 overlay 文件。
- **配置命令**：用户需要使用 `setenv dtbo_file_path <path to dtbo file>` 命令来配置环境变量，以便启动流程自动获取并使用 overlay 文件。例如，若 overlay 文件在 `/test.dtbo`，则执行：

  ```bash
  setenv dtbo_file_path /test.dtbo
  ```

### 完整配置 overlay 文件位置

需要配置的环境变量如下：

|U-Boot 环境变量名 | 含义 | 示例 |
|----------|----------|----------|
|dtbo_fs|overlay 文件所处分区的文件格式 |ext4 （目前只支持 ext4）|
|dtbo_dev|overlay 文件所处的设备接口类型 |mmc|
|dtbo_part|overlay 文件所处的设备号及分区号 |0:c|
|dtbo_file_path|overlay 文件所处分区的路径，以分区本身为根目录 |/test.dtbo|
|dtbo_load_addr|overlay 文件被 load 到的内存地址，一般不需要配置 |0x9000000 （默认值）|

用户可以通过以下命令配置环境变量并使 overlay 生效：

```bash
setenv dtbo_fs ext4
setenv dtbo_dev mmc
setenv dtbo_part 0:c
setenv dtbo_file_path /test.dtbo
boot
```

DTS Overlay 在本次启动就会生效。

## U-Boot 配置 watchdog

默认情况下 U-Boot 是 disable watchdog，通过关闭 config 项 CONFIG_DROBOT_DISABLE_WDT，可使能 watchdog

```bash
CONFIG_DROBOT_DISABLE_WDT=n
```

watchdog 的超时时间在 x5.dtsi 中配置，单位秒

```bash
	watchdog: watchdog@34250000 {
                ...
		timeout-sec = <10>;
                ...
	};
```

## U-Boot 配置 PHY

U-Boot 下配置 PHY 的详细步骤可以参考 [U-Boot 下 PHY 的适配](../24-Phy_Driver_Debug_Guide.html#span-id-uboot-config-phy-ubootphy) 相关章节。

## U-Boot 配置 UART

在 U-Boot 环境中支持配置 UART。

- 查看波特率：

  ```bash
  printenv baudrate
  ```

  `printenv baudrate` 命令用于打印 U-Boot 环境变量中关于波特率的设置。`baudrate` 是一个预定义的环境变量，存储了当前的串口通信波特率。

- 设置波特率 :

  ```bash
  setenv bootargs "console=tty1 console=ttyS0,115200"
  saveenv
  ```

  - `setenv bootargs` 用于修改 `bootargs` 环境变量。`bootargs` 是启动参数，`console=ttyS0,115200` 指定了使用 `ttyS0` 串口设备，并将波特率设置为 115200 （这个波特率值可以根据需要调整）。
  - `saveenv` 命令将修改后的环境变量保存到 U-Boot 的存储中，使得修改能够在下次启动时生效。

## U-Boot 配置 IO-Domain

U-Boot 内已实现了 Pinctrl 驱动，在设备树内进行配置和使用， U-Boot 下支持使用命令查看 IO-Domain 寄存器。

U-Boot 配置 IO-Domain 的详细功能介绍参考 [IO-Domain 调试指南中的 UbootSpace](../12-IO-DOMAIN_Debug_Guide_zh_CN.html#span-id-io-domain-uboot-uboot-space) 章节。

## U-Boot 中常用命令说明

当前 U-Boot 中支持的命令如下：

```c
Hobot>help
?         - alias for 'help'
ab_corrupt- Set the slot to be corrupted.
ab_select - Select the slot used to boot from and register the boot attempt.
adc       - ADC sub-system
avb       - Provides commands for testing Android Verified Boot 2.0 functionality
base      - print or set address offset
bdinfo    - print Board Info structure
blkcache  - block cache diagnostics and control
boot      - boot default, i.e., run 'bootcmd'
bootd     - boot default, i.e., run 'bootcmd'
bootelf   - Boot from an ELF image in memory
bootflow  - Boot flows
booti     - boot Linux kernel 'Image' format from memory
bootm     - boot application image from memory
bootp     - boot image via network using BOOTP/TFTP protocol
bootstage - Boot stage command
bootvx    - Boot vxWorks from an ELF image
btype     - board type utility commands
chpart    - change active partition of a MTD device
cmp       - memory compare
coninfo   - print console devices and information
cp        - memory copy
crc32     - checksum calculation
dcache    - enable or disable data cache
dfu       - Device Firmware Upgrade
dhcp      - boot image via network using DHCP/TFTP protocol
dm        - Driver model low level access
echo      - echo args to console
editenv   - edit environment variable
efuse     - Read/Dump efuse access via optee
env       - environment handling commands
erase     - erase FLASH memory
exit      - exit script
ext2load  - load binary file from a Ext2 filesystem
ext2ls    - list files in a directory (default /)
ext4load  - load binary file from a Ext4 filesystem
ext4ls    - list files in a directory (default /)
ext4size  - determine a file's size
ext4write - create a file in the root directory
false     - do nothing, unsuccessfully
fastboot  - run as a fastboot usb or udp device
fatinfo   - print information about filesystem
fatload   - load binary file from a dos filesystem
fatls     - list files in a directory (default /)
fatmkdir  - create a directory
fatrm     - delete a file
fatsize   - determine a file's size
fatwrite  - write file into a dos filesystem
fdt       - flattened device tree utility commands
flinfo    - print FLASH memory information
go        - start application at address 'addr'
gpio      - query and control gpio pins
gpt       - GUID Partition Table
gzwrite   - unzip and write memory to block device
hb_avb_helper- Do verify according partition type
help      - print command description/usage
i2c       - I2C sub-system
icache    - enable or disable instruction cache
iminfo    - print header information for application image
imxtract  - extract a part of a multi-image
itest     - return true/false on integer compare
loadb     - load binary file over serial line (kermit mode)
loads     - load S-Record file over serial line
loadx     - load binary file over serial line (xmodem mode)
loady     - load binary file over serial line (ymodem mode)
log       - log system
loop      - infinite loop on address range
lzmadec   - lzma uncompress a memory region
md        - memory display
mdio      - MDIO utility commands
memdump   - memdump system memory to flash
mii       - MII utility commands
mm        - memory modify (auto-incrementing address)
mmc       - MMC sub system
mmcinfo   - display MMC info
mtd       - MTD utils
mtdparts  - define flash/nand partitions
mtest     - simple RAM read/write test
mw        - memory write (fill)
net       - NET sub-system
nfs       - boot image via network using NFS protocol
nm        - memory modify (constant address)
panic     - Panic with optional message
part      - disk partition related commands
ping      - send ICMP ECHO_REQUEST to network host
pinmux    - show pin-controller muxing
poweroff  - Perform POWEROFF of the device
printenv  - print environment variables
protect   - enable or disable FLASH write protection
random    - fill memory with random pattern
reset     - Perform RESET of the CPU
run       - run commands in an environment variable
saveenv   - save environment variables to persistent storage
setenv    - set environment variables
setexpr   - set environment variable as the result of eval expression
sf        - SPI flash sub-system
showvar   - print local hushshell variables
sleep     - delay execution for some time
sound     - sound sub-system
source    - run script from memory
sspi      - SPI utility command
test      - minimal test like /bin/sh
tftpboot  - load file via network using TFTP protocol
true      - do nothing, successfully
ubi       - ubi commands
ubifsload - load file from an UBIFS filesystem
ubifsls   - list files in a directory
ubifsmount- mount UBIFS volume
ubifsumount- unmount UBIFS volume
ums       - Use the UMS [USB Mass Storage]
unlz4     - lz4 uncompress a memory region
unzip     - unzip a memory region
usb       - USB sub-system
usbboot   - boot from USB device
version   - print monitor, compiler and linker version
```

下面对其中常用的一些命令进行说明。

### 环境管理命令

`setenv`、`printenv` 和 `saveenv` 是 U-Boot 中常用的环境变量管理命令。它们主要用于管理和存储环境变量，这些环境变量可以影响系统的启动行为、硬件配置等。

#### setenv

`setenv` 命令用于设置或修改环境变量的值。它可以为一个或多个环境变量赋值，以便在系统启动或运行过程中使用。

用法：

```bash
setenv <variable_name> <value>
```

- `<variable_name>`：环境变量的名称。
- `<value>`：环境变量的值。

示例 1 ：

```bash
setenv bootargs "console=tty1 console=ttyS0,115200"
```

这个命令将 `bootargs` 环境变量设置为 `console=tty1 console=ttyS0,115200`。

注意：

- 如果环境变量已经存在，`setenv` 会覆盖原有值。
- 设置的环境变量只会在当前会话中有效，除非保存。

示例 2 ：

设置 IP 地址、子网掩码和网关：

```bash
setenv ipaddr 192.168.1.10
setenv netmask 255.255.255.0
setenv gatewayip 192.168.1.1
```

**注意**：只有先设置了 IP 地址，才能进行 `ping` 测试：

```bash
Hobot>ping 192.168.1.101
Using gmac-tsn@35010000 device
host 192.168.1.101 is alive
```

#### printenv

`printenv` 命令用于显示当前的环境变量及其值。它允许用户查看已定义的所有环境变量，或者显示特定环境变量的值。

用法：

```bash
printenv
```

显示所有环境变量及其值。

```bash
printenv <variable_name>
```

显示指定环境变量的值。

示例：

```bash
printenv baudrate
```

这将输出 `baudrate` 环境变量的当前值，例如：

```bash
Hobot>printenv baudrate
baudrate=115200
```

注意：

- `printenv` 不会修改任何环境变量，它仅用于查看当前的环境变量设置。

#### saveenv

`saveenv` 命令用于将当前环境变量的设置保存到存储介质中（通常是 NAND、 SD 卡或 SPI Flash 等），以便在系统重新启动后保持环境变量的持久性。通过 `saveenv` 保存的环境变量将保存在特定的存储区域，即使系统重启，保存的环境变量也会被重新加载。

用法：

```bash
saveenv
```

示例：

```bash
setenv bootargs "console=tty1 console=ttyS0,115200"
saveenv
```

这将设置 `bootargs` 环境变量并将其保存到存储中，使得在系统重新启动后仍然有效。

注意：

- `saveenv` 会将当前的环境变量保存到存储中，通常会覆盖存储区域中的原有环境变量。
- 保存环境变量后，重启系统时，这些变量会自动加载。

### md 命令

`md` (memory display) 是 U-Boot 中用于显示内存内容的命令。它可以根据不同的数据宽度来显示指定地址处的内存内容。命令的使用方法及其含义如下：

#### md 命令格式

```bash
md [.b, .w, .l, .q] address [# of objects]
```

#### md 参数解析

1. **`.b`、`.w`、`.l`、`.q`**：
   - **`.b`**：按字节（ Byte， 1 字节）显示内存数据。
   - **`.w`**：按字（ Word， 2 字节）显示内存数据。
   - **`.l`**：按双字（ Long word， 4 字节）显示内存数据。
   - **`.q`**：按四字（ Quad word， 8 字节）显示内存数据。

   这些标志符决定了每个单位数据的显示宽度。默认情况下，如果不指定宽度，它会选择默认的 `word` 宽度（ 2 字节）。

2. **address**：显示的起始地址。可以是十六进制表示的地址，指定内存的起始位置。

3. **# of objects**：可选参数，表示要显示的内存数据的数量，默认为 1 。如果指定此参数，`md` 命令会显示从指定地址起的多个内存单元。

#### md 示例

1. **md.b 0x34120000 4**：以字节为单位，从地址 `0x34120000` 开始显示 4 个字节的数据。

    ```bash
    Hobot>md.b 0x34120000 4
    34120000: 00 00 00 00                                      ....
    ```

2. **md.w 0x34120000 8**：以字为单位，从地址 `0x34120000` 开始显示 8 个字的数据。

    ```bash
    Hobot>md.w 0x34120000 8
    34120000: 00000000 00000000 00000000 00000000  ................
    34120010: 00000000 00000000 00000000 00000000  ................
    ```

3. **md.l 0x34120000 6**：以双字为单位，从地址 `0x34120000` 开始显示 6 个双字的数据。

    ```bash
    Hobot>md.l 0x34120000 6
    34120000: 00000000 00000000 00000000 00000000  ................
    34120010: 00000000 00000000                    ........
    ```

#### md 命令使用场景

`md` 命令一般常用在以下场景中：

1. **调试硬件问题**：查看特定内存地址的内容，确认硬件是否正确初始化。
2. **验证数据加载**：确认数据是否正确加载到内存中（例如，设备树、内核镜像等）。
3. **分析内存布局**：查看内存中存储的结构化数据（例如，设备树头信息、内核启动参数等）。
4. **开发和测试**：开发在过程中，快速查看内存中的数据变化。

#### md 命令的注意事项

- **地址对齐**：某些内存操作可能需要地址对齐（例如，`.w` 需要 2 字节对齐，`.l` 需要 4 字节对齐）。如果地址未正确对齐，可能会导致错误。
- **内存访问权限**：某些内存区域可能受保护，访问这些区域可能会导致错误或异常。
- **显示范围**：如果指定的显示范围超出有效内存区域，可能会导致未定义行为。

### mw 命令

`mw` (memory write) 是 U-Boot 中用于写入内存的命令。它用于将指定的值填充到内存的指定地址，支持按不同数据宽度进行写入。命令的使用方法及其含义如下：

#### mw 命令格式

```bash
mw [.b, .w, .l, .q] address value [count]
```

#### mw 参数解析

1. **`.b`、`.w`、`.l`、`.q`**：
   - **`.b`**：以字节（ 1 字节）为单位写入内存数据。
   - **`.w`**：以字（ 2 字节）为单位写入内存数据。
   - **`.l`**：以双字（ 4 字节）为单位写入内存数据。
   - **`.q`**：以四字（ 8 字节）为单位写入内存数据。

   这些选项指定了写入数据的大小和单位。如果不指定宽度，默认使用 `word`（ 2 字节）作为数据单位。

2. **address**：指定要写入的内存地址。可以是十六进制表示的地址。

3. **value**：指定要写入到内存的值。可以是十六进制或十进制的数字，取决于 U-Boot 的设置。

4. **count**（可选）：指定要写入的内存单元数量。默认为 1 。如果指定了该参数，`mw` 会将相同的值写入连续的内存单元。

#### mw 示例

1. **mw.b 0x88000000 0xAA 4**：将值 `0xAA`（十六进制）按字节（ 1 字节）写入内存地址 `0x88000000` 开始的连续 4 个内存单元。

    ```bash
    Hobot>mw.b 0x88000000 0xAA 4
    ```

    然后再使用 `md` 命令回读确认写入情况：

    ```bash
    Hobot>md.b 0x88000000 8
    88000000: aa aa aa aa 1f 20 03 d5                          ..... ..
    ```

2. **mw.w 0x88000000 0x1234 3**：将值 `0x1234`（十六进制）按字（ 2 字节）写入内存地址 `0x88000000` 开始的连续 3 个内存单元。

    ```bash
    Hobot>mw.w 0x88000000 0x1234 3
    ```

    然后再使用 `md` 命令回读确认写入情况：

    ```bash
    Hobot>md.w 0x88000000 8
    88000000: 1234 1234 1234 d503 7000 8fec 0000 0000  4.4.4....p......
    ```

3. **mw.l 0x88000000 0xDEADBEEF 2**：将值 `0xDEADBEEF`（十六进制）按双字（ 4 字节）写入内存地址 `0x88000000` 开始的连续 2 个内存单元。

    ```bash
    Hobot>mw.l 0x88000000 0xDEADBEEF 2
    ```

    然后再使用 `md` 命令回读确认写入情况：

    ```bash
    Hobot>md.l 0x88000000 8
    88000000: deadbeef deadbeef 8fec7000 00000000  .........p......
    88000010: 00130f20 00000000 00130f20 00000000   ....... .......
    ```

#### mw 命令使用场景

`mw` 命令一般常用在以下场景中：

1. **硬件调试**：向硬件寄存器写入特定值以测试硬件功能。
2. **内存测试**：填充内存区域以验证内存是否正常工作。
3. **修改内存内容**：在启动过程中动态修改内存中的数据（例如，设备树、内核启动参数等）。
4. **开发和测试**：在开发过程中快速修改内存内容以验证功能。

#### mw 命令的注意事项

- **地址对齐**：某些写入操作可能需要地址对齐（例如，`.w` 需要 2 字节对齐，`.l` 需要 4 字节对齐）。如果地址未正确对齐，可能会导致错误。
- **内存访问权限**：某些内存区域可能受保护，写入这些区域可能会导致错误或异常。
- **数据范围**：确保写入的值在指定的大小范围内（例如，字节值范围为 `0x00` 到 `0xFF`，字值范围为 `0x0000` 到 `0xFFFF`）。

### nm 命令

`nm` 是 U-Boot 中用于修改内存内容的命令。它的作用是修改指定地址的内存值，以**交互式的方式**逐字节（或其他所支持的长度）地修改指定内存地址的内容。不同于 `mw` 命令，`nm` 主要用于修改某个 **固定地址** 的内存值。这个命令通常用于调整内存中的某个值，而不涉及对连续内存区域的写入。

#### nm 命令格式

```bash
nm [.b, .w, .l, .q] address
```

#### nm 参数解析

1. **`.b`、`.w`、`.l`、`.q`**：
   - **`.b`**：以字节（ 1 字节）为单位修改内存。
   - **`.w`**：以字（ 2 字节）为单位修改内存。
   - **`.l`**：以双字（ 4 字节）为单位修改内存。
   - **`.q`**：以四字（ 8 字节）为单位修改内存。

   这些选项确定了修改的内存单元的大小。如果不指定宽度，默认按 `word`（ 2 字节）单位修改。

2. **address**：指定要修改的内存地址。这个地址通常是一个固定地址，修改此地址的数据值。

#### nm 命令示例

验证 nm 命令的效果，可以结合 md 命令查看内存内容。具体使用说明如下：

1. 输入命令后，U-Boot 会显示当前地址的值，并等待用户输入新值。
2. 输入新值后按回车，该地址的值会被更新。
3. 可以直接按回车跳到下一个地址（地址自动递增）。
4. 输入 `.`（点号）即可退出命令。

示例：

```bash
Hobot>nm.l 0x34120000
34120000: 80000000 ? 1
34120000: 00000001 ? 2
34120000: 00000002 ? 3
34120000: 00000003 ? abcd 
34120000: 0000abcd ? .
Hobot>md.l 0x34120000 1
34120000: 0000abcd                             ....
```

与 `mw` 命令不同，`nm` 主要针对单一地址的修改，通常用于调试和修改特定变量或内存位置的值，适合逐个修改内存单元或多次修改同一地址。

### mm 命令

`mm` 是 U-Boot 中用于修改内存内容的命令，与 `nm` 命令类似，它用于修改内存的某个地址，但 `mm` 具有 **自动递增地址** 的功能。这意味着 `mm` 可以在修改一个内存单元后，自动将地址递增到下一个内存单元，从而便于连续修改多个内存位置。

#### mm 命令格式

```bash
mm [.b, .w, .l, .q] address
```

#### mm 命令参数解析

1. **`.b`、`.w`、`.l`、`.q`**：
   - **`.b`**：以字节（ 1 字节）为单位修改内存。
   - **`.w`**：以字（ 2 字节）为单位修改内存。
   - **`.l`**：以双字（ 4 字节）为单位修改内存。
   - **`.q`**：以四字（ 8 字节）为单位修改内存。

   这些选项指定了每次修改时的内存单元宽度。如果没有指定，默认按 `word`（ 2 字节）修改。

2. **address**：指定起始的内存地址。这个地址是修改的起点，`mm` 会从该地址开始修改，并会在每次修改后自动递增地址，适用于连续内存单元的修改。

#### mm 命令示例

验证 `mm` 命令的效果，可以结合 `md` 命令查看内存内容。例如：

```bash
Hobot> 
88000000: 0a ? 1
88000001: 00 ? 2
88000002: 00 ? 3
88000003: 14 ? 4
88000004: 1f ? Hobot><INTERRUPT>
Hobot>md.w 0x88000000 8
88000000: 0201 0403 201f d503 7000 8fec 0000 0000  ..... ...p......
```

#### 内存修改命令的区别

- **`mw`**：
  - 用于向内存区域填充相同的数据。
  - 地址会自动递增。
  - 适合批量修改内存。
- **`nm`**：
  - 用于修改内存中的单一单元。
  - 地址保持不变。
  - 适合逐个修改内存单元或多次修改同一地址。
- **`mm`**：
  - 用于逐个修改内存单元。
  - 地址自动递增。
  - 适合连续修改内存区域。

另外，需要 **注意** 上述这些内存操作命令操作的内存范围需要是 **非安全 (Non-Secure)** 区域以及 **未** 被硬件设计为只读（如 Boot ROM）的区域。系统的内存区域分布可以参考 [地址空间映射](../memory_layout.html)。

### I2C 命令

在 U-Boot 中，`i2c` 命令用于调试和访问 I2C 总线及其连接的设备。通过该命令，用户可以执行 I2C 总线扫描、读取和写入 I2C 设备寄存器等操作。

关于 U-Boot 中 `i2c` 命令的详细使用说明可以参考《 I2C 调试指南》文档中的 [I2C U-Boot 阶段使用](../9-I2C_Debug_Guide_zh_CN.html#span-id-i2c-uboot-use-i2c-uboot) 章节。

### gpio 命令

U-Boot 下提供了 GPIO 的调试工具 `gpio` 命令，用户可以通过该命令控制引脚的电平（输入、输出、切换等），以及查询引脚的状态：

```bash
Hobot>gpio
gpio - query and control gpio pins

Usage:
gpio <input|set|clear|toggle> <pin>
    - input/set/clear/toggle the specified pin
gpio status [-a] [<bank> | <pin>]  - show [all/claimed] GPIOs
```

以下是对各个参数项的详细说明：

1. **`gpio <input|set|clear|toggle> <pin>`**
   - 这个命令用于操作指定的 GPIO 引脚（通过 `<pin>` 指定）。
   - **`input`**: 将指定的 GPIO 引脚配置为输入模式。此模式下， GPIO 引脚可以读取外部信号（例如，按钮的状态）。
   - **`set`**: 将指定的 GPIO 引脚设置为高电平（逻辑 1）。通常，这会使引脚输出 3.3V 或 1.8V，具体电压取决于硬件配置。
   - **`clear`**: 将指定的 GPIO 引脚设置为低电平（逻辑 0）。这通常会使引脚输出 0V。
   - **`toggle`**: 切换指定 GPIO 引脚的状态。如果引脚当前是高电平，将其设置为低电平，反之亦然。

   例如：
   - `gpio set gpio@ls_0_0` 将 GPIO 引脚 gpio@ls_0_0 设置为高电平。
   - `gpio clear gpio@ls_0_0` 将 GPIO 引脚 gpio@ls_0_0 设置为低电平。
   - `gpio toggle gpio@ls_0_0` 将 GPIO 引脚 gpio@ls_0_0 的状态在高低之间切换。

2. **`gpio status [-a] [<bank> | <pin>]`**
   - 这个命令用于显示 GPIO 引脚的状态。
   - **`status`**: 显示当前 GPIO 引脚的状态，可以是输入或输出，也可能显示是否已被占用(claimed)。
   - **`-a`**: 如果指定了 `-a` 选项，将显示所有的 GPIO 引脚的状态，而不仅仅是已被占用的引脚。
   - **`<bank>`**: 你可以通过指定一个 `bank` 来查看该组中的 GPIO 引脚状态（如果系统的 GPIO 被分成多个银行）。通常， GPIO 会被划分成不同的银行，每个银行包含多个引脚。
   - **`<pin>`**: 你也可以通过指定某个特定的引脚来查看该引脚的状态。

   例如：
   - `gpio status gpio@ls_0_0` 显示 GPIO 引脚 gpio@ls_0_0 的状态。
   - `gpio status -a` 会显示所有 GPIO 引脚的详细状态，包括未被占用和已占用的引脚。

`gpio` 工具的使用示例可以参考《 GPIO 调试指南》文档中的 [调用示例](../10-GPIO_Debug_Guide_zh_CN.html#span-id-gpio-debug-uboot) 章节

### dm 命令

`dm` 是 U-Boot 中与 **驱动模型 (Driver Model)** 相关的命令集合，用于提供低级别的访问和调试 U-Boot 驱动模型。驱动模型是 U-Boot 用于管理设备和驱动程序的一种结构，它使得 U-Boot 可以更加灵活地处理硬件设备的驱动程序。`dm` 命令可以帮助用户查看和调试与设备驱动相关的信息。

#### dm 命令格式

```bash
Hobot>dm
dm - Driver model low level access

Usage:
dm compat        Dump list of drivers with compatibility strings
dm devres        Dump list of device resources for each device
dm drivers       Dump list of drivers with uclass and instances
dm static        Dump list of drivers with static platform data
dm tree          Dump tree of driver model devices ('*' = activated)
dm uclass        Dump list of instances for each uclass
```

#### dm 参数解析

1. **`dm compat`**：
   - **功能**：显示与每个驱动兼容的字符串。
   - **用途**：帮助用户查看哪些驱动与特定硬件设备兼容，以及驱动的兼容性信息。

2. **`dm devres`**：
   - **功能**：显示每个设备的资源列表。
   - **用途**：列出设备在启动时使用的所有资源，比如内存、 I/O 地址等。这有助于诊断设备资源分配和管理的问题。
   - **注意**：该选项需要将 `CONFIG_DEVRES` 打开才能使用，当前板端默认不开启。

3. **`dm drivers`**：
   - **功能**：输出当前 U-Boot 系统中所有驱动的详细列表。
   - **用途**：显示当前系统中所有加载的驱动程序的类和实例，包括它们所属的设备类 (uclass) 和具体的驱动实例。`uclass` 代表设备驱动的类别，比如块设备、网络设备等。每个类别下可以有多个设备实例。

4. **`dm static`**：
   - **功能**：输出带有静态平台数据的驱动列表。
   - **用途**：显示那些带有静态平台数据的驱动程序，方便查看哪些驱动使用了编译时绑定的数据。静态平台数据通常是在编译时确定并与驱动绑定的数据，显示这些数据有助于调试静态配置的设备驱动。

5. **`dm tree`**：
   - **功能**：输出 U-Boot 驱动模型的设备树，展示设备层次结构及激活状态，类似于硬件树形结构视图，已激活的设备以 `*` 标记。
   - **用途**：以树状图的方式显示所有驱动模型设备的层次结构，可以帮助理解设备间的父子关系，查看设备的激活状态。

6. **`dm uclass`**：
   - **功能**：列出每个 uclass（设备类）下的实例。
   - **用途**：列出每个设备类别下的设备实例，帮助用户了解每个设备类中存在的设备。

#### dm 命令示例

重点说明 `dm compat` 和 `dm tree` 这两个命令。

1. **dm compat**

    ```bash
    Hobot>dm compat
    Driver                Compatible
    --------------------------------
    asix_eth
    ax88179_eth
    blk_partition
    bootmeth_distro       u-boot,distro-syslinux
    bootstd_drv           u-boot,boot-std
    board_type_btype_bus  btype-bus
    fixed_factor_clock    fixed-factor-clock
    fixed_rate_raw_clock
    designware_wdt        snps,dw-wdt
    ……
    es8156                hobot,es8156
    eth_bootdev           u-boot,bootdev-eth
    eth_eqos              st,stm32mp1-dwmac
                          horizon,sunrise5-dwmac
    eth_phy_generic_drv
    fixed_clock           fixed-clock
    syscon                syscon
    gpio-dwapb            snps,dw-apb-gpio
    guc_adc               guc,igav04a
    hobot_board_btype     hobot,btype
    hobot_i2s             hobot, hobot-i2s
    hobot_sound           hobot,audio-codec
    horizon_dsp_pinctrl   d-robotics,horizon-dsp-iomuxc
    horizon_hsio_pinctrl  d-robotics,horizon-hsio-iomuxc
    horizon_lsio_pinctrl  d-robotics,horizon-lsio-iomuxc
    i2c_designware        snps,designware-i2c
    i2c_generic_chip_drv  i2c-chip
    mmc_blk
    mmc_bootdev           u-boot,bootdev-mmc
    ns16550_serial        ns16550
                          ns16550a
                          ingenic,jz4780-uart
                          nvidia,tegra20-uart
                          snps,dw-apb-uart
    optee                 linaro,optee-tz
    pinconfig
    ……
    x5_sdhci              horizon,x5-sdhci
    xhci-dwc3             snps,dwc3
    ```

    `dm compat` 命令输出的详细分析如下：
    **Driver**：驱动程序名称
      - 每个驱动程序都有一个唯一的名称，用于标识其功能和用途。

    **Compatible**：兼容性字符串
      - 兼容性字符串是设备树中用于匹配硬件设备的属性值。驱动程序通过这些字符串来识别和绑定到特定的硬件设备。
      - 每个驱动程序可以支持多个兼容性字符串，以兼容不同厂商或型号的硬件。

    **举例说明**：
    - **`gpio-dwapb`**：
      - **兼容性字符串**：
        - `snps,dw-apb-gpio`
      - **功能**： DesignWare GPIO 控制器驱动程序。

    - **`hobot_i2s`**：
      - **兼容性字符串**：
        - `hobot,hobot-i2s`
      - **功能**： Hobot I2S 音频接口驱动程序。

2. **dm tree**

    ```bash
    Hobot>dm tree
    Class     Index  Probed  Driver                Name
    -----------------------------------------------------------
    root          0  [ + ]   root_driver           root_driver
    firmware      0  [ + ]   hobot_board_btype     |-- board_type
    gpio          0  [   ]   gpio-dwapb            |-- gpio@34120000
    gpio          1  [   ]   gpio-dwapb            |   `-- gpio@ls_0_
    gpio          2  [   ]   gpio-dwapb            |-- gpio@34130000
    gpio          3  [   ]   gpio-dwapb            |   `-- gpio@ls_1_
    pinctrl       0  [ + ]   horizon_lsio_pinctrl  |-- lsio_iomuxc@34180000
    pinconfig     0  [   ]   pinconfig             |   |-- pconf-bias-disabled
    pinconfig     1  [   ]   pinconfig             |   |-- pconf-spi
    ……
    pinconfig    70  [   ]   pinconfig             |   `-- lsiogpio1grp6
    gpio          4  [   ]   gpio-dwapb            |-- gpio@35060000
    gpio          5  [   ]   gpio-dwapb            |   `-- gpio@hs_0_
    gpio          6  [   ]   gpio-dwapb            |-- gpio@35070000
    gpio          7  [   ]   gpio-dwapb            |   `-- gpio@hs_1_
    pinctrl       1  [ + ]   horizon_hsio_pinctrl  |-- hsio_iomuxc@35050000
    pinconfig    71  [ + ]   pinconfig             |   |-- enetgrp
    ……
    clk           9  [   ]   fixed_clock           |-- adcclk
    clk          10  [   ]   fixed_clock           |-- i2cclk
    clk          11  [   ]   fixed_clock           |-- wdtclk
    bootstd       0  [   ]   bootstd_drv           `-- bootstd
    bootmeth      0  [   ]   bootmeth_distro           |-- distro
    bootmeth      1  [   ]   vbe_simple                `-- vbe_simple
    ```

    - `dm tree` 的输出包含以下几列信息：

      **Class**
      - **描述**：设备的类别，例如 `root`、`firmware`、`gpio`、`pinctrl`、`clk` 等。
      - **作用**：帮助区分不同类型的设备。

      **Index**
      - **描述**：设备在同类设备中的索引编号。
      - **作用**：标识同一类设备中的不同实例。

      **Probed**
      - **描述**：设备的初始化状态，通常用符号表示：
        - `[ + ]`：设备已成功初始化。
        - `[   ]`：设备尚未初始化。
      - **作用**：显示设备是否已被探测并初始化。

      **Driver**
      - **描述**：绑定到该设备的驱动程序名称。
      - **作用**：显示设备的驱动程序，帮助调试驱动程序相关问题。

      **Name**
      - **描述**：设备的名称，通常包含设备的地址或标识符。
      - **作用**：提供设备的唯一标识。

      `dm tree` 的输出通常以树状结构显示，使用缩进和符号来表示设备之间的层次关系：
        - `|--`：表示子设备。
        - `|--`：表示子设备的进一步缩进。
        - `` `--``：表示最后一个子设备。

        例如：

        ```bash
        root          0  [ + ]   root_driver           root_driver
        firmware      0  [ + ]   hobot_board_btype     |-- board_type
        gpio          0  [   ]   gpio-dwapb            |-- gpio@34120000
        gpio          1  [   ]   gpio-dwapb            |   `-- gpio@ls_0_
        ```

    - 举例说明 `dm tree` 输出：

      **根节点**

      ```bash
      root          0  [ + ]   root_driver           root_driver
      ```

      - **Class**：`root`，表示这是根节点。
      - **Index**：`0`，表示这是第一个根节点。
      - **Probed**：`[ + ]`，表示该设备已成功初始化。
      - **Driver**：`root_driver`，表示绑定到该设备的驱动程序。
      - **Name**：`root_driver`，表示设备的名称。

      **GPIO 控制器**

      ```bash
      gpio          0  [   ]   gpio-dwapb            |-- gpio@34120000
      ```

      - **Class**：`gpio`，表示这是 GPIO 控制器。
      - **Index**：`0`，表示这是第一个 GPIO 控制器。
      - **Probed**：`[   ]`，表示该设备尚未初始化。
      - **Driver**：`gpio-dwapb`，表示绑定到该设备的驱动程序。
      - **Name**：`gpio@34120000`，表示设备的名称，其中 `34120000` 是设备的内存地址。

      **引脚控制器 (Pinmux)**

      ```bash
      pinctrl       0  [ + ]   horizon_lsio_pinctrl  |-- lsio_iomuxc@34180000
      ```

      - **Class**：`pinctrl`，表示这是引脚控制器。
      - **Index**：`0`，表示这是第一个引脚控制器。
      - **Probed**：`[ + ]`，表示该设备已成功初始化。
      - **Driver**：`horizon_lsio_pinctrl`，表示绑定到该设备的驱动程序。
      - **Name**：`lsio_iomuxc@34180000`，表示设备的名称，其中 `34180000` 是设备的内存地址。

### mii 命令

MII（媒体独立接口， Media Independent Interface）是一种标准接口，用于在以太网设备（如网卡）和以太网物理层设备 (PHY) 之间传输数据。

在 U-Boot 中，`mii` 命令用于管理和操作网络接口的 MII 寄存器，可以用来进行调试、查看或修改以太网接口的工作状态、速度、双工模式等。

#### mii 命令格式

```bash
mii - MII utility commands

Usage:
mii device                            - list available devices
mii device <devname>                  - set current device
mii info   <addr>                     - display MII PHY info
mii read   <addr> <reg>               - read  MII PHY <addr> register <reg>
mii write  <addr> <reg> <data>        - write MII PHY <addr> register <reg>
mii modify <addr> <reg> <data> <mask> - modify MII PHY <addr> register <reg>
                                        updating bits identified in <mask>
mii dump   <addr> <reg>               - pretty-print <addr> <reg> (0-5 only)
Addr and/or reg may be ranges, e.g. 2-7.
```

#### mii 参数解析

- **`mii device`**：列出所有可用的 MII 设备。
- **`mii device <devname>`**：设置当前操作的 MII 设备。
- **`mii info`**：显示当前 MII 连接的状态信息（如链路、速率、双工模式等）。
- **`mii read`**：读取指定 PHY 寄存器的值，帮助获取网络状态信息。
- **`mii write`**：写入指定 PHY 寄存器的值，修改设备配置（如速率、双工模式等）。
- **`mii scan`**：扫描所有的 PHY 地址，检查它们的状态。
- **`mii reset`**：重置 PHY 设备，恢复到默认设置。
- **`mii dump`**：显示指定 PHY 设备的所有寄存器的内容，便于调试和分析。

#### mii 命令示例

1. **mii device**：

    `mii device` 命令用于显示当前系统中已配置的 MII 设备的列表。它通常用于查看系统中可用的网络设备及其状态。

    **用法：**

    ```bash
    mii device
    ```

    此命令会显示系统中所有可用的 MII 设备和其相关信息。通常它会列出多个网络接口的状态。

    **示例：**

    ```bash
    mii device
    ```

    **输出示例：**

    ```bash
    Hobot>mii device
    MII devices: 'gmac-tsn@35010000'
    Current device: 'gmac-tsn@35010000'
    ```

    分析输出：
    - `MII devices`: 这行显示了系统中当前可用的 MII 设备。这里显示的设备是 gmac-tsn@35010000 ，表示系统检测到一个名为 gmac-tsn@35010000 的 MII 设备。这个设备是一个集成的以太网控制器， 35010000 是设备的地址。

    - `Current device`: 这行显示了当前操作的 MII 设备。这里也显示为 gmac-tsn@35010000 ，表示当前命令正在作用于这个设备。

2. **mii info**：

    `mii info` 命令用于显示当前网络接口的 MII 状态信息，通常用于查看网络连接的状态，包括速率、双工模式、链路状态等。

    **用法：**

    ```bash
    mii info <addr>
    ```

    **输出示例：**

    ```bash
    Hobot>mii info
    PHY 0x00: OUI = 0x0732, Model = 0x11, Rev = 0x06, 100baseT, FDX
    PHY 0x01: OUI = 0x0732, Model = 0x11, Rev = 0x06, 100baseT, FDX
    Hobot>mii info 0x00
    PHY 0x00: OUI = 0x0732, Model = 0x11, Rev = 0x06, 100baseT, FDX
    ```

   可以看出系统检测到了两个 PHY 设备，分别位于地址 `0x00` 和 `0x01`，详细解释如下：
   - **PHY 0x00 和 PHY 0x01**：这表示系统检测到了两个物理层设备 (PHY)。`0x00` 和 `0x01` 是 PHY 设备的地址标识符，通常是硬件地址。
   - **OUI (组织唯一标识符)**：`OUI = 0x0732` 是制造商的唯一标识符 (Organizationally Unique Identifier)，用于标识设备制造商。
   - **Model 和 Rev**：`Model = 0x11` 和 `Rev = 0x06` 分别是 PHY 设备的型号和版本号。
   - **100baseT**：这表示设备当前支持 100 Mbps 的速率，`100baseT` 是以太网速率标准。
   - **FDX (Full Duplex)**：这表示设备正在以全双工模式运行，意味着数据可以同时发送和接收。

3. **mii read**：

    `mii read` 命令用于读取指定 PHY 地址的特定寄存器内容。每个 PHY 设备有多个寄存器，用于存储各种控制和状态信息。`mii read` 可以读取这些寄存器的值，帮助诊断网络设备的问题。

    当前板端使用的 PHY 芯片为 RTL8221F 其寄存器列表如下：

    ![RTL_Register_Mapping](../_static/_images/bootloader_user_guide/RTL_Register_Mapping.png)

    - **用法：**

    ```bash
    mii read <phy_address> <register>
    ```

    - `<phy_address>`：指定要读取的 PHY 地址。
    - `<register>`：指定要读取的寄存器编号。

    **示例：**

    ```bash
    mii read 0 0x02
    mii read 0 0x03
    ```

    这将读取地址为 `0` 的 PHY 设备的 `0x02` `0x03` 寄存器。

    **输出示例：**

    ```bash
    Hobot>mii read 0 0x2
    001C
    Hobot>mii read 0 0x3
    C916
    ```

    这个命令会显示寄存器 `PHYID1` 和 `PHYID1` 的值。

    从 RTL8221F 的数据手册中可以查到这两个寄存器的描述：

    ![RTL_PHYID1](../_static/_images/bootloader_user_guide/RTL_PHYID1.png)

    ![RTL_PHYID2](../_static/_images/bootloader_user_guide/RTL_PHYID2.png)

    从这两个寄存器的值可以获取到如下信息：
    - `OUI_MSB`： OUI_MSB 的值为 0x1C (00011100b)，`OUI` 值的高 16 位。
    - `OUI_LSB`： OUI_LSB 的值为 110010b，`OUI` 值的低 6 位。
    - `Model Number`： Model Number 的值为 10001b (0x11)。
    - `Revision Number`： Revision Number 的值为 110b (0x6)。

    `OUI` 值由 `OUI_MSB` 和 `OUI_LSB` 组成：`00011100b << 6 + 110010b = 011100110010b` 也就是 0x732 。这与前面的 `mii info` 的输出是一致的：

    ```bash
    PHY 0x00: OUI = 0x0732, Model = 0x11, Rev = 0x06, 100baseT, FDX
    ```

    另外， mii read 命令支持一次性读取多个寄存器的值：

    ```bash
    Hobot>mii read 0 0-2
    addr=00 reg=00 data=1040
    addr=00 reg=01 data=79AD
    addr=00 reg=02 data=001C
    ```

    上述示例一次性读取了 PHY0 寄存器设备中 0x0 ~ 0x2 的寄存器值。

4. **mii write**：

    `mii write` 命令用于写入指定 PHY 地址的特定寄存器。通过修改 PHY 寄存器的值，用户可以更改网络设备的配置（如速率、双工模式、自动协商等）。

    **用法：**

    ```bash
    mii write <phy_address> <register> <value>
    ```

    - `<phy_address>`：指定要写入的 PHY 地址。
    - `<register>`：指定要写入的寄存器编号。
    - `<value>`：要写入寄存器的值。

    **示例：**

    ```bash
    Hobot>mii read 0 0x4
    01E1
    Hobot>mii write 0 0x4 0x181
    ```

    这个命令将向地址为 `0` 的 PHY 设备的 `0x4` 寄存器写入 `0x181` 的值。写入完成后可以使用 `mii read` 命令回读一下，确认写入是否成功：

    ```bash
    Hobot>mii read 0 0x4
    0181
    ```

5. **mii dump**：

    `mii dump` 命令用于以易读的格式打印 MII PHY 设备的寄存器内容，它可以详细显示每个寄存器的位字段及其含义，能够有效帮助用户分析和调试网络设备的状态。

    **用法：**

    ```bash
    mii dump <phy_address> <reg_address>
    ```

    **示例：**

    ```bash
    Hobot>mii dump 0 4
    1.     (0181)                 -- Autonegotiation advertisement register --
      (8000:0000) 4.15    =     0     next page able
      (4000:0000) 4.14    =     0     (reserved)
      (2000:0000) 4.13    =     0     remote fault
      (1000:0000) 4.12    =     0     (reserved)
      (0800:0000) 4.11    =     0     asymmetric pause
      (0400:0000) 4.10    =     0     pause enable
      (0200:0000) 4. 9    =     0     100BASE-T4 able
      (0100:0100) 4. 8    =     1     100BASE-TX full duplex able
      (0080:0080) 4. 7    =     1     100BASE-TX able
      (0040:0000) 4. 6    =     0     10BASE-T   full duplex able
      (0020:0000) 4. 5    =     0     10BASE-T   able
      (001f:0001) 4. 4- 0 =     1     selector = IEEE 802.3 CSMA/CD
    ```

    寄存器 `0x4` 是 MII 管理接口中的 **Autonegotiation Advertisement Register （自协商广播寄存器）**，该寄存器用于描述 PHY 设备支持的速率和模式，并在自协商过程中向对端设备广播这些能力。该寄存器的值是 0x0181 。

    **字段解析**：
    - **`0x8000` (bit 15)**： Next Page Able
      - **值**：`0`
      - **含义**：不支持扩展自协商 (Next Page)功能。

    - **`0x4000` (bit 14)**：保留位
      - **值**：`0`

    - **`0x2000` (bit 13)**： Remote Fault
      - **值**：`0`
      - **含义**：没有检测到远程故障。

    - **`0x1000` (bit 12)**：保留位
      - **值**：`0`

    - **`0x0800` (bit 11)**： Asymmetric Pause
      - **值**：`0`
      - **含义**：不支持非对称暂停模式。

    - **`0x0400` (bit 10)**： Pause Enable
      - **值**：`0`
      - **含义**：不支持暂停模式。

    - **`0x0200` (bit 9)**： 100BASE-T4 Able
      - **值**：`0`
      - **含义**：不支持 100BASE-T4 模式。

    - **`0x0100` (bit 8)**： 100BASE-TX Full Duplex Able
      - **值**：`1`
      - **含义**：支持 100Mbps 全双工模式。

    - **`0x0080` (bit 7)**： 100BASE-TX Able
      - **值**：`1`
      - **含义**：支持 100Mbps 半双工模式。

    - **`0x0040` (bit 6)**： 10BASE-T Full Duplex Able
      - **值**：`0`
      - **含义**：不支持 10Mbps 全双工模式。

    - **`0x0020` (bit 5)**： 10BASE-T Able
      - **值**：`0`
      - **含义**：不支持 10Mbps 半双工模式。

    - **`0x001F` (bits 4-0)**： Selector
      - **值**：`0x0001`
      - **含义**：选择 IEEE 802.3 CSMA/CD 模式。

    从 `mii dump` 的输出来看，该 PHY 设备支持以下功能：
    - **100BASE-TX Full Duplex**：支持 100Mbps 全双工模式。
    - **100BASE-TX**：支持 100Mbps 半双工模式。
    - **不支持**：
      - 10BASE-T（ 10Mbps 半双工模式）
      - 10BASE-T Full Duplex（ 10Mbps 全双工模式）
      - 100BASE-T4
      - 暂停模式 (Pause)
      - 非对称暂停模式 (Asymmetric Pause)
      - 扩展自协商 (Next Page)

    **注意**：当前 PHY 设备默认支持 10Mbps 全 / 半双工模式，因为在 `mii write` 示例中对寄存器 `0x4` 写入了 0x181 ，禁用了该功能，所以这里 `mii dump` 出来的状态变化了。

### mdio 命令

MDIO (Management Data Input/Output) 是 IEEE 802.3 规范定义的管理接口协议，用于 MAC 层与 PHY 芯片之间的通信。在 U-Boot 中，`mdio` 系列命令是调试网络设备的核心工具，可实现对 PHY 寄存器的读写操作、设备状态检测及网络参数配置。

#### mdio 命令格式

```bash
mdio - MDIO utility commands

Usage:
mdio list                       - List MDIO buses
mdio read <phydev> [<devad>.]<reg> - read PHY's register at <devad>.<reg>
mdio write <phydev> [<devad>.]<reg> <data> - write PHY's register at <devad>.<reg>
mdio rx <phydev> [<devad>.]<reg> - read PHY's extended register at <devad>.<reg>
mdio wx <phydev> [<devad>.]<reg> <data> - write PHY's extended register at <devad>.<reg>
```

#### mdio 参数解析

- **`<phydev>`**： PHY 设备标识符，可以是以下几种形式：
  - `<busname> <addr>`：例如 `gmac-tsn@35010000 0`。
  - `<addr>`：例如 `0`。
  - `<eth name>`：例如 `eth0`。
- **`<addr>`**： PHY 设备地址。
- **`<devad>`**：设备地址。
- **`<reg>`**：寄存器地址。
- **`<data>`**：要写入的数据。

#### mdio 命令示例

1. **mdio list**
    - **功能**：列出所有可用的 MDIO 总线及其名称。
    - **用法**：

      ```bash
      mdio list
      ```

    - **输出示例**：

     ```bash
     Hobot>mdio list
     gmac-tsn@35010000:
     ```

    输出解析 :
    - gmac-tsn@35010000 ：
      - 含义：这是一个以太网 MAC 设备，支持时间敏感网络 (TSN)功能。
      - gmac-tsn：表示这是一个以太网 MAC 设备，支持 TSN 功能。
      - @35010000 ：表示该设备的基地址为 0x35010000 。
    - 系统中只有一个 MDIO 总线，名为 `gmac-tsn@35010000`。这意味着所有与以太网 PHY 设备的通信都将通过这个总线进行。

2. **mdio read \<phydev> [\<devad>.]\<reg>**
    - **功能**：读取指定 PHY 设备的寄存器值。
    - **参数**：
      - `<phydev>`： PHY 设备标识符，可以是 `<busname> <addr>`、`<addr>` 或 `<eth name>`。
      - `<devad>`：设备地址（可选，默认为 `0`）。
      - `<reg>`：寄存器地址。
    - **用法**：

      ```bash
      mdio read gmac-tsn@35010000 0 1
      ```

    - **输出示例**：

      ```bash
      Hobot>mdio read gmac-tsn@35010000 0 1
      Reading from bus gmac-tsn@35010000
      PHY at address 0:
      1 - 0x79ad
      ```

      字段解释如下：
      - **Reading from bus gmac-tsn@35010000**：表示该命令是在 MDIO 总线 `gmac-tsn@35010000` 上执行的。
      - **PHY at address 0**：指示这是总线上的第一个 PHY 设备（地址为 `0`）。
      - **1 - 0x79ad**：表示从寄存器 `1` 中读取到了值 `0x79ad`。

3. **mdio write \<phydev> [\<devad>.]\<reg> \<data>**
    - **功能**：向指定 PHY 设备的寄存器写入数据。
    - **参数**：
      - `<phydev>`： PHY 设备标识符。
      - `<devad>`：设备地址（可选，默认为 `0`）。
      - `<reg>`：寄存器地址。
      - `<data>`：要写入的数据。
    - **用法**：

      ```bash
      Hobot>mdio write gmac-tsn@35010000 0 4 0x181
      ```

    字段解释如下：
    - **`mdio write`**：用于向指定的 MDIO 总线上的 PHY 设备寄存器写入数据。
    - **`gmac-tsn@35010000`**： MDIO 总线的名称，表示目标设备是 `gmac-tsn`，基地址为 `0x35010000`。
    - **`0`**： PHY 设备的地址，表示目标 PHY 设备在 MDIO 总线上的地址为 `0`。
    - **`4`**：寄存器地址，表示要写入的寄存器编号为 `4`。
    - **`0x181`**：要写入的数据值。

    为了验证写入操作是否成功，可以使用 `mdio read` 命令读取寄存器 `4` 的值：

    ```bash
    Hobot>mdio read gmac-tsn@35010000 0 4 
    Reading from bus gmac-tsn@35010000
    PHY at address 0:
    4 - 0x181
    ```

    可以看到，值已经成功写入了。

4. **mdio rx、mdio wx**
    在 U-Boot 中，**mdio rx、mdio wx** 命令用于读、写以太网 PHY 设备的扩展寄存器 (Extended Registers)。扩展寄存器通常用于更高级的配置和状态信息，这些信息可能不在标准的 MII 寄存器中提供。并非所有 PHY 设备都支持扩展寄存器。在使用 mdio rx/wx 命令之前，需要参考设备手册以确定正确的寄存器地址以及确认当前 PHY 设备是否支持扩展寄存器访问。

## Bootloader 相关术语表

| 术语       | 解释                                                                 |
|------------|----------------------------------------------------------------------|
| BootROM    | 硬件固化的初始启动代码，负责验证第一级引导程序 |
| [U-Boot](https://docs.u-boot.org/en/latest/)     | Universal Boot Loader，开源的通用引导加载程序，广泛应用于嵌入式系统      |
| [SPL](https://docs.u-boot.org/en/latest/develop/spl.html#u-boot-boot-phases)   | Secondary Program Loader，二级程序加载器，用于初始化基础硬件并加载完整 U-Boot |
| Secure Boot| 通过逐级验证固件 / 软件签名，确保启动链完整性和可信性的安全机制 |
| [OP-TEE](https://optee.readthedocs.io/en/latest/)     | Open Portable Trusted Execution Environment，开放可信执行环境，提供安全服务（如密钥管理、加密操作） |
| [TA](https://optee.readthedocs.io/en/latest/architecture/trusted_applications.html#trusted-applications) | Trusted Application，可信应用程序。 |
| [PTA](https://optee.readthedocs.io/en/latest/architecture/trusted_applications.html#pseudo-trusted-applications) | Pseudo Trusted Applications，伪可信应用程序。它是 OP-TEE Core 向其外部世界公开的接口，<br> 用于保护客户端 Trusted Applications 和不安全的客户端实体。|
| [ETA](https://optee.readthedocs.io/en/latest/architecture/trusted_applications.html#early-ta) | Early TA，早期可信应用程序，它直接链接到 TEE 核心 blob 中的特殊数据部分。  |
| [AVB](https://android.googlesource.com/platform/external/avb/+/refs/heads/main/README.md)        | Android Verified Boot，安卓验证启动机制，通过数字签名确保启动链完整性       |
| DTS        | Device Tree Source，设备树源文件，以文本形式描述硬件配置信息               |
| DTB        | Device Tree Binary，由 DTS 编译生成的二进制设备树文件，供 Bootloader 和内核使用 |
| DTC        | Device Tree Compiler，设备树编译器，用于将 DTS 编译为 DTB                  |
| FDT        | Flattened Device Tree，扁平化设备树，指 DTB 在内存中的数据结构形式          |
| FIT        | Flat Image Tree， FIT 是 U-Boot 支持的一种复合镜像格式。<br> 主要用于将多个启动镜像（内核、设备树、 RAM Disk 等）打包成单一文件，并支持 **安全校验​**。   |
