Linux独立中断栈学习笔记及验证实验(ARM、x86)

   前几天在学习内核源码的时候,无意中看到了Linux内核中有 中断栈 的概念。这个是我以前没有注意到的,为了深入理解这个知识,我查找了一些资料:

  1. Linux内核中的中断栈与内核栈的补充说明
  2. 《深入Linux内核构架》第14章 内核活动 14.1 中断 P695
   这些资料都是针对X86构架的。对于中断栈,我自己总结如下:

   从《深入Linux内核构架》中可以知道:内核在IA-32平台上,早期 (2.6.36及之前)内核如果配置了4K内核栈(CONFIG_4KSTACKS)(默认是8K),对于常规的内核工作以及IRQ处理例程共用这个栈来说似乎有点不够用,所有引入了两个栈:硬件IRQ栈和软件IRQ栈。在这种情况下,当内核进入中断之后,检测自己所在的栈是内核栈还是中断栈。如果是中断栈(中断嵌套情况)就去执行中断例程;如果是内核栈就切换到中断栈,同时复制当前内核栈中的部分thread_info数据到中断栈。
   但是 2.6.36之后的内核就不再有4K内核栈的配置,对于IA-32统一使用8K内核栈,并总是使用两个独立的8K中断栈。这样的改变应该是由于计算机性能的提高、内存的扩大(4G内存已经很平常,16G、32G内存也已不新鲜)以及软件的复杂度提高(对栈的需求增加)。

   这个变化的Git提交信息如下:

点击(此处)折叠或打开

  1. commit 91151240ed8e97cc4457dae4094153c2744f1eb8
  2. Merge: 211baf4 fe8e0c2
  3. Author: Linus Torvalds
  4. Date: Fri Oct 22 08:54:21 2010 -0700
  5. Merge branch 'x86-irq-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
  6. * 'x86-irq-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  7. x86, 32-bit: Align percpu area and irq stacks to THREAD_SIZE
  8. x86, 32-bit: 对其percpu域和irq栈到THREAD_SIZE
  9. x86: Move alloc_desk_mask variables inside ifdef
  10. x86:将alloc_desk_mask变量移入ifdef
  11. x86-32: Align IRQ stacks properly
  12. x86-32:适当对齐IRQ栈
  13. x86: Remove CONFIG_4KSTACKS
  14. x86:移除CONFIG_4KSTACKS
  15. x86: Always use irq stacks
  16. x86:总是使用irq栈
  17. Fixed up trivial conflicts in include/linux/{irq.h, percpu-defs.h}
  18. 修正include/linux/{irq.h, percpu-defs.h}中细小的冲突
这个提交并入主线内核的时间:2.6.36~2.6.37-rc1

点击(此处)折叠或打开

  1. $ git tag --contains 91151240ed8
  2. v2.6.37
  3. v2.6.37-rc1
  4. v2.6.37-rc2
  5. v2.6.37-rc3
  6. v2.6.37-rc4
  7. v2.6.37-rc5
  8. v2.6.37-rc6
  9. v2.6.37-rc7
  10. v2.6.37-rc8
  11. v2.6.38
  12. v2.6.38-rc1
  13. v2.6.38-rc2
  14. v2.6.38-rc3
  15. v2.6.38-rc4
  16. v2.6.38-rc5
  17. v2.6.38-rc6
  18. v2.6.38-rc7
  19. v2.6.38-rc8
  20. ......
   对于内核栈到转换,大家可以参考《深入Linux内核构架》。里面有很详细的介绍。但是这个是针对x86平台的。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  我是做嵌入式Linux开发的,so 我所想的是 ARM平台是否有同样的设计呢?我跟踪了ARM构架的内核代码发现其中(arch/arm/kernel/irq.c)并 没有和x86类似的栈转换设计。也就是说:ARM并没有独立的中断栈,中断共用当前进程的内核栈。但是单从代码上分析我觉得还是不够的,有可能是我能力有限,没有看出来。所以,再通过实验来证明才是比较可靠的。所有我设计了一个对比实验来证明,使用原理如下:

   编写一个内核模块,在模块的初始化函数中注册一个中断。在中断例程中定义一个自动变量(test_point),这个变量必然会被放在运行中断例程时所使用的栈中。在这个中断例程中打印出当前进程的内核栈范围和这个自动变量的地址,从中看出运行中断例程所使用的栈是否为进程的内核栈。如果自动变量的地址不在当前进程的内核栈范围中,则可以推断出这个内核使用了独立的中断栈。

  


    我在ARM平台和IA-32平台都做了实验。

    ARM平台是一个开发板,有一个独立GPIO作为中断的引脚,可以手工产生中断,是一个非共享中断,所以代码比较简单,只需要模块初始化和清理函数即可。
ARM平台实验代码:  irq_stack_test_module_v2 _pub.zip   
在编译前,请自行修改Makefile和头文件(中断号)。
     
    开发板(基于TI8168,内核2.6.37)上的实验数据如下:

点击(此处)折叠或打开

  1. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  2. test_point@0xc04c1ea4
  3. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  4. test_point@0xc04c1ea4
  5. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  6. test_point@0xc04c1ea4
  7. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  8. test_point@0xc04c1ea4
  9. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  10. test_point@0xc04c1ea4
  11. swapper-PID:0-kernel_stack@0xc04c0000-to-c04c2000
  12. test_point@0xc04c1ea4
  13. OGLES2Chameleon-PID:1349-kernel_stack@0xdd6ee000-to-dd6f0000
  14. test_point@0xdd6eff0c
  15. OGLES2Chameleon-PID:1349-kernel_stack@0xdd6ee000-to-dd6f0000
  16. test_point@0xdd6eff0c
  17. OGLES2Chameleon-PID:1349-kernel_stack@0xdd6ee000-to-dd6f0000
  18. test_point@0xdd6eff0c
  19. OGLES2Chameleon-PID:1349-kernel_stack@0xdd6ee000-to-dd6f0000
  20. test_point@0xdd6eff0c
从上面可以看出: 所有的test_point都在当前进程内核栈中,ARM没有独立的中断栈。

------------------------------------------------------------------------------
     在IA-32就没这么方便了,毕竟是PC,不太方便引一个外部可以手动产生的中断,所以就使用了一个共享中断。当然这个共享中断最好是可以有频繁的中断,这样才可以产生我们需要的打印数据。由于使用了共享中断,我们必须有一个设备结构体要传递给中断申请函数,所以代码就稍微麻烦一点点。
IA-32 平台实验代码:  irq_stack_test_module_x86_pub.zip   
在编译前,请自行修改Makefile和头文件(中断号)。

    IA-32 PC上的实验数据如下:

点击(此处)折叠或打开

  1. Linux tekkaman-desktop 2.6.32-40-generic #87-Ubuntu SMP Mon Mar 5 20:26:31 UTC 2012 i686 GNU/Linux
  2. 内核配置文件中:# CONFIG_4KSTACKS is not set
  3. [ 3567.989081] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  4. [ 3567.989082] test_point@0xc0765e94
  5. [ 3568.005816]
  6. [ 3568.005817] chrome-PID:4194-kernel_stack@0xf121a000-to-f121c000
  7. [ 3568.005818] test_point@0xf121bea0
  8. [ 3568.022556]
  9. [ 3568.022557] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  10. [ 3568.022558] test_point@0xc0765e94
  11. [ 3568.039293]
  12. ......
  13. [ 3569.696301] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  14. [ 3569.696302] test_point@0xc0765e94
  15. [ 3569.713021]
  16. [ 3569.713022] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  17. [ 3569.713023] test_point@0xc0765e94
  18. [ 3569.729764]
  19. [ 3569.729766] nautilus-PID:1662-kernel_stack@0xf577c000-to-f577e000
  20. [ 3569.729767] test_point@0xf577df24
  21. [ 3569.746502]
  22. [ 3569.746503] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  23. [ 3569.746505] test_point@0xc0765e94
  24. [ 3569.763234]
  25. [ 3569.763235] swapper-PID:0-kernel_stack@0xc0764000-to-c0766000
  26. [ 3569.763236] test_point@0xc0765e94
从实验中可以看出, 所有的test_point都在进程内核栈中,没有独立的中断栈。

更换了一台高版本内核的 PC:

点击(此处)折叠或打开

  1. Linux  3.2.1-gentoo-r2 #2 SMP Wed Feb 22 08:57:23 CST 2012 i686 AMD Athlon(tm) 64 X2 Dual Core Processor 4800+ AuthenticAMD GNU/Linux
  2. 中断号:10
  3. [ 3809.857920] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  4. [ 3809.857923] test_point@0xf5459f90
  5. [ 3809.867821]
  6. [ 3809.867823] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  7. [ 3809.867826] test_point@0xf5459f90
  8. [ 3809.868093]
  9. [ 3809.868095] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  10. [ 3809.868098] test_point@0xf5459f90
  11. [ 3810.170480]
  12. [ 3810.170483] chrome-PID:16845-kernel_stack@0xcc2a6000-to-cc2a8000
  13. [ 3810.170487] test_point@0xf5459f90
  14. [ 3810.170919]
  15. [ 3810.170920] chrome-PID:16845-kernel_stack@0xcc2a6000-to-cc2a8000
  16. [ 3810.170923] test_point@0xf5459f90
  17. [ 3810.217095]
  18. [ 3810.217099] chrome-PID:16845-kernel_stack@0xcc2a6000-to-cc2a8000
  19. [ 3810.217102] test_point@0xf5459f90
  20. [ 3811.327909]
  21. [ 3811.327913] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  22. [ 3811.327916] test_point@0xf5459f90

  23. 中断号:41
  24. [ 3972.337204] syslog-ng-PID:2274-kernel_stack@0xf3f3a000-to-f3f3c000
  25. [ 3972.337207] test_point@0xf5459f90
  26. [ 3972.337349]
  27. [ 3972.337350] syslog-ng-PID:2274-kernel_stack@0xf3f3a000-to-f3f3c000
  28. [ 3972.337353] test_point@0xf5459f90
  29. [ 3972.337497]
  30. [ 3972.337499] syslog-ng-PID:2274-kernel_stack@0xf3f3a000-to-f3f3c000
  31. [ 3972.337501] test_point@0xf5459f90
  32. [ 3972.337637]
  33. [ 3972.337639] syslog-ng-PID:2274-kernel_stack@0xf3f3a000-to-f3f3c000
  34. [ 3972.337642] test_point@0xf5459f90
  35. [ 3972.385449]
  36. [ 3972.385451] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  37. [ 3972.385454] test_point@0xf5459f90
  38. [ 3972.385670]
  39. [ 3972.385672] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  40. [ 3972.385674] test_point@0xf5459f90
  41. [ 3972.385823]
  42. [ 3972.385825] swapper/1-PID:0-kernel_stack@0xf5446000-to-f5448000
  43. [ 3972.385828] test_point@0xf5459f90
从实验中可以看出, 所有的test_point都不在进程内核栈中,并都是同一个地址,so 有独立的中断栈。


综合所有实验以及内核源码,我们可以得出结论:


  1. 对于IA-32平台,高版本的内核(>2.6.36)内核都实现了独立的中断栈
  2. 对于ARM平台,内核暂未实现独立的中断栈

PS:其实对于独立的中断栈,不仅在IA-32上有,PPC等其他平台也有实现,有兴趣的朋友可以参考内核源码。对于上面的实验,也可以使用软件中断(如tasklet)再做一次,有兴趣的朋友可以自行修改源码。
阅读(1016) | 评论(0) | 转发(0) |
0

上一篇:16道嵌入式C语言面试题(经典)

下一篇:(转帖)Ascii码表(全)

相关热门文章
  • saltstack批量部署并配置nginx...
  • 欢迎回收笔记本在ChinaUnix博...
  • 一个由网络闪断导致的CICS交易...
  • gnuplot用于科学研究
  • Oracle 11g系统自动收集统计信...
  • A sample .exrc file for vi e...
  • IBM System p5 服务器 HACMP ...
  • 游标的特征
  • busybox的httpd使用CGI脚本(Bu...
  • Solaris PowerTOP 1.0 发布
评论热议

你可能感兴趣的:(Linux独立中断栈学习笔记及验证实验(ARM、x86))