2013年01月29日 情報科学類 オペレーティングシステム II 筑波大学 システム情報工学研究科 コンピュータサイエンス専攻, 電子・情報工学系 新城 靖 <yas@cs.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2012/2013-01-29
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
図? x86 の Intel 8259
図? x86 の APIC
APIC は、次のような割り込み信号を受け取る。例:
例:
図? 割り込み記述子テーブルと割り込みハンドラ
typedef void (*funcp_t)(void); funcp_t idt[256];
old_pc = pc; old_flags = flags;
n = 割り込みベクタ; handler = idt[n];
push old_pc; push old_flags; pc = handler; // (*handler)();ただし、単純な call 命令とは違い、スタック上にプログラムカウンタの他に、 プロセッサの状態を示すフラグ等も積む。
図? PICの線が不足した時の対応
include/linux/interrupt.h typedef irqreturn_t (*irq_handler_t)(int, void *); request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)
void free_irq(unsigned int, void *dev)
irqreturn_t irq_handler_t(int irq, void *dev)
$ cat /proc/interrupts
CPU0 CPU1
0: 4208761 38584 IO-APIC-edge timer
1: 0 3 IO-APIC-edge i8042
7: 0 0 IO-APIC-edge parport0
8: 1 2 IO-APIC-edge rtc
9: 0 0 IO-APIC-level acpi
12: 3 1 IO-APIC-edge i8042
50: 5380 86508 PCI-MSI ahci
74: 346 0 PCI-MSI HDA Intel
98: 294 28232 PCI-MSI eth1
169: 130 57006 IO-APIC-level uhci_hcd:usb3
177: 0 0 IO-APIC-level uhci_hcd:usb4, uhci_hcd:usb7
217: 358 149530 IO-APIC-level ehci_hcd:usb1, uhci_hcd:usb5
225: 0 0 IO-APIC-level ehci_hcd:usb2, uhci_hcd:usb6
233: 0 0 IO-APIC-level uhci_hcd:usb8
NMI: 0 0
LOC: 4246864 4246863
ERR: 0
MIS: 0
$
linux-3.6.8/drivers/char/rtc.c 96: static unsigned long rtc_port; 97: static int rtc_irq; ... 191: static unsigned long rtc_status; /* bitmapped status byte. */ 192: static unsigned long rtc_freq; /* Current periodic IRQ rate */ 193: static unsigned long rtc_irq_data; /* our output to the world */ ... 953: static int __init rtc_init(void) 954: { ... 1000: if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", 1001: (void *)&rtc_port)) { 1002: rtc_has_irq = 0; 1003: printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); 1004: return -EIO; 1005: } ... 1137: } 239: static irqreturn_t rtc_interrupt(int irq, void *dev_id) 240: { ... 248: spin_lock(&rtc_lock); 249: rtc_irq_data += 0x100; 250: rtc_irq_data &= ~0xff; ... 259: rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); ... 262: if (rtc_status & RTC_TIMER_ON) 263: mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); ... 265: spin_unlock(&rtc_lock); ... 268: spin_lock(&rtc_task_lock); 269: if (rtc_callback) 270: rtc_callback->func(rtc_callback->private_data); 271: spin_unlock(&rtc_task_lock); ... 274: kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); 275: 276: return IRQ_HANDLED; 277: }
linux-3.6.8/arch/x86/include/asm/irq_vectors.h 51: # define SYSCALL_VECTOR 0x80 122: #define NR_VECTORS 256 linux-3.6.8/arch/x86/kernel/traps.c 78: gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, }; 677: void __init trap_init(void) 678: { ... 689: set_intr_gate(X86_TRAP_DE, ÷_error); 690: set_intr_gate_ist(X86_TRAP_NMI, &nmi, NMI_STACK); ... 724: set_system_trap_gate(SYSCALL_VECTOR, &system_call); ... 740: }
linux-3.6.8/kernel/irq/handle.c 182: irqreturn_t handle_irq_event(struct irq_desc *desc) 183: { 184: struct irqaction *action = desc->action; 185: irqreturn_t ret; 186: 187: desc->istate &= ~IRQS_PENDING; 188: irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); ... 191: ret = handle_irq_event_percpu(desc, action); ... 194: irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); 195: return ret; 196: }
linux-3.6.8/kernel/irq/handle.c 132: irqreturn_t 133: handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) 134: { 135: irqreturn_t retval = IRQ_NONE; 136: unsigned int flags = 0, irq = desc->irq_data.irq; 137: 138: do { 139: irqreturn_t res; ... 142: res = action->handler(irq, action->dev_id); ... 149: switch (res) { ... 163: case IRQ_HANDLED: 164: flags |= action->flags; 165: break; 167: default: 168: break; 169: } 171: retval |= res; 172: action = action->next; 173: } while (action); ... 179: return retval; 180: }
struct irqaction *action
は、
action->next
でリスト構造を作っている。
プロセス・コンテキストでできること。
割り込みコンテキストでは、このうようなことはできない。 速やかに終了すべきである。busy loop はできるが、あまり やらない方がよい。他の割り込みは、実行される可能性もある。
unsigned long flags; local_irq_save(flags); /* 割り込み禁止 */ ... local_irq_restore(flags); /* 割り込み許可 (save の時の状態にもどる) */単一CPUの x86 では、cli() と sti() で割り込みの禁止と許可を設定する方法 があった。それそれ同名の CPU の命令を実行して、全ての割り込みを禁止/許 可する。マルチプロセッサ(マルチコア含む)では、1つのCPU で割り込みを禁止 しても、他の CPU では許可されていることがあるので、cli()/sti() の方法は 使えない。
特定の割り込み番号の割り込みを禁止する方法もある。
void disable_irq(unsigned ing irq); // 全CPUの割り込みを禁止する void disable_irq_nosync(unsigned ing irq); // 同上。ただし、割り込みハンドラの終了を待たない。 void enable_irq(unsigned ing irq); // 割り込みを許可する。 void synchronize_irq(unsigned ing irq); // 割り込みハンドラの終了を待つ。