IRQ VECTOR DEVICE COMMENT 0 32 Timer Never use 1 33 Keybord Never use 2 34 PIC cascading Never use 3 35 Serial Port#2 known ISA uses 4 36 Serial Port#1 known ISA uses 5 37 (Parallel Port#2) 6 38 Floppy Disk known ISA uses 7 39 Parallel Port#1 known ISA uses 8 40 RTC(Real-Time Clock) 9 41 - 10 42 - 11 43 - 12 44 PS/2 mouse known ISA uses 13 45 fpu Avoid using 14 46 EIDE disk cont. #1 Avoid using 15 47 EIDE disk cont. #2 Avoid using
2.4.0(init/main.c) asmlinkage void __init start_kernel(void) { char * command_line; unsigned long mempages; extern char saved_command_line[]; /* * Interrupts are still disabled. Do necessary setups, then * enable them */ lock_kernel(); printk(linux_banner); setup_arch(&command_line); printk("Kernel command line: %s\n", saved_command_line); parse_options(command_line); trap_init(); init_IRQ(); <=== sched_init(); time_init(); softirq_init(); ... --------------------------------------------------------------------- 2.4.0(arch/i386/kernel/i8259.c) void __init init_IRQ(void) { int i; ... /* * 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_IRQS; i++) { int vector = FIRST_EXTERNAL_VECTOR + i; if (vector != SYSCALL_VECTOR) set_intr_gate(vector, interrupt[i]); } ... --------------------------------------------------------------------- 2.4.0(arch/i386/kernel/traps.c) ... #define _set_gate(gate_addr,type,dpl,addr) \ do { \ int __d0, __d1; \ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ "movw %4,%%dx\n\t" \ "movl %%eax,%0\n\t" \ "movl %%edx,%1" \ :"=m" (*((long *) (gate_addr))), \ "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \ } while (0) ... void set_intr_gate(unsigned int n, void *addr) { _set_gate(idt_table+n,14,0,addr); } ...
2.2.14 (arch/i386/kernel/irq.h) typedef struct { unsigned int status; /* IRQ status-IRQ_INPROGRESS,IRQ_DISABLED */ struct hw_interrupt_type *handler;/* handle/enable/disable functions */ struct irqaction *action; /* IRQ action list */ unsigned int depth; /* Disable depth for nested irq disables */ unsigned int unused[4]; } irq_desc_t; --------------------------------------------------------------------- 2.4.0 (include/linux/irq.h) ... typedef struct { unsigned int status; /* IRQ status */ hw_irq_controller *handler; struct irqaction *action; /* IRQ action list */ unsigned int depth; /* nested irq disables */ spinlock_t lock; } ____cacheline_aligned irq_desc_t; extern irq_desc_t irq_desc [NR_IRQS]; ... struct hw_interrupt_type { const char * typename; unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq); void (*ack)(unsigned int irq); void (*end)(unsigned int irq); void (*set_affinity)(unsigned int irq, unsigned long mask); }; typedef struct hw_interrupt_type hw_irq_controller; ... --------------------------------------------------------------------- 2.4.0 (arch/i386/kernel/i8259.c) static struct hw_interrupt_type i8259A_irq_type = { "XT-PIC", startup_8259A_irq, shutdown_8259A_irq, enable_8259A_irq, disable_8259A_irq, mask_and_ack_8259A, end_8259A_irq, NULL };
2.4.0 (include/asm/hw_irq.h) #define BUILD_IRQ(nr) \ asmlinkage void IRQ_NAME(nr); \ __asm__( \ "\n"__ALIGN_STR"\n" \ SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \ "pushl $"#nr"-256\n\t" \ "jmp common_interrupt"); #define BUILD_COMMON_IRQ() \ __asm__( \ "\n" __ALIGN_STR"\n" \ "common_interrupt:\n\t" \ SAVE_ALL \ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \ "jmp ret_from_intr\n");
2.4.0 (include/asm/hw_irq.h) ... #define SAVE_ALL \ "cld\n\t" \ "pushl %es\n\t" \ "pushl %ds\n\t" \ "pushl %eax\n\t" \ "pushl %ebp\n\t" \ "pushl %edi\n\t" \ "pushl %esi\n\t" \ "pushl %edx\n\t" \ "pushl %ecx\n\t" \ "pushl %ebx\n\t" \ "movl $" STR(__KERNEL_DS) ",%edx\n\t" \ "movl %edx,%ds\n\t" \ "movl %edx,%es\n\t" ...
2.4.0 (arch/i386/kernel/i8259.c) BUILD_COMMON_IRQ( ) #define BI(x,y) \ BUILD_IRQ(x##y) #define BUILD_16_IRQS(x) \ BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ BI(x,c) BI(x,d) BI(x,e) BI(x,f) ... #define IRQ(x,y) \ IRQ##x##y##_interrupt #define IRQLIST_16(x) \ IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) void (*interrupt[NR_IRQS])(void) = { IRQLIST_16(0x0), #ifdef CONFIG_X86_IO_APIC IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3), IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), IRQLIST_16(0xc), IRQLIST_16(0xd) #endif }; ...---------------------------------------------------------------------
2.4.0 (arch/i386/kernel/irq.c) /* * do_IRQ handles all normal device IRQ's (the special * SMP cross-CPU interrupts have their own specific * handlers). */ asmlinkage unsigned int do_IRQ(struct pt_regs regs) { ... int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; unsigned int status; kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); /* mask_and_ack_8259A() */ /* REPLAY is when Linux resends an IRQ that was dropped earlier WAITING is used by probe to mark irqs that are being tested */ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); status |= IRQ_PENDING; /* we _want_ to handle it */ /* * If the IRQ is disabled for whatever reason, we cannot * use the action we have. */ action = NULL; if (!(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 (!action) goto out; ... for (;;) { spin_unlock(&desc->lock); handle_IRQ_event(irq, ®s, action); spin_lock(&desc->lock); if (!(desc->status & IRQ_PENDING)) break; desc->status &= ~IRQ_PENDING; } desc->status &= ~IRQ_INPROGRESS; out: /* * The ->end() handler has to deal with interrupts which got * disabled while the handler was running. */ desc->handler->end(irq); /* enable_8259A_irq(irq) */ spin_unlock(&desc->lock); if (softirq_active(cpu) & softirq_mask(cpu)) do_softirq(); return 1; } --------------------------------------------------------------------- int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { int status; int cpu = smp_processor_id(); irq_enter(cpu, irq); status = 1; /* Force the "do bottom halves" bit */ 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(); irq_exit(cpu, irq); return status; }
2.4.0 enum { HI_SOFTIRQ=0, /* 汎用的なハンドラ登録のメカニズム。2.2 タスクキュー機能の改良版。*/ NET_TX_SOFTIRQ, /* TCP/IP プロトコルスタックの送信処理 */ NET_RX_SOFTIRQ, /* TCP/IP プロトコルスタックの受信処理 */ TASKLET_SOFTIRQ /* 構造は TASKLET_SOFTIRQ と同じ。TASKLET_SOFTIRQ より優先。BH ハンドラのみ利用している */ };以下のような構造体が用意されている。
struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; };
open_softirq(): /* 指定したソフトウエア割り込みレベルにハンドラを登録する */ __cpu_raise_softirq():/* 指定したレベルのソフトウエア割り込みを発生要求する */ do_softirq(): /* ソフトウエア割り込みレベルに対応したハンドラを起動する */ tasklet_schedule(): /* TASKLET_SOFTIRQ レベルにハンドラを登録する */ tasklet_hi_schedule():/* HI_SOFTIRQ レベルにハンドラを登録する */ tasklet_action(): /* TASKLET_SOFTIRQ レベルに登録されたハンドラ群を全て実行する */ tasklet_hi_action(): /* HI_SOFTIRQ レベルに登録されたハンドラ群を全て実行する */
2.4.0 struct tq_struct { struct list_head list; /* linked list of active bh's */ unsigned long sync; /* must be initialized to zero */ void (*routine)(void *); /* function to call */ void *data; /* argument to function */ }; typedef struct list_head task_queue; #define DECLARE_TASK_QUEUE(q) LIST_HEAD(q) extern task_queue tq_timer, tq_immediate, tq_disk; 2.2.14 struct tq_struct { struct tq_struct *next; /* linked list of active bh's */ unsigned long sync; /* must be initialized to zero */ void (*routine)(void *); /* function to call */ void *data; /* argument to function */ }; typedef struct tq_struct * task_queue; #define DECLARE_TASK_QUEUE(q) task_queue q = NULL extern task_queue tq_timer, tq_immediate, tq_scheduler, tq_disk;タスクキューには以下の種類がある。
2.4.0 2.2.14 enum { enum { TIMER_BH = 0, TIMER_BH = 0, TQUEUE_BH, CONSOLE_BH, DIGI_BH, TQUEUE_BH, SERIAL_BH, DIGI_BH, RISCOM8_BH, SERIAL_BH, SPECIALIX_BH, RISCOM8_BH, AURORA_BH, SPECIALIX_BH, ESP_BH, AURORA_BH, SCSI_BH, ESP_BH, IMMEDIATE_BH, NET_BH, CYCLADES_BH, SCSI_BH, CM206_BH, IMMEDIATE_BH, JS_BH, KEYBOARD_BH, MACSERIAL_BH, CYCLADES_BH, ISICOM_BH CM206_BH, }; JS_BH, MACSERIAL_BH, ISICOM_BH };BHハンドラで使用する関数
2.4.0 /* mark_bh():指定した番号のBHハンドラの起動要求を行なう。2.4 ではBH ハンドラ関数は HI_SOFTIRQ レベルのソフトウエア割り込みとして登録される*/ static inline void mark_bh(int nr) { tasklet_hi_schedule(bh_task_vec+nr); } /* bh_action():BH ハンドラを実行する. 2.2 以前との互換性のため BH ハンドラ実行中は 他の BH ハンドラが動作できないように禁止フラグを立てる */ static void bh_action(unsigned long nr) { int cpu = smp_processor_id(); if (!spin_trylock(&global_bh_lock)) goto resched; if (!hardirq_trylock(cpu)) goto resched_unlock; if (bh_base[nr]) bh_base[nr](); hardirq_endlock(cpu); spin_unlock(&global_bh_lock); return; resched_unlock: spin_unlock(&global_bh_lock); resched: mark_bh(nr); } /* init_bh():指定した番号のBHハンドラを登録する */ void init_bh(int nr, void (*routine)(void)) { bh_base[nr] = routine; mb(); } /* remove_bh():指定した番号のBHハンドラを登録を削除する */ void remove_bh(int nr) { tasklet_kill(bh_task_vec+nr); bh_base[nr] = NULL; } 2.2.14 /* mark_bh():指定した番号のBHハンドラの起動要求を行なう */ extern inline void mark_bh(int nr) { set_bit(nr, &bh_active); } /* init_bh():指定した番号のBHハンドラを登録する */ extern inline void init_bh(int nr, void (*routine)(void)) { unsigned long flags; bh_base[nr] = routine; atomic_set(&bh_mask_count[nr], 0); spin_lock_irqsave(&i386_bh_lock, flags); bh_mask |= 1 << nr; spin_unlock_irqrestore(&i386_bh_lock, flags); } /* remove_bh():指定した番号のBHハンドラを登録を削除する */ extern inline void remove_bh(int nr) { unsigned long flags; spin_lock_irqsave(&i386_bh_lock, flags); bh_mask &= ~(1 << nr); spin_unlock_irqrestore(&i386_bh_lock, flags); synchronize_bh(); bh_base[nr] = NULL; }