dma_alloc_coherent申请的内存用来初始化自旋锁导致内核oops

问题引入

最近在arm linux平台开发调试一个ip的驱动,这个驱动原本是在较早的linux内核版本上验证的,并且是使用的arm920平台,而现在我们需要将他移植到armv7a的平台上,并且使用较新的linux5.4.67版本的内核,调试过程中遇到了一处内核恐慌,报错如下

[17:13:01:765][   17.282207][   T36] Unhandled fault: external abort on non-linefetch (0x1008) at 0x8418002c
[17:13:01:780][   17.288631][   T36] pgd = (ptrval)
[17:13:01:780][   17.292018][   T36] [8418002c] *pgd=603e5811, *pte=63800667, *ppte=63800417
[17:13:01:780][   17.299030][   T36] Internal error: : 1008 [#1] SMP ARM
[17:13:01:780][   17.304151][   T36] Modules linked in: test(O+)
[17:13:01:796][   17.309032][   T36] CPU: 0 PID: 36 Comm: insmod Tainted: G           O      5.4.67+ #198
[17:13:01:811][   17.317004][   T36] Hardware name: TEST-TEXT Express
[17:13:01:811][   17.322901][   T36] PC is at arch_spin_lock+0xc/0x48
[17:13:01:811][   17.327756][   T36] LR is at arch_spin_lock+0xc/0x48
[17:13:01:827][   17.332662][   T36] pc : [<80050e64>]    lr : [<80050e64>]    psr: 600f0093
[17:13:01:827][   17.339600][   T36] sp : 81a05c80  ip : 8418003c  fp : 7f010100
[17:13:01:827][   17.345498][   T36] r10: 02000000  r9 : 00000017  r8 : 00400000
[17:13:01:843][   17.351423][   T36] r7 : 80333258  r6 : 81363c40  r5 : 8418002c  r4 : 600f0013
[17:13:01:858][   17.358626][   T36] r3 : 8418002c  r2 : 2020534f  r1 : 8418002c  r0 : 8418002c
[17:13:01:858][   17.365836][   T36] Flags: nZCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment user
[17:13:01:858][   17.373727][   T36] Control: 10c5387d  Table: 6196404a  DAC: 00000055
[17:13:01:874][   17.380131][   T36] Process insmod (pid: 36, stack limit = 0x(ptrval))
[17:13:01:874][   17.386650][   T36] Stack: (0x81a05c80 to 0x81a06000)
[17:13:01:874][   17.391818][   T36] 5c80: 600f0013 8028ac44 8418002c 8004fe94 ffffffff 8418002c 81363c40 7f0032ac
[17:13:01:889][   17.400670][   T36] 5ca0: 81363c40 8418002c 81363c64 00000000 81363c40 7f0033b8 81363c40 81363c64
[17:13:01:905][   17.409522][   T36] 5cc0: 81363c40 00000000 832c5180 7f003474 832c5180 832c5180 803ade84 832c5180
[17:13:01:905][   17.418372][   T36] 5ce0: 40043000 40043000 00000000 7f000bd8 849c0000 7f00c4cf 8046fe00 81a05d18
[17:13:01:921][   17.427226][   T36] 5d00: 81a05d18 00000000 81363b40 8022d658 8047c410 81a05d28 80330af0 8047c400
[17:13:01:936][   17.436074][   T36] 5d20: 00000000 80230440 7f010000 7f010300 00000000 803dcdb0 7f0100ac 00000003
[17:13:01:936][   17.444937][   T36] 5d40: fffffdfb 7f0004ec 00400000 02000000 ffffffff 81a05d5c 803dcdb0 7f0100ac
[17:13:01:952][   17.453780][   T36] 5d60: 8047c410 7f0100ac 00000000 80230948 8047c410 00000000 00000000 8022f118
[17:13:01:952][   17.462640][   T36] 5d80: 00000000 8047c410 7f0100ac 803b6318 81363980 81a05f34 80078c60 8022f5c4
[17:13:01:967][   17.471498][   T36] 5da0: 00000000 8047c410 7f0100ac 8022f688 8047c410 7f0100ac 8022f5dc 8022d86c
[17:13:01:983][   17.480349][   T36] 5dc0: 803e4b58 80479334 7f0100ac 832c5400 00000000 8022e728 7f00c4cf 7f00c4d0
[17:13:01:983][   17.489197][   T36] 5de0: 00000000 7f0100ac 7f015000 ffffe000 00000000 8022fba8 803be000 7f015000
[17:13:01:999][   17.498055][   T36] 5e00: ffffe000 7f01501c 803be000 8000a5f0 837de8a0 803dfd80 800b3470 00000000
[17:13:02:014][   17.506914][   T36] 5e20: 81363980 0040003f 80078c60 800bfc00 832c5400 837de880 803dfe40 8007c0b8
[17:13:02:014][   17.515768][   T36] 5e40: 8379fc60 81363980 7f010100 800bed2c 7f010100 81363940 00000002 7f010100
[17:13:02:030][   17.524619][   T36] 5e60: 81363940 81363a40 7f010148 8007a2c4 7f010100 600f0013 00000002 81363940
[17:13:02:030][   17.533468][   T36] 5e80: 00000002 8007c0c0 7f01010c 00007fff 7f010100 80079178 81363948 00000708
[17:13:02:045][   17.542326][   T36] 5ea0: 84147e20 7f017000 7f0102d8 8412f000 001592c8 00000fa6 84130880 00171cf8
[17:13:02:045][   17.551155][   T36] 5ec0: 0000e700 00000c5d e92d4010 00000000 00000000 00000000 00000000 00000000
[17:13:02:061][   17.559991][   T36] 5ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[17:13:02:077][   17.568868][   T36] 5f00: 00000000 00000000 00000000 00008e98 00189310 84147e98 00000000 001592c8
[17:13:02:077][   17.577735][   T36] 5f20: 81a04000 00000080 0014492f 8007c3a0 00000000 8413e3c8 8413e600 8412f000
[17:13:02:092][   17.586589][   T36] 5f40: 00018e98 84147768 84147590 84141ba0 00011000 00012cd0 00005d90 00013c90
[17:13:02:092][   17.595423][   T36] 5f60: 00000000 00000000 00000000 00005d80 0000002b 0000002c 00000021 00000000
[17:13:02:108][   17.604283][   T36] 5f80: 00000013 00000000 00000000 00018e98 01010000 00000000 00000080 80009204
[17:13:02:108][   17.613155][   T36] 5fa0: 81a04000 80009000 00018e98 01010000 00170478 00018e98 001592c8 00000000
[17:13:02:123][   17.622000][   T36] 5fc0: 00018e98 01010000 00000000 00000080 7ea13e58 7ea13e5c 00000000 0014492f
[17:13:02:139][   17.630855][   T36] 5fe0: 7ea13b30 7ea13b20 00036e51 00011d22 600f0030 00170478 00000000 00000000
[17:13:02:139][   17.639896][   T36] [<80050e64>] (arch_spin_lock) from [<8028ac44>] (_raw_spin_lock_irqsave+0x10/0x18)
[17:13:02:155][   17.649051][   T36] [<8028ac44>] (_raw_spin_lock_irqsave) from [<8004fe94>] (down+0xc/0x3c)
[17:13:02:155][   17.658430][   T36] [<8004fe94>] (down) from

猜想解决

遇到这个问题后我们可以看到是自旋锁出数据访问异常,排查代码发现,因为这份代码适配的内核版本较为老旧,代码中申请了很多个信号量作为互斥锁,而互斥锁申请锁的函数down会使用到自旋锁,自旋锁使用的内存在访问使用时产生了数据访问异常,这让我们不得不怀疑内存申请是否存在问题,进一步探索发现,这份驱动代码第一次申请互斥锁是使用kmalloc来申请内存,该锁的使用是没有任何异常的,而后其他的互斥锁申请是使用的dma_alloc_coherent的,看到这里就基本上是怀疑dma_alloc_coherent函数申请的内存是不能用于互斥锁的,保留这个猜想,我们尝试修改代码运行,果然问题解决!!

探究本源

仅仅解决表面问题可不是我的风格,在工作不忙时,我抽空开始翻阅自旋锁的实现代码和dma_alloc_coherent的代码,最终确认了两点事实:

  • 自旋锁为了保证在多核smp系统中变量访问的原子性,使用了
    LDREX/STREX的指令
  • dma_alloc_coherent申请的内存在MMU映射时会配置其内存属性为Device,而正常的Kmalloc申的内存属性为Normal

基于上述事实就不能猜到LDREX/STREX的指令可能不能用于Device属性的内存访问,毕竟外设能访问修改的内存地址CPU是无法监控的到(严谨来说AXI总线上似乎有能做全局监控的,但我想应该需要外设也支持这个信号才行,本人作为嵌入式软件开发者对SOC内部总线了解不够,这里就不展开来说了)。最后按本人习惯还是想在arm的手册里找到明确说明这一点的内容,为此我查找了很多arm的文档(不得不说arm的文档太多,有时候感觉分类有点乱),在armv7a架构手册并没能找到,最终在《ARM® Synchronization Primitives Development Article》文档中1.2.1节确认了如下描述:

The LDREX and STREX instructions split the operation of atomically updating memory into two separate steps. Together, they provide atomic updates in conjunction with exclusive monitors that track exclusive memory accesses, see Exclusive monitors on page 1-5. Load-Exclusive and Store-Exclusive must only access memory regions marked as Normal.

至此问题解决,撒花!

更多推荐

dma_alloc_coherent申请的内存用来初始化自旋锁导致内核oops