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

简介:    前几天在学习内核源码的时候,无意中看到了Linux内核中有中断栈的概念。这个是我以前没有注意到的,为了深入理解这个知识,我查找了一些资料:Linux内核中的中断栈与内核栈的补充说明 《深入Linux内核构架》第14章 内核活动 14.1 中断 P695   这些资料都是针对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),这个变量必然会被放在运行中断例程时所使用的栈中。在这个中断例程中打印出当前进程的内核栈范围和这个自动变量的地址,从中看出运行中断例程所使用的栈是否为进程的内核栈。如果自动变量的地址不在当前进程的内核栈范围中,则可以推断出这个内核使用了独立的中断栈。

img_4f2bff255b4bfb12086697098f402dd7.jpg
  


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

    ARM平台是一个开发板,有一个独立GPIO作为中断的引脚,可以手工产生中断,是一个非共享中断,所以代码比较简单,只需要模块初始化和清理函数即可。
ARM平台实验代码: zip.gif 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 平台实验代码: zip.gif 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)再做一次,有兴趣的朋友可以自行修改源码。
相关文章
|
6月前
|
网络协议 Java Linux
Linux学习笔记
Linux学习笔记
107 0
|
2月前
|
Shell Linux
Linux shell编程学习笔记30:打造彩色的选项菜单
Linux shell编程学习笔记30:打造彩色的选项菜单
|
3月前
|
Ubuntu Linux
查看Linux系统架构的命令,查看linux系统是哪种架构:AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号
查看Linux系统架构的命令,查看linux系统是哪种架构:AMD、ARM、x86、x86_64、pcc 或 查看Ubuntu的版本号
715 3
|
16天前
|
Docker 容器
docker:记录如何在x86架构上构造和使用arm架构的镜像
为了实现国产化适配,需将原x86平台上的Docker镜像转换为适用于ARM平台的镜像。本文介绍了如何配置Docker buildx环境,包括检查Docker版本、安装buildx插件、启用实验性功能及构建多平台镜像的具体步骤。通过这些操作,可以在x86平台上成功构建并运行ARM64镜像,实现跨平台的应用部署。
123 2
|
25天前
|
并行计算 Ubuntu Linux
Ubuntu学习笔记(三):Linux下操作指令大全
Ubuntu学习笔记,介绍了Linux操作系统中常用的命令和操作,如文件管理、系统信息查看、软件安装等。
39 3
|
1月前
|
机器学习/深度学习 弹性计算 编解码
阿里云服务器计算架构X86/ARM/GPU/FPGA/ASIC/裸金属/超级计算集群有啥区别?
阿里云服务器ECS提供了多种计算架构,包括X86、ARM、GPU/FPGA/ASIC、弹性裸金属服务器及超级计算集群。X86架构常见且通用,适合大多数应用场景;ARM架构具备低功耗优势,适用于长期运行环境;GPU/FPGA/ASIC则针对深度学习、科学计算、视频处理等高性能需求;弹性裸金属服务器与超级计算集群则分别提供物理机级别的性能和高速RDMA互联,满足高性能计算和大规模训练需求。
|
2月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
3月前
|
机器学习/深度学习 算法 数据库
阿里云服务器架构区别解析:从X86计算、Arm计算到高性能计算架构的区别参考
在我们选择阿里云服务器的架构时,选择合适的云服务器架构对于提升业务效率、保障业务稳定至关重要。阿里云提供了多样化的云服务器架构选择,包括X86计算、ARM计算、GPU/FPGA/ASIC、弹性裸金属服务器以及高性能计算等。本文将深入解析这些架构的特点、优势及适用场景,以供参考和选择。
阿里云服务器架构区别解析:从X86计算、Arm计算到高性能计算架构的区别参考
|
3月前
|
Linux 网络安全 开发工具
内核实验(二):自定义一个迷你Linux ARM系统,基于Kernel v5.15.102, Busybox,Qemu
本文介绍了如何基于Linux Kernel 5.15.102版本和BusyBox创建一个自定义的迷你Linux ARM系统,并使用QEMU进行启动和调试,包括内核和BusyBox的编译配置、根文件系统的制作以及运行QEMU时的命令和参数设置。
258 0
内核实验(二):自定义一个迷你Linux ARM系统,基于Kernel v5.15.102, Busybox,Qemu
|
3月前
|
存储 运维 Shell
运维.Linux.bash学习笔记.数组及其使用
运维.Linux.bash学习笔记.数组及其使用
32 0