割り込み

					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 PIC

8259、8259、CPU

図? x86 の Intel 8259

◆APIC

Local APIC、Core、I/O APIC

図? x86 の APIC

APIC は、次のような割り込み信号を受け取る。

◆/proc/interrupts

/proc/interrupts は、割り込みの回数を保持している。
$ 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
$ []

◆例外

例外(exceptions) とは、ハードウェア・デバイスとは無関係に、 CPU の命令実行の途中で生じる。例 多くの CPU アーキテクチャでは、例外を割り込みと同じように扱う。 x86 では、システム・コールの処理も、割り込みと同じように扱う。

◆割り込みハンドラ

割り込みハンドラ(interrupt handlers)とは、割り込みが生じた時にそれに応 答するために実行される関数。割り込みサービスルー単(interrupt service routine, ISR)とも呼ばれる。

例:

Linux では、割り込みハンドラは、C言語の関数。普通の関数との違い。

◆割り込みの前半部分と後半部分

次の2つを両立させたい Linux では、これを両立するために、割り込みの処理を2つに分ける。 例: ネットワークカードによるメッセージの受信

◆割り込み番号の共有

1つの割り込み番号を、複数のデバイスで共有することがある。

◆request_irq()

Linux で、割り込みの前半部を登録するには、request_irq() を使う。 CPUアーキテクチャに独立した形で割り込みハンドラを登録するには、 request_irq() を用いる。
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)
主なフラグ
IRQF_DISABLED
割り込みハンドラの実行中、「全ての」割り込みを禁止する。 このフラグがセットされていなければ、自分自身だけ禁止され、 他の割り込みは許可された状態で動作する。
IRQF_SAMPLE_RANDOM
乱数生成器のために割り込みを利用してもよい。
IRQF_TIMER
システム・タイマのために利用する。
IRQF_SHARED
複数のデバイスで同じ割り込み線を共有できる。

◆free_irq()

割り込みハンドラが不要になった時には、free_irq() で取り除く。
void free_irq(unsigned int, void *dev)

◆irq_handler_t handler

割り込みハンドラは、次のような関数である。
irqreturn_t irq_handler_t(int irq, void *dev)
IRQ_NONE
割り込みは、自分自身のものではなかった。
IRQ_HANDLED
割り込みをきちんと処理した。
全割り込みハンドラが IRQ_NONE を返せば、なんらかのトラブルを意味する。 複数の割り込みハンドラが IRQ_HANDLED を返すことは正常。

◆x86 CMOS Real-Time Clock rtc_interrupt()

x86 CMOS Real-Time Clock での割り込みハンドラの例。
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 はできるが、あまり やらない方がよい。他の割り込みは、実行される可能性もある。

◆x86 Interrupt Descriptor Table (IDT)

x86 IDT は、ハードウェア・レベルの割り込みハンドラの一覧表を保持する。 その先頭番地は、IDTR レジスタに保存される。
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, &divide_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

◆do_IRQ

x86 Linux では、Interrupt Descriptor Table に従い、do_IRQ() が呼ばれる。 引数には、x86 のレジスタを表現した構造体へのポインタが渡される。これに より、割り込みが発生した時のレジスタの値がわかる。割り込みハンドラが有 効で、割り込み線に登録されていれば、最終的には、handle_IRQ_event() と いう、CPU とは独立の割り込みハンドラが呼ばれる。

◆handle_IRQ_event()

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

■クイズ7 割り込み

★問題(701) 割り込みの利用

コンピューで、キーボード、マウス、ネットワーク・カード等のデバイスから の入力では割り込みが多く使われている。割り込みを使う方法と割り込みを使 わない方法を対比して、割り込みを使う方法の利点を説明しなさい。

★問題(702) x86 CMOS Real-Time Clock の割り込みハンドラ

x86 CMOS Real-Time Clock の割り込みハンドラを関数名で答えなさい。 その関数の引数と結果を、簡単に説明しなさい。

★問題(703) x86 CMOS Real-Time Clock の割り込みハンドラの呼び出し

今日の資料の中で、x86 CMOS Real-Time Clock の割り込みハンドラを呼び出し ていると思われる関数と行数を答えなさい。
Last updated: 2011/02/07 23:07:21
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>