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