

对Linux x86-64架构上硬中断的重新认识
source link: http://abcdxyzk.github.io/blog/2015/05/07/kernel-irq-irq/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

对Linux x86-64架构上硬中断的重新认识
2015-05-07 15:48:00
http://www.lenky.info/archives/2013/03/2245
对于x86硬中断的概念,一直都落在理论的认识之上,直到这两天才(因某个问题)发现Linux的实现却并非如此,这里纠正一下(注意:Linux内核源码更新太快,一个说法的时效性太短,所以需注意我提到的香草内核版本,并且以x86-64架构为基准)。
以前的认识:Linux对硬中断(本文如无特殊说明,都是指普通意义上的可屏蔽硬件中断)的处理有优先级概念,高优先级硬中断可以打断低优先级硬中断。
重新认识:
1,对于x86硬件而言,在文档325462.pdf卷3章节6.9 PRIORITY AMONG SIMULTANEOUS EXCEPTIONS AND INTERRUPTS 提到一个表格,是指如果在同一时刻有多个异常或中断到达,那么CPU会按照一个指定的优先级顺序对它们进行响应和服务,而并不是我之前所想的判断是否可相互打断执行的高低级别。
2,对于Linux系统而言,硬中断之间并没有优先级的概念(虽然Intel CPU提供支持,请参考文档325462.pdf卷3章节10.8.3 Interrupt, Task, and Processor Priority),或者说优先级只有两个,全部关闭或全部开启,如下:
Regardless of what the hardware might support, typical UNIX-type systems only make use of two levels: the minimum (all interrupts enabled) and the maximum (all interrupts disabled).
这意味着,如果一个硬中断处理函数正在执行,只要当前是处于开启中断的情况,那么此时发生的任何另外一个中断都可以打断当前处理函数,从而出现中断嵌套的情况。 值得注意的是,Linux提供对单个中断开启/禁止的接口(以软件实现为主,比如给对应中断描述符desc的status打上IRQ_DISABLED旗标):
void disable_irq(unsigned int irq)
void enable_irq(unsigned int irq)
下面来看看Linux的实际处理,其硬中断的一般处理流程(具体可见参考1、2、3以及源代码,以2.6.30.8为例):
硬件中断 -> common_interrupt -> do_IRQ -> handle_irq -> generic_handle_irq_desc -> desc->handle_irq或__do_IRQ。
其中desc->handle_irq是一个回调函数,会根据不同中断类型(I/O APIC、MSI)有不同的指向,比如:handle_fasteoi_irq()、handle_edge_irq(),这可以参考设置函数ioapic_register_intr()和setup_msi_irq()。通过/proc/interrupts可以看到各个中断的具体类型:
[root@localhost ~]# cat /proc/interrupts
CPU0 CPU1
0: 888 0 IO-APIC-edge timer
1: 96 112 IO-APIC-edge i8042
3: 1 0 IO-APIC-edge
4: 1 0 IO-APIC-edge
7: 0 0 IO-APIC-edge parport0
8: 1 0 IO-APIC-edge rtc0
9: 0 0 IO-APIC-fasteoi acpi
12: 204 0 IO-APIC-edge i8042
14: 0 0 IO-APIC-edge ata_piix
15: 460641 900 IO-APIC-edge ata_piix
16: 0 0 IO-APIC-fasteoi Ensoniq AudioPCI
17: 118347 0 IO-APIC-fasteoi ehci_hcd:usb1, ioc0
18: 70 0 IO-APIC-fasteoi uhci_hcd:usb2
19: 115143 0 IO-APIC-fasteoi eth0
24: 0 0 PCI-MSI-edge pciehp
25: 0 0 PCI-MSI-edge pciehp
26: 0 0 PCI-MSI-edge pciehp
27: 0 0 PCI-MSI-edge pciehp
28: 0 0 PCI-MSI-edge pciehp
...
不管是desc->handle_irq还是__do_IRQ,它们都会调入到另外一个函数handle_IRQ_event()。重点:从CPU接收到中断信号并开始处理,到这个函数为止,都是处于中断禁止状态。为什么?很简单,因为Intel开发者手册上是这么说的,在文档325462.pdf卷3章节6.8.1 Masking Maskable Hardware Interrupts提到:
When an interrupt is handled through an interrupt gate, the IF flag is automati-
cally cleared, which disables maskable hardware interrupts. (If an interrupt is
handled through a trap gate, the IF flag is not cleared.)
在CPU开始处理一个硬中断到进入函数handle_IRQ_event()为止的这段时间里,因为处于中断禁止状态,所以不会出现被其它中断打断的情况。但是,在进入到函数handle_IRQ_event()后,立马有了这么两句:
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();
...
函数local_irq_enable_in_hardirq()的定义如下:
#ifdef CONFIG_LOCKDEP
# define local_irq_enable_in_hardirq() do { } while (0)
#else
# define local_irq_enable_in_hardirq() local_irq_enable()
#endif
宏CONFIG_LOCKDEP用于表示当前是否开启内核Lockdep功能,这是一个调试功能,用于检测潜在的死锁类风险,如果开启,那么函数local_irq_enable_in_hardirq()为空,即继续保持中断禁止状态,为什么Lockdep功能需要保持中断禁止待后文再述,这里考虑一般情况,即不开启Lockdep功能,那么执行函数local_irq_enable_in_hardirq()就会开启中断。 看函数handle_IRQ_event()里的代码,如果没有带上IRQF_DISABLED旗标,那么就会执行函数local_irq_enable_in_hardirq(),从而启用中断。旗标IRQF_DISABLED可在利用函数request_irq()注册中断处理回调时设置,比如:
if (request_irq(uart->port.irq, bfin_serial_rx_int, IRQF_DISABLED,
"BFIN_UART_RX", uart)) {
如果没有设置,那么到函数handle_IRQ_event()这里的代码后,因为中断已经开启,当前中断的后续处理就可能被其它中断打断,从而出现中断嵌套的情况。
3,如果新来的中断类型与当前正在执行的中断类型相同,那么会暂时挂起。主要实现代码在函数__do_IRQ()(handle_fasteoi_irq()、handle_edge_irq()类似)内:
/*
* If the IRQ is disabled for whatever reason, we cannot
* use the action we have.
*/
action = NULL;
if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS)))) {
action = desc->action;
status &= ~IRQ_PENDING; /* we commit to handling */
status |= IRQ_INPROGRESS; /* we are handling it */
}
desc->status = status;
/*
* If there is no IRQ handler or it was disabled, exit early.
* Since we set PENDING, if another processor is handling
* a different instance of this same irq, the other processor
* will take care of it.
*/
if (unlikely(!action))
goto out;
逻辑很简单,如果当前中断被禁止(IRQ_DISABLED)或正在执行(IRQ_INPROGRESS),那么goto cot,所以同种类型中断不会相互嵌套。
4,从这个补丁开始,Linux内核已经全面禁止硬中断嵌套了,即从2.6.35开始,默认就是:
run the irq handlers with interrupts disabled.
因为这个补丁,所以旗标IRQF_DISABLED没用了,mainline内核在逐步删除它。
我仔细检查了一下,对于2.6.34以及以前的内核,如果要合入这个补丁,那么有略微影响的主要是两个慢速驱动,分别为rtc-twl4030和twl4030-usb,需要按照类似开启Lockdep功能一样:
#ifdef CONFIG_LOCKDEP
/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
* we don't want and can't tolerate. Although it might be
* friendlier not to borrow this thread context...
*/
local_irq_enable();
#endif
进行主动启用中断。还有另个一个慢速驱动IDE,其驱动中调用的是函数local_irq_enable_in_hardirq(),即它在开启Lockdep功能的情况下并没有明确要求启用中断,所以它应该不受补丁合入影响。嘛,我只是理论分析研究一下,仅供参考,如有风险,请实际操作者自行承担,:)。其它请看参考4,5,6。
1,Linux下386中断处理
2,Linux中断基础构架
3,linux源码entry_32.S中interrupt数组的分析
4,http://lwn.net/Articles/321663/
5,http://lwn.net/Articles/380931/
6,http://thread.gmane.org/gmane.linux.kernel/801267
转载请保留地址:http://www.lenky.info/archives/2013/03/2245 或 http://lenky.info/?p=2245
Posted by kk
Recommend
-
47
嗨 各位小伙伴好,好久没有写文章了,这次分享一下我们从使用node以来,前端架构上的一些优化 如果看过我上一篇文章B站的前端之路的小伙伴可能知道 我们从去年开始打烊 使用node 到现在已经经历了一年的迭代,承载的访问量也从百万级别 扩大到了现在的亿级别,这次...
-
44
-
48
本文将向大家介绍如何在AIX和Power架构上运行Metasploit框架,这对于那些想要尝试在这些架构上运行Metasploit的人可能会有所帮助(至少目前我还没有在网上发现关于这方面的教程内容)。
-
12
几个月前发过一篇文章讨论技术思路,接着上次的讨论继续。 iGuo:新一阶段的技术尝试 zhuanlan.zhihu.com ...
-
16
...
-
5
采访嘉宾 | 张雷、高飞“内容社区”已经成为小红书最被外界认可的“标签”,...
-
3
MVC三层架构 我们在刚刚成为程序员的时候,就会被前辈们 “教育” 说系统的设计要遵循 MVC(Model-View-Controller)架构。它将整体的系统分成了 Model(模型),View(视图)和 Controller(控制器)三个层次,也就是将用户视图和业务处理隔离开,并且...
-
9
搭建一个通用监控告警平台,架构上需要有哪些设计 ...
-
13
传Navi 31的GCD尺寸约为350mm²,AMD或在RDNA 3架构上删除了部分功能模块
-
3
探索aarch64架构上使用ftrace的BPF LSM 笔者在MacBook M2上搭建Linux虚拟机上开发eBPF程序时,遇到一些LSM eBPF类型程序无法运行的问题。 在笔者尝试定位这些差异时,看到这篇文章,可以让大家更直观地了解LSM eBPF在...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK