編號 32-127 是硬體裝置的 I/O Interrupt,而編號 128 則是由 Linux 核心作為 System Call 之用
在 PC 架構中,有幾個裝置的中斷訊號必須分配到中斷控制器的固定 IRQ Line
如下圖的 IRQ 0、2 及 13
IRQ 欄位表示硬體的 IRQ Line,INT 欄位表示 Linux 核心使用的 IRQ Number
上述的 I/O Interrupt 及其處理函式被儲存於 Linux 核心的 irq_desc 陣列中
變數型態為 struct irq_desc (或 irq_desc_t),陣列大小為 NR_IRQS
定義於 kernel/irq/handle.c
irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
[0 ... NR_IRQS-1] = {
.handler = &no_irq_type,
.lock = SPIN_LOCK_UNLOCKED
}
};
定義於 include/linux/irq.h
typedef struct irq_desc {
hw_irq_controller *handler;
void *handler_data;
struct irqaction *action; /* IRQ action list */
unsigned int status; /* IRQ status */
unsigned int depth; /* nested irq disables */
unsigned int irq_count; /* For detecting broken interrupts */
unsigned int irqs_unhandled;
spinlock_t lock;
} ____cacheline_aligned irq_desc_t;
定義於 include/asm-i386/mach-default/irq_vectors_limits.h
#ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
# define NR_IRQ_VECTORS NR_IRQS
# else
# define NR_IRQ_VECTORS (32 * NR_CPUS)
# endif
#else
#define NR_IRQS 16
#define NR_IRQ_VECTORS NR_IRQS
#endif
以上可看出,若系統使用 APIC 來管理裝置中斷時,IRQ 的個數為 224 個,否則為 16 個
當系統初始化時,核心呼叫 init_IRQ() 函式將 irq_desc 陣列中的 status 欄位設定為 IRQ_DISABLED
並且呼叫 set_intr_gate() 函式設定 CPU 的 Interrupt Gate,這個動作就是設定中斷發生時的處理函式
定義於 arch/i386/kernel/i8259.c
void __init init_IRQ(void)
{
int i;
/* all the set up before the call gates are initialised */
pre_intr_init_hook();
/*
* Cover the whole vector space, no vector can escape
* us. (some of these will be overridden and become
* 'special' SMP interrupts)
*/
for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
int vector = FIRST_EXTERNAL_VECTOR + i;
if (i >= NR_IRQS)
break;
if (vector != SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]);
}
/* setup after call gates are initialised (usually add in
* the architecture specific gates)
*/
intr_init_hook();
/*
* Set the clock to HZ Hz, we already have a valid
* vector now:
*/
setup_pit_timer();
/*
* External FPU? Set up irq13 if so, for
* original braindamaged IBM FERR coupling.
*/
if (boot_cpu_data.hard_math && !cpu_has_fpu)
setup_irq(FPU_IRQ, &fpu_irq);
irq_ctx_init(smp_processor_id());
}
void __init init_ISA_irqs (void)
{
int i;
#ifdef CONFIG_X86_LOCAL_APIC
init_bsp_APIC();
#endif
init_8259A(0);
for (i = 0; i < NR_IRQS; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
if (i < 16) {
/*
* 16 old-style INTA-cycle interrupts:
*/
irq_desc[i].handler = &i8259A_irq_type;
} else {
/*
* 'high' PCI IRQs filled in on demand
*/
irq_desc[i].handler = &no_irq_type;
}
}
}
沒有留言:
張貼留言