别再只会用GDB了:手把手教你用EJTAG调试龙芯开发板(以Loongson 3A4000为例)

张开发
2026/4/24 17:05:47 15 分钟阅读

分享文章

别再只会用GDB了:手把手教你用EJTAG调试龙芯开发板(以Loongson 3A4000为例)
龙芯开发板深度调试指南EJTAG实战全解析第一次拿到龙芯3A4000开发板时我和大多数开发者一样习惯性地打开GDB准备调试。但当板卡还处于上电初始化阶段网络和串口都没准备好时我才意识到需要更底层的调试手段——这就是EJTAG的价值所在。不同于常见的GDB远程调试EJTAG能让你在硬件最初始的状态下就获得完全控制权这对于Bootloader开发、内核移植等底层工作来说简直是救命稻草。1. 为什么龙芯开发者需要掌握EJTAG在龙芯生态中做底层开发经常会遇到这样的场景刚焊好的板子无法启动串口没有任何输出修改了CPU初始化代码后系统在内存检测阶段就挂死了或者需要单步跟踪Linux内核的早期启动过程。这些情况下传统的调试工具根本无从下手。EJTAG作为MIPS架构的原生调试接口具有几个不可替代的优势硬件级访问直接通过JTAG引脚与CPU核对话不依赖任何外设初始化全生命周期调试从第一条指令开始就能控制CPU直到系统完全启动非侵入式调试不需要在目标代码中插入任何调试桩(Stub)寄存器级控制可以读写任何CPU寄存器和内存即使MMU还未初始化特别是在龙芯3A4000这样的多核处理器上EJTAG还能实现# 查看所有核的状态 ejtag-debug -c info cores Core 0: Running at 1.8GHz, PC0xffffffffbfc00000 Core 1: Held in reset Core 2: Held in reset Core 3: Held in reset提示龙芯的EJTAG实现与标准MIPS略有不同特别要注意3A4000的TAP控制器需要特殊初始化序列2. 搭建EJTAG调试环境工欲善其事必先利其器。要使用EJTAG调试龙芯开发板需要准备以下硬件设备型号示例注意事项调试器龙芯官方EJTAG调试器建议使用v2.3以上版本连接线2x7 2.54mm间距排线注意防反插设计开发板3A4000评估板确认EJTAG接口已引出主机x86/龙芯PC需要USB 2.0以上接口硬件连接时有个容易踩的坑——3A4000的EJTAG接口定义Pin1: EJTAG_TDI Pin2: GND Pin3: EJTAG_TDO Pin4: GND Pin5: EJTAG_TMS Pin6: GND Pin7: EJTAG_TCK Pin8: GND Pin9: EJTAG_TRST Pin10: NC Pin11: VREF Pin12: NC软件方面需要准备编译ejtag-debug工具链龙芯社区提供源码安装USB驱动lsusb应能识别2961:6688设备准备对应内核的vmlinux符号文件安装过程关键步骤git clone https://github.com/loongson/ejtag-debug.git cd ejtag-debug ./configure --targetmips64el-linux make -j8 sudo cp src/ejtag-debug /usr/local/bin3. EJTAG核心调试技巧连接好硬件后让我们从几个实际开发场景出发看看EJTAG如何解决具体问题。3.1 基础寄存器操作当开发板完全无响应时首先检查CPU是否活着ejtag-debug -c print $pc 0xffffffffbfc00000这个地址是龙芯3A4000的复位向量如果能看到说明CPU至少执行到了这里。查看全部通用寄存器ejtag-debug -c info registers r0 : 0x0000000000000000 r1 : 0x0000000000000000 ... pc : 0xffffffffbfc00000 sr : 0x00000000040400003.2 内存访问技巧在早期初始化阶段用EJTAG查看内存内容非常有用ejtag-debug -c x/8x 0xffffffffbfc00000 0xbfc00000: 0x401a8000 0x00000000 0x401a8000 0x00000000 0xbfc00010: 0x401a8000 0x00000000 0x401a8000 0x00000000写入内存时要注意对齐问题ejtag-debug -c set *0x800000000x12345678注意3A4000的内存控制器初始化前直接访问内存可能失败此时应该先配置正确的SDRAM参数3.3 与GDB协同调试虽然EJTAG很强大但源码级调试还是GDB更方便。好在两者可以配合使用首先在ejtag-debug中启动GDB serverejtag-debug -g 3333然后在另一个终端连接mips64el-linux-gdb vmlinux (gdb) target remote :3333 (gdb) b start_kernel (gdb) c这样就能结合EJTAG的硬件访问能力和GDB的源码调试优势。4. 实战调试一个启动故障去年我在移植U-Boot到3A4000定制板时遇到一个典型问题系统在内存初始化后死机。通过EJTAG我这样排查首先确认CPU执行流ejtag-debug -c bt #0 0xffffffff8020a104 in __delay0x14 #1 0xffffffff8020a1a0 in delay0x20 #2 0xffffffff8028b5dc in sdram_init0x15c检查SDRAM控制器的关键寄存器ejtag-debug -c x/4x 0xffffffffbfe10480 0xbfe10480: 0x00000000 0x00000000 0x00000000 0x00000000发现问题后修改U-Boot的sdram_init函数参数重新烧写ejtag-debug -c load_binary /tmp/u-boot.bin 0xbfc00000单步跟踪确认ejtag-debug -c b 0xffffffff8028b480 ejtag-debug -c stepi 20最终发现是板载的DDR4颗粒参数配置不当导致。整个过程如果没有EJTAG可能要多花几周时间盲调。5. 高级技巧与性能分析除了基础调试EJTAG还能做很多有意思的事情多核调试# 暂停所有核 ejtag-debug -c halt all # 只让核0继续运行 ejtag-debug -c core 0 continue性能计数器分析# 配置计数器统计指令数 ejtag-debug -c pmc 0 config 0x1 # 读取计数值 ejtag-debug -c pmc 0 read缓存诊断# 查询L2缓存状态 ejtag-debug -c cache 2 info L2 Cache: 256KB, 8-way, linesize 64B这些功能在优化启动速度和调试多核竞争条件时特别有用。比如我曾经用性能计数器发现3A4000的TLB重填耗时异常最终定位到是页表配置问题。调试龙芯平台就像探险而EJTAG就是你的多功能生存刀。从最初的板级启动到复杂的多核调度问题它总能给你最底层的视角。虽然学习曲线有点陡峭但掌握后你会发现原来处理器内部的一切都是透明的。

更多文章