2012年02月07日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2011/2012-02-07
あるいは、次のページから手繰っていくこともできます。
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.1.3/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);
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: }
linux-3.1.3/arch/x86/include/asm/irq_vectors.h
arch/x86/include/asm/irq_vectors.h
133: #define NR_VECTORS 256
linux-3.1.3/arch/x86/kernel/traps.c
78: gate_desc idt_table[NR_VECTORS] __page_aligned_data = { { { { 0, 0 } } }, };
824: void __init trap_init(void)
825: {
...
836: set_intr_gate(0, ÷_error);
837: set_intr_gate_ist(2, &nmi, NMI_STACK);
...
871: set_system_trap_gate(SYSCALL_VECTOR, &system_call);
...
linux-3.1.3/arch/x86/include/asm/irq_vectors.h
51: # define SYSCALL_VECTOR 0x80
linux-3.1.3/kernel/irq/handle.c
167: irqreturn_t handle_irq_event(struct irq_desc *desc)
168: {
169: struct irqaction *action = desc->action;
170: irqreturn_t ret;
171:
172: desc->istate &= ~IRQS_PENDING;
173: irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
174: raw_spin_unlock(&desc->lock);
175:
176: ret = handle_irq_event_percpu(desc, action);
177:
178: raw_spin_lock(&desc->lock);
179: irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
180: return ret;
181: }
linux-3.1.3/kernel/irq/handle.c
116: irqreturn_t
117: handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
118: {
119: irqreturn_t retval = IRQ_NONE;
120: unsigned int random = 0, irq = desc->irq_data.irq;
121:
122: do {
123: irqreturn_t res;
...
126: res = action->handler(irq, action->dev_id);
...
133: switch (res) {
...
147: case IRQ_HANDLED:
148: random |= action->flags;
149: break;
150:
151: default:
152: break;
153: }
154:
155: retval |= res;
156: action = action->next;
157: } while (action);
...
164: return retval;
165: }
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);
// 割り込みハンドラの終了を待つ。