作为一名嵌入式Linux开发者,内核移植调试是绕不开的必修课。记得我第一次尝试在IMX6ULL上移植主线内核时,整整两周时间都耗在各种奇怪的报错上。本文将分享我在正点原子IMX6ULL开发板上移植Linux 7.0内核时积累的调试经验,这些方法能帮你节省至少50%的调试时间。
嵌入式Linux内核移植过程中,90%的问题都集中在以下几个领域:
如果没有系统化的调试方法,开发者很容易陷入"改代码→编译→烧录→测试"的死循环。接下来介绍的六大类调试技巧,将帮助你建立完整的调试思维框架。
dmesg是内核给开发者最直接的调试接口。掌握以下命令组合能快速定位90%的启动问题:
bash复制# 组合命令:清空日志后立即捕获新日志(避免历史干扰)
dmesg -c > /dev/null && sleep 1 && dmesg -T -l err,warn
这个命令序列的执行逻辑是:
-c清空环形缓冲区sleep 1等待新日志产生-T显示人类可读时间戳-l err,warn只显示错误和警告内核日志级别可通过多种方式动态调整:
bash复制# 运行时调整控制台日志级别(只影响控制台输出)
echo 4 > /proc/sys/kernel/printk
# 内核启动参数设置(需修改bootargs)
loglevel=4 debug # 同时开启debug模式
# 驱动代码中动态设置(示例)
printk(KERN_DEBUG "调试信息"); // 级别7
printk(KERN_INFO "状态信息"); // 级别6
经验:在调试阶段建议保持loglevel=7,生产环境设为4。注意高日志级别可能影响系统性能。
结合grep的正则表达式可以实现精准过滤:
bash复制# 查找所有probe失败的驱动
dmesg | grep -E "probe.*failed|error.*initializ|failed.*to get"
# 查找内存相关错误
dmesg | grep -E "oom|out of memory|alloc failed"
# 查找设备树解析问题
dmesg | grep -E "of_|dtb|fdt|missing.*property"
设备树调试的金科玉律:永远先检查/proc/device-tree。以下是进阶用法:
bash复制# 递归查看节点属性(需安装tree命令)
tree -l /proc/device-tree/soc/
# 查看特定属性的十六进制值
hexdump -C /proc/device-tree/soc/bus@2100000/lcdif@21c8000/reg
# 检查中断映射
cat /proc/device-tree/soc/bus@2100000/lcdif@21c8000/interrupts
设备树编译器(dtc)的进阶用法:
bash复制# 生成带注释的反编译结果(需内核开启CONFIG_OF_OVERLAY)
dtc -I fs -O dts -o full.dts -@ /proc/device-tree
# 只提取特定节点的定义
dtc -I fs -O dts /proc/device-tree | \
awk '/lcdif@21c8000 {/,/^};/' > lcdif-node.dts
对于显示子系统,OF graph的正确连接至关重要:
bash复制# 自动化验证连接性脚本
for node in $(find /proc/device-tree -name "remote-endpoint"); do
echo -n "$node → "
cat $node 2>/dev/null || echo "NULL"
done
这个脚本会遍历所有remote-endpoint属性,显示连接关系。正常情况应该成对出现。
bash复制# 显示所有CRTC的状态
cat /sys/kernel/debug/dri/0/crtc-*/status
# 获取当前帧的VSYNC时间
cat /sys/kernel/debug/dri/0/mxsfb-vsync
# 手动触发屏幕刷新(调试闪屏问题)
echo 1 > /sys/kernel/debug/dri/0/force_redraw
modetest是DRM调试的瑞士军刀:
bash复制# 测试特定显示模式(带颜色格式验证)
modetest -M mxsfb -s 1024x600@RG24 -P 29@RG16
# 测试多buffer切换(调试撕裂问题)
modetest -M mxsfb -s 1024x600@RG24 -F buffers=3
参数说明:
-P指定像素格式-F启用多缓冲@RG24表示RGB888格式bash复制#!/bin/bash
# 内核关键配置检查工具
check_config() {
zcat /proc/config.gz | grep -q "$1=y" && \
echo -e "\033[32m[OK]\033[0m $1" || \
echo -e "\033[31m[FAIL]\033[0m $1"
}
check_config CONFIG_DRM_MXSFB
check_config CONFIG_DRM_PANEL_SIMPLE
check_config CONFIG_TOUCHSCREEN_GOODIX
CONFIG_FB_MXS=nCONFIG_CLK_IMX6UL=yCONFIG_IMX_DMA=ybash复制# 实时监控GPIO状态变化
watch -n 0.1 "cat /sys/kernel/debug/gpio"
# 检查GPIO复用状态(IMX6ULL专用)
cat /sys/kernel/debug/pinctrl/20e0000.iomuxc/pinmux-pins
bash复制# 连续读取I2C寄存器(调试触摸屏)
i2ctransfer -y 1 w1@0x5d 0x00 r16
# 压力测试I2C总线
for i in {1..100}; do
i2cget -y 1 0x5d 0x00 && echo "Pass $i" || break
done
bash复制# 设置跟踪函数
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo drm_atomic_helper_commit > /sys/kernel/debug/tracing/set_graph_function
# 开始记录(最多10MB数据)
echo 1 > /sys/kernel/debug/tracing/tracing_on
sleep 5
echo 0 > /sys/kernel/debug/tracing/tracing_on
# 查看结果
cat /sys/kernel/debug/tracing/trace > /tmp/drm_trace.log
bash复制# 启用中断事件跟踪
echo irq:* > /sys/kernel/debug/tracing/set_event
# 统计中断延迟
cat /sys/kernel/debug/tracing/trace_stat/function0
mermaid复制graph TD
A[LCD无显示] --> B{背光是否亮?}
B -->|是| C[检查dmesg中的DRM日志]
B -->|否| D[检查背光供电电路]
C --> E{有probe成功日志?}
E -->|是| F[用modetest测试模式]
E -->|否| G[检查设备树节点]
F --> H{能显示测试图案?}
H -->|是| I[检查应用层配置]
H -->|否| J[用示波器测时序]
| 错误代码 | 含义 | 典型解决方案 |
|---|---|---|
| -EPROBE_DEFER | 依赖资源未就绪 | 检查驱动初始化顺序 |
| -ENODEV | 设备不存在 | 验证设备树节点 |
| -ENOMEM | 内存不足 | 检查CMA配置 |
| -ETIMEDOUT | 操作超时 | 调整超时参数或检查硬件连接 |
| 工具 | 安装方法 | 用途 |
|---|---|---|
| i2c-tools | apt install i2c-tools | I2C设备检测 |
| usbutils | apt install usbutils | USB设备枚举 |
| evtest | apt install evtest | 输入设备测试 |
| strace | apt install strace | 系统调用跟踪 |
bash复制#!/bin/bash
# 一键收集调试信息
DEBUG_DIR="/tmp/debug_$(date +%s)"
mkdir -p $DEBUG_DIR
# 收集系统信息
dmesg > $DEBUG_DIR/dmesg.log
lsmod > $DEBUG_DIR/lsmod.log
cat /proc/cmdline > $DEBUG_DIR/cmdline.log
# 收集设备树信息
dtc -I fs /proc/device-tree -O dts > $DEBUG_DIR/full.dts
# 收集DRM状态
ls /sys/class/drm/ > $DEBUG_DIR/drm_devices.log
cat /sys/kernel/debug/dri/*/state > $DEBUG_DIR/drm_state.log
echo "调试信息已保存到 $DEBUG_DIR"
掌握这些调试方法后,你会发现内核移植过程中的大部分问题都能在30分钟内定位。记住,好的调试不是靠运气,而是靠系统化的方法和工具链。