声明:本文是真实案例分析,而非crash分析工具使用说明,不熟悉相关工具的同学,请参考官方文档
1、问题现场:
Unable to handle kernel NULL pointer dereference at virtual address 00000001
Mem abort info:
Exception class = DABT (current EL), IL = 32 bits
SET = 0, FnV = 0
EA = 0, S1PTW = 0
Data abort info:
ISV = 0, ISS = 0x00000006
CM = 0, WnR = 0
user pgtable: 4k pages, 39-bit VAs, pgd = ffffffc03c784000
[0000000000000001] *pgd=00000000070f8003, *pud=00000000070f8003, *pmd=0000000000000000
Internal error: Oops: 96000006 [#1] PREEMPT SMP
Modules linked in:
CPU: 0 PID: 1948 Comm: pt-osd Not tainted 4.14.61-00003-g8d661a5-dirty #39
Hardware name:
task: ffffffc031325700 task.stack: ffffff800cc50000
PC is at i2c_dw_isr+0x4fc/0x654
LR is at i2c_dw_isr+0x428/0x654
pc : [<ffffff80086c0f70>] lr : [<ffffff80086c0e9c>] pstate: 604001c9
sp : ffffff8008003e10
x29: ffffff8008003e10 x28: 000000000000ff80
x27: 0000000000000000 x26: 0000000000000001
x25: 0000000000000400 x24: ffffff800c34b7f8
x23: 0000000000000001 x22: ffffff8008fb1000
x21: 0000000000000010 x20: 00000000ffff0081
x19: ffffffc03e170018 x18: 000000000000671f
x17: 0000007f80918620 x16: 0000007f80c54698
x15: 0000000000001d55 x14: 0000000000000000
x13: 0000000000000000 x12: 0000000000000000
x11: 0000000000000000 x10: 0000000000000000
x9 : 0000000000000000 x8 : ffffff80086c10c8
x7 : 0000000000000001 x6 : 0000000000000400
x5 : 0000000000000c34 x4 : 0000000000000065
x3 : 0000000000000001 x2 : 0000000000000000
x1 : 0000000000000000 x0 : 0000000000000000
X19: 0xffffffc03e16ff98:
ff98 00000000 00000000 57d3a303 00000000 08ae0e10 ffffff80 00000000 00000000
ffb8 00001000 00000000 00000000 00000000 08f0a328 ffffff80 000044ae 00000001
ffd8 81a40052 00000000 00000000 00000000 00000000 00000000 00000000 00000000
fff8 00000000 00000000 3e04ee00 ffffffc0 0474a698 ffffffc0 08559eb0 ffffff80
0018 0474a410 ffffffc0 09105000 ffffff80 00000000 00000000 91e791e7 00000000
0038 0c34b778 ffffff80 0c34b778 ffffff80 3e04e980 ffffffc0 00000000 00000000
0058 00000000 00000000 086c1978 ffffff80 00000000 00000000 00000000 00000000
0078 0c34b888 ffffff80 00000001 00000000 00000000 00000000 0c34b9a7 ffffff80
Process pt-osd (pid: 1948, stack limit = 0xffffff800cc50000)
Call trace:
Exception stack(0xffffff8008003cd0 to 0xffffff8008003e10)
3cc0: 0000000000000000 0000000000000000
3ce0: 0000000000000000 0000000000000001 0000000000000065 0000000000000c34
3d00: 0000000000000400 0000000000000001 ffffff80086c10c8 0000000000000000
3d20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
3d40: 0000000000000000 0000000000001d55 0000007f80c54698 0000007f80918620
3d60: 000000000000671f ffffffc03e170018 00000000ffff0081 0000000000000010
3d80: ffffff8008fb1000 0000000000000001 ffffff800c34b7f8 0000000000000400
3da0: 0000000000000001 0000000000000000 000000000000ff80 ffffff8008003e10
3dc0: ffffff80086c0e9c ffffff8008003e10 ffffff80086c0f70 00000000604001c9
3de0: ffffff8008003e10 ffffff80086c0b90 0000007fffffffff 0000000000000001
3e00: ffffff8008003e10 ffffff80086c0f70
[<ffffff80086c0f70>] i2c_dw_isr+0x4fc/0x654
[<ffffff8008106a28>] __handle_irq_event_percpu+0x7c/0x148
[<ffffff8008106bc8>] handle_irq_event+0x58/0xc0
[<ffffff800810a740>] handle_fasteoi_irq+0x98/0x180
[<ffffff8008105ad8>] generic_handle_irq+0x24/0x38
[<ffffff8008106220>] __handle_domain_irq+0x60/0xac
[<ffffff8008081384>] gic_handle_irq+0x104/0x1c4
Exception stack(0xffffff800cc53ec0 to 0xffffff800cc54000)
3ec0: 0000000000000035 0000007f2408bee0 0000000000000000 0000007f24000030
3ee0: 0000000000000000 0000007f240cbf60 0000007f2408a2d0 0000000000000001
3f00: 00000021000001bd 000001be0001f0be 0000000000000071 0000007f24000778
3f20: 0001f0bb00000021 00000021000001bb 0000000000000000 0000000000001d55
3f40: 0000007f80c54698 0000007f80918620 000000000000671f 0000007f2408bef0
3f60: 0000007f2408bec0 0000007ea56fa680 0000007ea56fa680 00000000007e9000
3f80: 0000007ea56fa750 0000000000000d24 000000000000003a 0000007ea56fa670
3fa0: 0000000000000002 0000007ea56fa510 0000007f806f43c0 0000007ea56fa510
3fc0: 0000007f80918648 0000000060000000 0000000000000009 00000000ffffffff
3fe0: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
[<ffffff80080833f8>] el0_irq_naked+0x50/0x58
Code: 6b1f037f 32160026 1a8110c1 3707fc85 (394002e5)
---[ end trace 9acff67b837bbb81 ]---
Kernel panic - not syncing: Fatal exception in interrupt
SMP: stopping secondary CPUs
oops, flush dcache for cpu3
oops, flush dcache for cpu2
oops, flush dcache for cpu1
Kernel Offset: disabled
CPU features: 0x0a02a38
Memory Limit: none
panic_handler:kernel panic:0.
2、分析问题思路
1)首先通过PC,查看对应的汇编代码
crash_arm64> dis -l ffffff80086c0f70
drivers/i2c/busses/i2c-designware-master.c: 336 0xffffff80086c0f70 <i2c_dw_isr+1276>: ldrb w5, [x23]
对应一个ldr指令,地址是x23,但发现x23:0000000000000001,与上面问题现场Unable to handle kernel NULL pointer dereference at virtual address 00000001刚好吻合。
2)分析i2c_dw_isr()对应的汇编代码,发现x19寄存器就是struct dw_i2c_dev结构体指针,x23寄存器是struct i2c_msg结构体buf成员指针,x24寄存器是struct i2c_msg结构体指针
crash_arm64> struct i2c_msg ffffff800c34b7f8 -x
struct i2c_msg {
addr = 0xb888,
flags = 0xc34,
len = 0xff80,
buf = 0x1 <Address 0x1 out of bounds>
}
crash_arm64>
3)但是从x19寄存器来看,msgs指针好像和x24寄存器值不相同
crash_arm64>
crash_arm64> struct dw_i2c_dev.msgs ffffffc03e170018
msgs = 0xffffff800c34b888
crash_arm64>
crash_arm64> rd ffffff800c34b7f8 -x
ffffff800c34b7f8: ffffff800c34b888
crash_arm64>
4)从这里看出x24指向的struct i2c_msg结构体内容,居然是当前struct i2c_msg结构体指针
5)为了弄清楚执行i2c_dw_isr()时struct i2c_msg结构体真实内容,故在开机时预先申请了一个struct dw_i2c_dev结构体和struct i2c_msg结构体空间,当代码执行到i2c_dw_isr()时,拷贝当时的struct dw_i2c_dev结构体和struct i2c_msg结构体内容
6)比较两者发现,只有cmd_complete和msgs不同,其余均相同,故怀疑是进程同步问题,而非DDR跳变,或者踩内存问题
怀疑进程同步理由:
cmd_complete.wait.lock.rlock.raw_lock.owner,两者的值只相差1,说明是两次连续的i2c_transfer()
7)由于平台使用SMP,有没有一种可能是cpu0在执行中断处理程序,而另外一个CPU在发起I2C访问呢?
crash_arm64> struct dw_i2c_dev.adapter.bus_lock ffffffc03e170018
adapter.bus_lock = {
wait_lock = {
raw_lock = {
owner = 0,
next = 0
}
},
waiters = {
rb_root = {
rb_node = 0x0
},
rb_leftmost = 0x0
},
owner = 0xffffffc03df20000
},
crash_arm64>
crash_arm64> task 0xffffffc03df20000
PID: 1750 TASK: ffffffc03df20000 CPU: 3 COMMAND: "jmfserver"
struct task_struct {
thread_info = {
flags = 8,
addr_limit = 549755813887,
ttbr0 = 32989184,
preempt_count = 2
},
state = 2,
stack = 0xffffff800c348000,
crash_arm64> bt 1750
PID: 1750 TASK: ffffffc03df20000 CPU: 3 COMMAND: "jmfserver"
#0 [ffffff800c34b590] __switch_to at ffffff8008085df0
#1 [ffffff800c34b5b0] __schedule at ffffff8008aa54ac
#2 [ffffff800c34b640] schedule at ffffff8008aa5a24
#3 [ffffff800c34b660] schedule_timeout at ffffff8008aa90e4
#4 [ffffff800c34b700] wait_for_common at ffffff8008aa6890
#5 [ffffff800c34b790] wait_for_completion_timeout at ffffff8008aa696c
#6 [ffffff800c34b7a0] i2c_dw_xfer at ffffff80086c1748
#7 [ffffff800c34b7e0] __i2c_transfer at ffffff80086bc164
#8 [ffffff800c34b830] i2c_transfer at ffffff80086bc338
#9 [ffffff800c34b860] i2c_master_send at ffffff80086bc3d8
#10 [ffffff800c34b8a0] regmap_i2c_write at ffffff8008575584
#11 [ffffff800c34b8c0] _regmap_raw_write at ffffff80085716bc
#12 [ffffff800c34b930] regmap_bulk_write at ffffff8008571e60
从上面来看,的确存在这种情况。
8)在修改msgs成员处添加相应锁保护,问题不再复现