启动嵌入式系统是任何基于FPGA或嵌入式Linux的开发流程中最常见且至关重要的环节。通常情况下,开发者会依赖SD卡、TFTP或NFS等传统方式。然而,当板载存储或以太网接口无法访问时,通过JTAG启动Linux镜像便成了唯一可行的选择。
AMD官方技术文章《通过JTAG在AMD XILINX SoC器件里启动Linux的方法》阐述了核心原理——利用XSCT工具进行调试。本文将在该文档基础上,提供更为详细和扩展的实践操作指南。

原文地址:https://adaptivesupport.amd.com/s/article/000035979?language=zh_CN

说明:本文内容主要针对 Zynq-7000 SoC 平台。对于 Zynq-UltraScale+ 平台,其原理类似,但具体操作会面临不同的挑战,后续将另文详述。
XSCT 是什么?
XSCT (Xilinx Software Command-line Tool) 是赛灵思(现AMD)提供的命令行工具,用于替代旧版的 XSDB。它随 Vivado、Vitis 或 PetaLinux 工具链一同安装,支持脚本与交互式操作,主要用于管理硬件目标、下载FPGA比特流或可执行文件、系统初始化等任务。

关于 XSCT 与 XSDB 的区别,可参考官方说明。更多详细功能,请查阅 Xilinx 官方文档 UG-1400:
https://docs.xilinx.com/r/en-US/ug1400-vitis-embedded/Xilinx-Software-Command-Line-Tool
硬件需求
要使用 JTAG 启动,需满足以下基本条件:
- 目标硬件必须具备可访问的 JTAG 接口。
- 需使用 JTAG 调试线缆连接开发主机与目标板卡。
推荐使用 Xilinx SmartLynq 调试器(支持更高频率并可远程连接)。

也可使用 Platform Cable USB II 等传统线缆。

步骤详解:JTAG 引导全流程
1️⃣ 启动 XSCT 环境
在命令行中直接运行 XSCT 可执行文件即可进入其交互式环境,例如:
<INSTALLATION_PATH>/Xilinx/Vitis/2021.1/bin/xsct
或从 Windows 开始菜单中启动:

启动后,你将看到一个带有 xsct% 提示符的界面,可以执行 help、jtag、memory 等各种命令。

2️⃣ 连接目标硬件
XSCT 通过调用硬件服务器来连接 JTAG 套件。使用 connect 命令建立连接:
connect -url tcp:<DEVICE_IP>:3121
其中,设备的 IP 地址取决于所使用的 JTAG 套件:
- 使用 SmartLynq 时,IP 地址通常显示在设备屏幕上。
- SmartLynq 通过 USB 连接时,可使用
10.0.0.2。
- 使用 Platform Cable 时,通常使用
127.0.0.1 (localhost)。
默认端口为 3121,如使用其他端口需相应修改。对于任何需要通过网络通信的设备,理解其连接机制都是网络与系统管理的基础。
3️⃣ 查看 JTAG 链上的设备
使用 targets 命令列出 JTAG 链上所有可识别的设备:
xsct% targets
1 APU
2 ARM Cortex-A9 MPCore #0 (Running)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
如果连接错误或板卡未上电,会显示如下错误:
xsct% targets
1 whole scan chain (board power off)
最常见的问题与 JTAG 时钟频率有关。电缆长度、链上器件数量等物理特性可能影响稳定连接。此时,XSCT 会报出如下类似错误:
xsct% targets
1 whole scan chain (Unknown device configuration)
xsct% targets
1 whole scan chain (Unknown IR length)
xsct% targets
1 whole scan chain (too many devices)
遇到此类问题,需要调整 JTAG 频率。首先查看线缆支持的频率列表,然后选择一个合适的值:
xsct% jtag targets 1
xsct% jtag frequency -list
125000 250000 500000 1000000 2000000 3000000 4000000 6000000 7500000 10000000 12000000 13000000 15000000 20000000 30000000 40000000 50000000 60000000 70000000 80000000 90000000 100000000
xsct% jtag frequency 7500000
7500000
xsct% jtag frequency 7000000
7017543
4️⃣ 下载 FPGA 比特流 (Bitstream)
通过 JTAG 将比特流文件下载到 FPGA 的可编程逻辑 (PL) 部分:
xsct% targets
1 APU
2 ARM Cortex-A9 MPCore #0 (Running)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct% targets 4
xsct% fpga “<PATH_TO_IMAGE>/system.bit”
00% 0MB 0.0MB/s 00:00
33% 1MB 0.9MB/s 00:01
66% 2MB 0.9MB/s 00:02
100% 3MB 0.9MB/s 00:03
5️⃣ 下载并运行 FSBL (第一阶段引导加载程序)
FSBL 是 Zynq-7000 SoC 上电后 BootROM 加载的第一个用户程序,负责初始化硬件。首先确保目标 CPU 为 ARM Core #0:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
然后使用 dow (Download) 命令下载 FSBL 的 ELF 文件:
xsct% dow “${imagesPath}/zynq_fsbl.elf”
Downloading Program -- zynq_fsbl.elf
section, .text: 0x00000000 - 0x0000e753
section, .handoff: 0x0000e754 - 0x0000e79f
section, .init: 0x0000e7a0 - 0x0000e7ab
section, .fini: 0x0000e7ac - 0x0000e7b7
section, .rodata: 0x0000e7b8 - 0x0000eacf
section, .data: 0x0000ead0 - 0x000116bf
section, .mmu_tbl: 0x00014000 - 0x00017fff
section, .init_array: 0x00018000 - 0x00018003
section, .fini_array: 0x00018004 - 0x00018007
section, .rsa_ac: 0x00018008 - 0x0001903f
section, .bss: 0x00019040 - 0x0001b29f
section, .heap: 0x0001b2a0 - 0x0001d29f
section, .stack: 0xffff0000 - 0xffffd3ff
100% 0MB 0.4MB/s 00:00
Setting PC to Program Start Address 0x00000000
Successfully downloaded zynq_fsbl.elf
Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0x3ff67154 (Suspended)
下载后 CPU 处于暂停状态。让 FSBL 运行几秒钟以完成其初始化工作,然后手动停止:
xsct% con; after 5000; stop
Info: ARM Cortex-A9 MPCore #0 (target 2) Running
Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0xfaf0 (Suspended)
关键注意事项:
- 下载 FSBL 前,必须禁用内存管理单元 (MMU)。如果目标正在运行 Linux,需先中断。
- FSBL 的行为受启动引脚控制。若引脚固定,可能需要修改 FSBL 源码强制其进入 JTAG 启动模式。
6️⃣ 初始化处理系统 (PS)
运行 FSBL 后,需要使用 Vivado 导出的硬件平台描述文件来初始化其余硬件。XSA 文件中包含一个 ps7_init.tcl 脚本:
$> cd hw-description && ls -l
... system.bit
... ps7_init.c
... ps7_init.h
... ps7_init.tcl
<其余文件略>
在 XSCT 中执行该脚本以初始化 DDR、PLL、时钟、MIO 等外设:
xsct% targets
1 APU
2* ARM Cortex-A9 MPCore #0 (Suspended)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct% targets 1
xsct% source ps7_init.tcl
xsct% ps7_init
若无输出,通常表示初始化成功。脚本内容会根据芯片硅版本自动选择相应的初始化数据,其内部流程清晰地展示了 SoC 各模块的启动顺序,这对于嵌入式系统运维与底层开发有很好的参考价值。
7️⃣ 下载设备树二进制文件 (DTB)
U-Boot 需要设备树来识别硬件。将 DTB 文件下载到 DDR 内存的预定地址:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
xsct% set deviceTreeOffset 0x100000
xsct% dow -data “system.dtb” ${deviceTreeOffset}
100% 0MB 0.4MB/s 00:00
Successfully downloaded system.dtb
-data 选项表明下载的是纯数据文件,而非可执行的 ELF。
设备树偏移地址在 U-Boot 编译时已硬编码。对于 PetaLinux 项目,可在配置文件中查找 CONFIG_SUBSYSTEM_UBOOT_DEVICETREE_OFFSET 的值:
DEVICE_TREE_OFFSET="$(grep "CONFIG_SUBSYSTEM_UBOOT_DEVICETREE_OFFSET" “<PLNX_PRJ_PATH>/project-spec/configs/config” | cut -d'=' -f 2)"
echo ${DEVICE_TREE_OFFSET}
8️⃣ 下载并运行 U-Boot (第二阶段引导加载程序)
现在可以下载 U-Boot 镜像。下载完成后,使用 con (Continue) 命令释放 CPU,即可在串口终端看到 U-Boot 启动输出:
xsct% targets -set -nocase -filter {name =~ "arm*#0"}
xsct% dow “u-boot.elf”
Downloading Program -- u-boot.elf
section, .text: 0x04000000 - 0x040003a7
section, .efi_runtime: 0x040003a8 - 0x040011ef
section, .text_rest: 0x04001200 - 0x0409dbff
section, .rodata: 0x0409dc00 - 0x040c0ea8
section, .hash: 0x040c0eac - 0x040c0ec3
section, .data: 0x040c0ec8 - 0x040cc4cf
section, .got.plt: 0x040cc4d0 - 0x040cc4db
section, .u_boot_list: 0x040cc4dc - 0x040ce30f
section, .efi_runtime_rel: 0x040ce310 - 0x040ce3df
section, .rel.dyn: 0x040ce3e0 - 0x040e22e7
section, .bss_start: 0x040ce3e0 - 0x040ce3df
section, .bss: 0x040ce3e0 - 0x040e1397
section, .bss_end: 0x040e1398 - 0x040e1397
100% 0MB 0.4MB/s 00:02
Setting PC to Program Start Address 0x04000000
Successfully downloaded u-boot.elf
xsct% con
Info: ARM Cortex-A9 MPCore #0 (target 2) Running
串口终端将显示类似如下信息:
U-Boot 2021.01 (Jun 01 2021 - 11:54:06 +0000)
CPU: Zynq 7z020
Silicon: v3.1
DRAM: ECC disabled 1 GiB
Flash: 0 Bytes
NAND: 0 MiB
MMC: mmc@e0101000: 0
Loading Environment from SPIFlash... SF: Detected s25fl256s1 with page size 256 Bytes, erase size 64 KiB, total 32 MiB
*** Warning - bad CRC, using default environment
In: serial@e0000000
Out: serial@e0000000
Err: serial@e0000000
Net: ZYNQ GEM: e000b000, mdio bus e000b000, phyaddr -1, interface rgmii-id
eth0: ethernet@e000b000
Hit any key to stop autoboot: 0
Zynq >
9️⃣ 下载并启动 Linux 内核
最后一步是将打包好的 Linux 内核镜像(如 PetaLinux 生成的 image.ub,包含内核、设备树和根文件系统)下载到 DDR 内存的空闲区域,并通过 U-Boot 启动。
首先暂停 CPU 运行:
xsct% targets
1 APU
2* ARM Cortex-A9 MPCore #0 (Running)
3 ARM Cortex-A9 MPCore #1 (Running)
4 xc7z020
xsct% stop
Info: ARM Cortex-A9 MPCore #0 (target 2) Stopped at 0x3ff67154 (Suspended)
下载内核镜像到指定地址(例如 0x10000000):
xsct% dow -data “image.ub” 0x10000000
100% 104MB 0.4MB/s 04:49
Successfully downloaded image.ub
xsct% con
下载完成后释放 CPU,然后在 U-Boot 命令行中使用 bootm 命令启动内核:
Zynq> bootm 0x10000000
## Loading kernel from FIT Image at 10000000 ...
Using ‘conf-system-top.dtb’ configuration
Verifying Hash Integrity ... OK
Trying ‘kernel-1’ kernel subimage
Description: Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x100000f8
Data Size: 56678904 Bytes = 54.1 MiB
Architecture: ARM
OS: Linux
Load Address: 0x00200000
Entry Point: 0x00200000
Hash algo: sha256
Hash value: a6b9da747c32596a2818145ac499b124900effba9552aa23483fe758574c1003
Verifying Hash Integrity ... sha256+ OK
...
## Loading fdt from FIT Image at 10000000 ...
Using ‘conf-system-top.dtb’ configuration
Verifying Hash Integrity ... OK
Trying ‘fdt-system-top.dtb’ fdt subimage
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x1360dbfc
Data Size: 20202 Bytes = 19.7 KiB
Architecture: ARM
Hash algo: sha256
Hash value: f440bd81389f4e984d78d8baba23f93118ce9562bfcce6c47a741b1ef01cb238
Verifying Hash Integrity ... sha256+ OK
Booting using the fdt blob at 0x1360dbfc
Loading Kernel Image
Loading Ramdisk to 2ce0e000, end 2ffff260 ... OK
Loading Device Tree to 2ce06000, end 2ce0dee9 ... OK
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 5.10.0-xilinx-v2021.1 (oe-user@oe-host) (arm-xilinx-linux-gnueabi-gcc (GCC) 10.2.0, GNU ld (GNU Binutils) 2.35.1) #1 SMP PREEMPT Fri Jun 4 15:57:16 UTC 2021
CPU: ARMv7 Processor [413fc090] revision 0 (ARMv7), cr=18c5387d
...
PetaLinux 2021.1 ZynqLinux ttyPS0
root@ZynqLinux:~ > uname -r
5.10.0-xilinx-v2021.1
总结
通过 JTAG 启动 Zynq-7000 嵌入式 Linux 系统虽然步骤略显繁琐,但在调试和特定部署场景下是极其重要的技能。掌握此方法,意味着你拥有了在缺乏传统启动媒介时,依然能引导和控制目标系统的核心能力。随着云原生和基础设施即代码(IaaS)理念的普及,这种对底层硬件的精细控制能力,也为构建更可靠、可远程管理的嵌入式边缘节点奠定了基础。