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);
// 割り込みハンドラの終了を待つ。