Interrupt

As the name suggests, interrupt signals provide a way to divert the processor to code outside the normal flow of control. When an interrupt signal arrives, the CPU must stop what it's currently doing and switch to a new activity; it does this by saving the current value of the program counter (i.e., the content of the eip and cs registers) in the Kernel Mode stack and by placing an address related to the interrupt type into the program counter.

 

There is a key difference between interrupt handling and process switching: the code executed by an interrupt or by an exception handler is not a process. Rather, it is a kernel control path that runs on behalf of the same process that was running when the interrupt occurred. As a kernel control path, the interrupt handler is lighter than a process (it has less context and requires less time to set up or tear down).

 

Each interrupt or exception is identified by a numberranging from to 255; for some unknown reason, Intel calls this 8-bit unsignednumber a vector. The vectorsof nonmaskable interrupts and exceptions are fixed, while those of maskableinterrupts can be altered by programming the Interrupt Controller.

 

Linux uses the following vectors:

• Vectors ranging from to 31 correspond toexceptions and nonmaskable interrupts.

• Vectors ranging from 32 to 47 are assigned tomaskable interrupts, that is, to interrupts caused by IRQs.

• The remaining vectors ranging from 48 to 255 may be used to identify software interrupts. Linux uses only one of them, namely the 128 or 0x80 vector,which it uses to implement system calls. When an int 0x80 Assembly instruction is executed by a process in User Mode, the CPU switches into Kernel Mode and starts executing the system_call( ) kernel function.

 

A system table called Interrupt Descriptor Table (IDT) associates each interrupt or exception vector with the address of the corresponding interrupt or exception handler. The IDT must be properly initialized before the kernel enables interrupts.

#define NR_IRQS	128

struct irqdesc {
	unsigned int	 nomask   : 1;		/* IRQ does not mask in IRQ   */
	unsigned int	 enabled  : 1;		/* IRQ is currently enabled   */
	unsigned int	 triggered: 1;		/* IRQ has occurred	      */
	unsigned int	 probing  : 1;		/* IRQ in use for a probe     */
	unsigned int	 probe_ok : 1;		/* IRQ can be used for probe  */
	unsigned int	 valid    : 1;		/* IRQ claimable	      */
	unsigned int	 unused   :26;
	void (*mask_ack)(unsigned int irq);	/* Mask and acknowledge IRQ   */
	void (*mask)(unsigned int irq);		/* Mask IRQ		      */
	void (*unmask)(unsigned int irq);	/* Unmask IRQ		      */
	struct irqaction *action;
	unsigned int	 unused2[3];
};

static struct irqdesc irq_desc[NR_IRQS];

/*
 * do_IRQ handles all normal device IRQ's
 */
asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
{
	struct irqdesc * desc = irq_desc + irq;
	struct irqaction * action;
	int status, cpu;

	spin_lock(&irq_controller_lock);
	desc->mask_ack(irq);
	spin_unlock(&irq_controller_lock);

	cpu = smp_processor_id();
	irq_enter(cpu, irq);
	kstat.irqs[cpu][irq]++;
	desc->triggered = 1;

	/* Return with this interrupt masked if no action */
	status = 0;
	action = desc->action;

	if (action) {
		if (desc->nomask) {
			spin_lock(&irq_controller_lock);
			desc->unmask(irq);
			spin_unlock(&irq_controller_lock);
		}

		if (!(action->flags & SA_INTERRUPT))
			__sti();

		do {
			status |= action->flags;
			action->handler(irq, action->dev_id, regs);
			action = action->next;
		} while (action);

		if (status & SA_SAMPLE_RANDOM)
			add_interrupt_randomness(irq);
		__cli();

		if (!desc->nomask && desc->enabled) {
			spin_lock(&irq_controller_lock);
			desc->unmask(irq);
			spin_unlock(&irq_controller_lock);
		}
	}

	irq_exit(cpu, irq);

	/*
	 * This should be conditional: we should really get
	 * a return code from the irq handler to tell us
	 * whether the handler wants us to do software bottom
	 * half handling or not..
	 *
	 * ** IMPORTANT NOTE: do_bottom_half() ENABLES IRQS!!! **
	 * **  WE MUST DISABLE THEM AGAIN, ELSE IDE DISKS GO   **
	 * **                       AWOL                       **
	 */
	if (1) {
		if (bh_active & bh_mask)
			do_bottom_half();
		__cli();
	}
}

bottom half  is a low-priority function, usually related to interrupt handling, that is waiting for the kernel to find a convenient moment to run it. Bottom halves that arewaiting will be executed only when one of the following events occurs:

• The kernel finisheshandling a system call.

• The kernel finisheshandling an exception.

• The kernelterminates the do_IRQ( ) function—thatis, it finishes handling an interrupt.

• The kernel executes the schedule( ) function to select anew process to run on the CPU.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值