do_IRQ

do_IRQ->__do_IRQ->handle_IRQ_event。

do_IRQ 模型:
  1. unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
  2. {
  3.         ...
  4.         irq_enter();

  5.         //handle external interrupt (ISR)
  6.         ...
  7.         irq_exit();

  8.         return 1;
  9. }
do_IRQ()中调用irq_enter函数可以看做hardirq 部分的开始,而irq_exit函数的调用则标志着softirq部分的开始。


1, 因为C的调用惯例是要把函数参数放在栈的顶部,因此pt_regs结构包含原始寄存器的值,这些值是以前在汇编入口例程中保存在栈上的(SAVE_ALL)。中断的值也会得以保存,所以,do_IRQ()可以将它提取出来,X86的代码为:

int irq = regs->orig_eax & 0xff;

pt_regs:

当中断发生时,CPU将寄存器的EFLAGS的内容,以及代表返回地址的CS和EIP两个寄存器的内容压入堆栈。如果CPU的运行级别发生变化,则在此之前还要发生堆栈的切换,并且要把代表老堆栈指针的SS和ESP的内容压入堆栈。
以上这些都是CPU自动完成的动作,之后内核代码会将(中断号-256)压入系统堆栈,紧接着调用SAVE_ALL将中断发生时ES、DS、EAX、EBP、EDI、ESI、EDX、ECX和EBX寄存器中的值依次压入系统堆栈。完成这些操作之后的系统堆栈如下图所示:



从图中不难发现实际上这些宏定义的值就是各个寄存器的内容在系统堆栈中相对栈顶指针的偏移量。
上面这个图是针对中断的,对于异常ORIG_EAX偏移处存放的是错误码(如果有的话),而对于系统调用则是存放着系统调用号。

2,真正的中断处理:__do_IRQ





3, handle_IRQ_event,处理中断线上的服务程序


__do_IRQ中的加锁,使得能同步更新IRQ状态、action。

IRQ_DISABLED:  相应的IRQ被禁用.既然中断线被禁用了,也就不会产生中断,进入do_IRQ()了?因为电子器件的各种原因可能会产生 “伪中断”上报给CPU.
IRQ_PENDING:  CPU收到这个中断信号了,已经给出了应答,但并末对其进行处理.回顾上面的代码,进入do_IRQ后,发送ack,再设置此标志.
IRQ_ INPROGRESS:  表示这条IRQ线的中断正在被处理.为了不弄脏CPU的高速缓存.把相同IRQ线的中断放在一起处理可以提高效率,且使中断处理程序不必重入。

举例说明:如果CPU A接收到一个中断信号.回一个ACK,设置c,假设此时末有这个中断线的中断处理程序在处理,继而会将标志位设为IRQ_ INPROGRESS.转去中断处理函数执行.如果此时,CPU B检测到了这条IRQ线的中断信号.它会回一个ACK.设置IRQ_PENDING.但时此时这条IRQ线的标志为IRQ_ INPROGRESS.所以,它会进经过goto out退出.如果cpu A执行完了中断处理程序,判断它的标志线是否为IRQ_PENDING.因为CPU B已将其设为了IRQ_PENDING.所以继续循环一次.直到循环完后,清除IRQ_INPROGRESS标志。


为什么要在handle_IRQ_event最后关闭中断(local_irq_disable)?
First, because the processor disabled interrupts, they are turned back on unless SA_INTERRUPT was specified during the handler's registration. Recall that SA_INTERRUPT specifies that the handler must be run with interrupts disabled. Next, each potential handler is executed in a loop. If this line is not shared, the loop terminates after the first iteration. Otherwise, all handlers are executed. After that, add_interrupt_randomness() is called if SA_SAMPLE_RANDOM was specified during registration. This function uses the timing of the interrupt to generate entropy for the random number generator. Appendix B, "Kernel Random Number Generator," has more information on the kernel's random number generator. Finally, interrupts are again disabled (do_IRQ() expects them still to be off) and the function returns. Back in do_IRQ(), the function cleans up and returns to the initial entry point, which then jumps to ret_from_intr().

在中断返回时,将会进行退栈清理性的工作,如果此时响应中断,不确定后果是什么。然后恢复标志。

4, 从do_IRQ函数返回后,将执行 ret_from_intr(linux-2.6.11.12\arch\i386\kernel\entry.S  
ret_from_intr 恢复寄存器,将内核恢复到中断前的状态。

5,应答:ack与end
          desc->handler->ack(irq); // 会把当前中断线在所有处理器上都屏蔽(在ack中完成屏蔽 )
          desc->handler->end(irq);



### 回答1: 这是一个IT类问题。这个说法是不准确的。do_bottom_half()和do_irq()都是Linux内核中的函数,但它们的作用不同。do_irq()是一个中断处理程序,用于处理硬件中断。而do_bottom_half()是一个软中断处理程序,用于处理软中断。软中断是由内核自己产生的中断,而不是由硬件设备触发的中断。 ### 回答2: do_bottom_half()和do_irq()是Linux内核中的两个函数。 do_irq()是处理中断的函数,它负责接收和处理硬件设备产生的中断信号。当硬件设备发出中断请求时,处理器会暂停当前正在执行的任务,转而执行do_irq()函数来处理中断。do_irq()函数会根据中断类型进行相应的处理,例如保存寄存器状态、调用中断处理程序等。 而do_bottom_half()是do_irq()的一个子函数,它是处理中断处理程序中的底半部分。在处理中断时,由于中断处理程序需要尽快执行完成,因此可能会出现一些无法立即处理的操作。为了避免中断处理时间过长,Linux内核采用了底半部机制。底半部是指将一些需要延迟处理的任务放到中断处理程序之后,在适当的时机再去执行它们。而do_bottom_half()函数就是用来执行这些延迟任务的。 因此,可以说do_bottom_half()就是do_irq()函数的一部分,用来处理do_irq()的底半部分任务。通过将一些延迟任务放到底半部来处理,可以提高系统的中断响应速度和整体性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值