2011年02月08日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2010/2011-02-08
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/

図? x86 の Intel 8259

図? x86 の APIC
APIC は、次のような割り込み信号を受け取る。
$ 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
$
例:
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)
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: }
...
790: }
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);
264:
265: spin_unlock(&rtc_lock);
266:
267: /* Now do the rest of the actions */
268: spin_lock(&rtc_task_lock);
269: if (rtc_callback)
270: rtc_callback->func(rtc_callback->private_data);
271: spin_unlock(&rtc_task_lock);
272: wake_up_interruptible(&rtc_wait);
273:
274: kill_fasync(&rtc_async_queue, SIGIO, POLL_IN);
275:
276: return IRQ_HANDLED;
277: }
プロセス・コンテキストでできること。
割り込みコンテキストでは、このうようなことはできない。 速やかに終了すべきである。busy loop はできるが、あまり やらない方がよい。他の割り込みは、実行される可能性もある。
arch/x86/include/asm/irq_vectors.h
131: #define NR_VECTORS 256
arch/x86/kernel/traps.c
78: gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, };
...
837: void __init trap_init(void)
838: {
...
849: set_intr_gate(0, ÷_error);
850: set_intr_gate_ist(2, &nmi, NMI_STACK);
...
896: set_system_trap_gate(SYSCALL_VECTOR, &system_call);
897: set_bit(SYSCALL_VECTOR, used_vectors);
arch/x86/include/asm/irq_vectors.h:
50: # define SYSCALL_VECTOR 0x80
kernel/irq/handle.c
368: irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
369: {
370: irqreturn_t ret, retval = IRQ_NONE;
371: unsigned int status = 0;
372:
373: do {
...
375: ret = action->handler(irq, action->dev_id);
...
378: switch (ret) {
...
410: case IRQ_HANDLED:
411: status |= action->flags;
412: break;
413:
414: default:
415: break;
416: }
417:
418: retval |= ret;
419: action = action->next;
420: } while (action);
421:
422: if (status & IRQF_SAMPLE_RANDOM)
423: add_interrupt_randomness(irq);
424: local_irq_disable();
425:
426: return retval;
427: }
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);
// 割り込みハンドラの終了を待つ。