3.3. start_kernel() ÇÔ¼ö¿¡¼­ÀÇ IDT ÀÇ ÃʱâÈ­

start_kernel() ÇÔ¼ö´Â ¸î°¡Áö ÃʱâÈ­¸¦ ÇÏ°í, trap_init() ÇÔ¼ö¿Í init_IRQ() ÇÔ¼ö¸¦ Â÷·Ê·Î È£ÃâÇؼ­ ÇÁ·Î¼¼¼­ÀÇ IDT ¿¡ trap gate ¿Í interrupt gate ¸¦ ÃʱâÈ­½ÃŲ´Ù. start_kernel() ÇÔ¼ö´Â /usr/src/linux/init/main.c ¿¡ ÀÖ´Ù.

3.3.1. trap_init() ÇÔ¼ö

trap_init() ÇÔ¼ö´Â ´ÙÀ½°ú °°´Ù :

---------------------------------------
/usr/src/linux/arch/i386/kernel/traps.c
---------------------------------------
void __init trap_init(void)
{
	set_trap_gate(0,&divide_error);
	set_trap_gate(1,&debug);
	set_intr_gate(2,&nmi);
	set_system_gate(3,&int3);	/* int3-5 can be called from all */
	set_system_gate(4,&overflow);
	set_system_gate(5,&bounds);
	set_trap_gate(6,&invalid_op);
	set_trap_gate(7,&device_not_available);
	set_trap_gate(8,&double_fault);
	set_trap_gate(9,&coprocessor_segment_overrun);
	set_trap_gate(10,&invalid_TSS);
	set_trap_gate(11,&segment_not_present);
	set_trap_gate(12,&stack_segment);
	set_trap_gate(13,&general_protection);
	set_intr_gate(14,&page_fault);
	set_trap_gate(15,&spurious_interrupt_bug);
	set_trap_gate(16,&coprocessor_error);
	set_trap_gate(17,&alignment_check);
	set_trap_gate(18,&machine_check);
	set_trap_gate(19,&simd_coprocessor_error);

	set_system_gate(SYSCALL_VECTOR,&system_call);
		:
		:	
}
¿©±â ³ª¿À´Â set_xxxx_gate() ÇÔ¼ö´Â ¸ðµÎ ´ÙÀ½°ú °°Àº _set_gate() ¸ÅÅ©·Î·Î ¸ÅÇεȴ٠:
---------------------------------------
/usr/src/linux/arch/i386/kernel/traps.c
---------------------------------------
#define _set_gate(gate_addr,type,dpl,addr) \
do { \
  int __d0, __d1; \
  __asm__ __volatile__ ( \
	"movw %%dx,%%ax  \n\t" \
	"movw %4,%%dx    \n\t" \
	"movl %%eax,%0   \n\t" \
	"movl %%edx,%1" \
	:"=m" (*((long *) (gate_addr))), \
	 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
	 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
} while (0)

¶ÇÇÑ, set_trap_gate(), set_system_gate(), set_intr_gate() µîÀÇ ÇÔ¼ö´Â ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :

---------------------------------------
/usr/src/linux/arch/i386/kernel/traps.c
---------------------------------------
void set_intr_gate(unsigned int n, void *addr)
{
	_set_gate(idt_table+n,14,0,addr);
}

static void __init set_trap_gate(unsigned int n, void *addr)
{
	_set_gate(idt_table+n,15,0,addr);
}

static void __init set_system_gate(unsigned int n, void *addr)
{
	_set_gate(idt_table+n,15,3,addr);
}

static void __init set_call_gate(void *a, void *addr)
{
	_set_gate(a,12,3,addr);
}
ÀÌÁ¦ trap_init() ÇÔ¼ö¿¡¼­ Á¤ÀÇÇÏ´Â °ÔÀÌÆ®µé Áß set_intr_gate(14,&page_fault); ¸¦ ¼±ÅÃÇؼ­ ¾î¶»°Ô È®ÀåÀÌ µÇ¸ç, ¾î¶°ÇÑ °á°ú¸¦ ³º°Ô µÇ´ÂÁö »ý°¢ÇØ º¸°Ú´Ù. ÀÌ ¶óÀÎÀº ´ÙÀ½°ú °°ÀÌ È®ÀåµÈ´Ù : (ÆíÀÇ»ó ÅÇ(\t) °ú °³Ç๮ÀÚ(\n), Çà°è¼ÓÇ¥½Ã(\), µû¿ÈÇ¥ ÀϺδ »ý·«ÇÏ°Ú´Ù)
_set_gate(idt_table+14, 14, 0, page_fault);
-------------------------------------------
#define _set_gate(gate_addr,type,dpl,addr)
do {
  int __d0, __d1;
  __asm__ __volatile__ (
	movw %%dx,%%ax
	movw %4,%%dx
	movl %%eax,%0
	movl %%edx,%1
	:"=m" (*((long *) (gate_addr))),
	 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1)
	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))),
	 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16));
} while (0)

À§ÀÇ ¾î¼Àºí¸® ¸í·ÉµéÀ» ÀÚ¼¼È÷ º¸¸é, ¸ÕÀú, Ãâ·ÂºÎ¿¡ gate_addr ¹øÁö¿Í, gate_addr+1 ¹øÁö¸¦ ÁöÁ¤ÇØ µÎ°í ÀÖ´Ù. ÀÌ°ÍÀº, ¿¹¿Ü»óȲ 14¹ø, Áï, ÆäÀÌÁö ÆúÆ® ¿¹¿Ü»óȲÀÇ °æ¿ì, 14¹ø° °ÔÀÌÆ®À̹ǷÎ, idt_table+14 ÀÇ À§Ä¡ÀÌ´Ù. ±×¸®°í, ÀÌ°ÍÀº ¸Þ¸ð¸® ¿ÀÆÛ·£µåÀ̹ǷΠ"=m" À» »ç¿ëÇÏ¿´´Ù.

±×¸®°í, "=&a" (__d0) ¿Í "=&d" (__d1) À» ÀÌ¿ëÇؼ­ eax ·¹Áö½ºÅÍ¿Í edx ·¹Áö½ºÅ͸¦ °¢°¢ %2 ¿Í %3 ¿¡ early clobber ·Î ÇÒ´çÇß´Ù. early clobber ¿É¼Ç(&)À¸·Î ÇÒ´çÇßÀ¸¹Ç·Î, ÀԷºο¡ ³ª¿À´Â "2" ¿Í "3" ÀÇ °ªÀÌ ¾î¼Àºí¸® ÀνºÆ®·°¼ÇµéÀÌ Çؼ®µÇ±â Àü¿¡ ÇÒ´çµÇ¾î µé¾î°£´Ù. Áï, eax ·¹Áö½ºÅÍ¿¡ (__KERNEL_CS << 16) ÀÇ °ªÀÌ, edx ¿¡ ((char *)(addr)) ÀÇ °ª, Áï, ÀÎÅÍ·´Æ® °ÔÀÌÆ®¿¡ ÀúÀåµÇ´Â Çڵ鷯ÀÇ ÄÚµå ¼¼±×¸ÕÆ®¿¡¼­ÀÇ ¿ÀÇÁ¼ÂÀÇ °ªÀÌ ÀúÀåµÈ´Ù.

±×¸®°í¼­, movw %%dx, %%ax ¸¦ ¼öÇàÇÑ´Ù. ±×·¸°Ô Çϸé, ´ÙÀ½ ±×¸²°ú °°ÀÌ edx ·¹Áö½ºÅÍÀÇ ÇÏÀ§ 16ºñÆ®°¡ eax ·¹Áö½ºÅÍÀÇ ÇÏÀ§ 16ºñÆ®·Î º¹»çµÇ°Ô µÈ´Ù. [1]

그림 3-1. Making Interrupt Gate 1

±×¸®°í, movw %4, %%dx ¿¡ ÀÇÇؼ­ 4¹ø° ¿ÀÆÛ·£µå, Áï, ((short)(0x8000+(dpl<<13)+(type<<8))) ÀÌ dx ·¹Áö½ºÅÍ¿¡ º¹»çµÇ´Âµ¥, ÀÎÅÍ·´Æ® °ÔÀÌÆ®ÀÇ °æ¿ì, dpl Àº 0, type Àº 14 À̹ǷÎ, º¹»çµÇ´Â °ªÀº, 0x8e00 ÀÌ µÈ´Ù. ±×·¯¸é, eax ¿Í edx ÀÇ °ªÀº ´ÙÀ½ ±×¸²°ú °°´Ù :

그림 3-2. Making Interrupt Gate 2

±×¸®°í ³ª¼­, eax ·¹Áö½ºÅÍÀÇ °ªÀº gate_addr ¹øÁö¿¡, edx °ªÀº gate_addr+1 ¹øÁö¿¡ °¢°¢ ÀúÀåÇÏ°Ô µÇ´Âµ¥, ÀÌ°ÍÀ» ÀÎÅÚ¿¡¼­ Á¦°øÇÏ´Â ¸Å´º¾óÀÇ ÀÎÅÍ·´Æ® °ÔÀÌÆ® µð½ºÅ©¸³ÅÍ¿Í ºñ±³ÇØ º¸µµ·Ï ÇÏÀÚ. ÀÎÅÚ ÇÁ·Î¼¼¼­µéÀÇ interrupt gate descriptor ´Â ´ÙÀ½°ú °°Àº ±¸Á¶¸¦ °¡Áø´Ù :

그림 3-3. Interrupt gate descriptor

±×¸²¿¡¼­, P ´Â segment present flag À̸ç, dpl Àº descriptor privilege level, D ´Â °ÔÀÌÆ®ÀÇ »çÀÌÁ °áÁ¤ÇÏ´Â °ÍÀ¸·Î½á, 1 À̸é, 32ºñÆ®, 0 À̸é 16ºñÆ®ÀÌ´Ù. ¾Õ¼­ ¼³¸íÇÑ eax ¿Í edx ¸¦ °¢°¢ ÇØ´çÇÏ´Â °÷¿¡ ³Ö¾î¼­ ºñ±³ÇØ º¸¸é, Á¤È®È÷ __KERNEL_CS ¼¼±×¸ÕÆ®ÀÇ (¿ì¸®°¡ »ìÆ캸´Â °ÍÀÌ 14¹ø, ÆäÀÌÁö ÆúÆ®, Çڵ鷯 : page_fault) page_fault ·¹À̺í(ÁÖ¼Ò)ÀÌ ÇØ´ç Çʵ忡 µé¾î°¡°Ô µÇ°í, dpl Àº 0,Áï, Ä¿³Î ·¹º§ÀÇ ±ÇÇÑÀ» °¡Áö¸ç, °ÔÀÌÆ®ÀÇ Å¸ÀÔÀ» °áÁ¤ÇÏ´Â 8-12¹ø ºñÆ®´Â 01110 À¸·Î½á, D=1, Áï 32ºñÆ® °ÔÀÌÆ®¿¡, ÀÎÅÍ·´Æ® °ÔÀÌÆ®ÀÇ Å¸ÀÔ°ú ÀÏÄ¡ÇÏ°Ô µÈ´Ù.

³ª¸ÓÁö set_system_gate(), set_trap_gate(), set_call_gate() ¿Í °°Àº ÇÔ¼öµéµµ, ÀÌ¿Í ¸¶Âù°¡Áö·Î ÀûÀýÇÏ°Ô °ÔÀÌÆ® µð½ºÅ©¸³Å͸¦ ÁöÁ¤µÈ ¹øÁö (ù¹ø° Àμö) ¿¡ ¸¸µé¾î¼­ ³Ö¾î ÁÖ°Ô µÈ´Ù.

ÀÌÁ¦, ´Ù½Ã trap_init() ÇÔ¼ö·Î µ¹¾Æ°¡¼­ ¼Ò½ºÄڵ带 »ìÆ캸°Ú´Ù.

ÇÔ¼ö¿¡¼­´Â 0 - 19 ¹ø±îÁöÀÇ idt ¿£Æ®¸®¿¡ °¢°¢ ƯÁ¤ ÇÔ¼öÀÇ ÁÖ¼Ò¸¦ ³Ö´Â ½ÄÀ¸·Î idt ¿£Æ®¸®µéÀ» ÃʱâÈ­ ½ÃŲ´Ù. ±× ÇÔ¼öµéÀº ¸ðµÎ /usr/src/linux/arch/i386/kernel/entry.S ¿¡ Á¤ÀÇµÈ ¾î¼Àºí¸® ÇÔ¼öµé·Î½á, ÀÎÅÚ ÇÁ·Î¼¼¼­¿¡¼­ Á¤ÀÇÇÏ´Â 0 - 19¹ø±îÁöÀÇ ¹Ì¸® ¿¹¾àµÈ ¿¹¿Ü»óȲ ¹× ÀÎÅÍ·´Æ® ¿¡ ´ëÇÑ Çڵ鷯¸¦ ±¸ÇöÇÏ°í ÀÖ´Ù.

±×µé Áß ÁÖ¸ñÇØ¾ß ÇÒ ºÎºÐÀº, 14¹ø page fault ¿¹¿Ü»óȲ¿¡ ´ëÇÑ Çڵ鷯·Î½á, ÀÌ Çڵ鷯´Â, ¸®´ª½º ÆäÀÌ¡ ½Ã½ºÅÛ¿¡¼­ ¸Å¿ì Áß¿äÇÑ ¿ªÇÒÀ» ÇÑ´Ù.

¶Ç ÇÑ°¡Áö, SYSCALL_VECTOR ¶ó°í Á¤ÀÇµÈ »ó¼ö, Áï 0x80 ¹ø° idt ¿£Æ®¸®´Â Ư¼öÇÑ ¿£Æ®¸®·Î½á, ¸®´ª½º¿¡¼­ system call À» ±¸ÇöÇÒ ¶§ »ç¿ëÇÏ´Â ¿¹¿Ü»óȲ Çڵ鷯ÀÎ system_call À» °¡¸®Å°°í ÀÖ´Â °ÍÀ» º¼ ¼ö ÀÖ´Ù. Áï, ¸®´ª½ºÀÇ ½Ã½ºÅÛ ÄÝÀº int 80 ÀνºÆ®·°¼ÇÀ» ÀÌ¿ëÇÏ¿© ±¸ÇöµÈ´Ù´Â °ÍÀ» ¾Ë ¼ö ÀÖ´Ù.

3.3.2. init_IRQ() ÇÔ¼ö

¾Õ Àý¿¡¼­ 0-0x19 ¹ø »çÀÌÀÇ idt Å×À̺íÀ» ÃʱâÈ­ ½ÃÅ°´Â Ä¿³ÎÀÇ ·çƾµéÀ» »ìÆì º¸¾Ò´Ù. ±×·¯¸é, ³ª¸ÓÁö idt Å×À̺íÀº ¾î¶»°Ô ÃʱâÈ­½ÃÅ°´Â°¡? ±×ºÎºÐÀ» »ìÆ캸µµ·Ï ÇÏÀÚ.

ÀÌ ÇÔ¼ö´Â, ÀÎÅÚÀÌ ¿¹¾àÇصР0 - 0x19 ¹ø »çÀÌÀÇ idt ÀÌÈÄÀÇ ºÎºÐµé¿¡ ´ëÇÑ ÀÎÅÍ·´Æ® ¼­ºñ½º ·çƾÀ» Á¤ÀÇÇØ ÁÖ´Â ºÎºÐÀÌ´Ù. 0x20 ¹ø ºÎÅÍ ¸ÅÇÎÀ» Çϴµ¥(¼Ò½º´Â º¸ÀÌÁö ¾Ê°Ú´Ù. ÀÌ ÇÔ¼ö´Â /usr/src/linux/arch/i386/i8259.c ¿¡ ÀÖ´Ù.) 0x20 ¹ø idt ¿£Æ®¸®ºÎÅÍ irq0 ¹øÀ¸·Î ÇÒ´çÇؼ­ (idt entry 0x20 : irq0, idt entry 0x21 : irq1 ÀÌ·±½ÄÀ¸·Î) °¢°¢ IRQ0xNN_interrupt() À¸·Î ¸ÅÇνÃÄÑ ÁØ´Ù.

3.3.2.1. 8259A and I/O APIC

ÀÎÅÚÀÇ ÇÁ·Î¼¼¼­µé¿¡´Â ¿ÜºÎ ÀÎÅÍ·´Æ® ½Ã±×³ÎÀ» ¹Þ¾ÆµéÀ̱â À§ÇØ ÁغñµÈ ÇɵéÀÌ ÀÖ´Ù(´Ù¸¥ ÇÁ·Î¼¼¼­µµ ¸¶Âù°¡Áö´Ù -¤µ-) ƯÈ÷ P6 Æйи®¿¡´Â LINT0 LINT1 À̶ó´Â ÇÉ°ú INTR, NMI ÇÉÀÇ µÎ°¡Áö°¡ Á¸ÀçÇϴµ¥, LINT[1:0] ÇÉÀº ÇÁ·Î¼¼¼­ ³»ºÎÀÇ local APIC(Advanced Programmable Interrupt Controller) °ú ¿¬°áµÇ¾î ÀÖ´Ù. ÀÌ ÇɵéÀº, ÇÁ·Î¼¼¼­¿¡¼­ local APIC ÀÌ disable µÇ¾úÀ» °æ¿ì, °¢°¢ INTR °ú NMI ÇÉÀ¸·Î½á µ¿ÀÛÇÑ´Ù. ÀϹÝÀûÀ¸·Î, APIC °¡ »ç¿ëµÇ´Â °æ¿ì´Â SMP (Symmetic Multi Processor, ´ëĪÇü ´ÙÁß ÇÁ·Î¼¼¼­) ½Ã½ºÅÛ¿¡¼­ ¿ÜºÎÀÇ I/O APIC ÄÁÆ®·Ñ·¯¿Í ÇÔ²² »ç¿ëµÇ¾îÁ®¼­ ÇÁ·Î¼¼¼­ °£ÀÇ Åë½Å µî¿¡ »ç¿ëµÈ´Ù. ¸¸¾à single processor ½Ã½ºÅÛ¿¡¼­ »ç¿ëµÈ´Ù¸é, ¿ÜºÎ ÀÎÅÍ·´Æ® ÄÁÆ®·Ñ »Ó¸¸ ¾Æ´Ï¶ó ÇÁ·Î¼¼¼­ ÀÚüÀÇ Å¸À̸Ó, performance counter µî°ú °°Àº ÀÎÅÍ·´Æ®, ¶ÇÇÑ, Non Maskable Interrupt Watchdog °°Àº ÀÎÅÍ·´Æ®µµ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï ÇØ ÁØ´Ù.

ÀÌ ¹®¼­¿¡¼­´Â single processor ½Ã½ºÅÛ¿¡¼­ ¿ÜºÎ ÀÎÅÍ·´Æ® ÄÁÆ®·Ñ·¯·Î 8259A ¸¦ »ç¿ëÇÏ°í ÀÖ´Â »óȲÀ» ¿¹·Î µé°Ú´Ù. APIC ½Ã½ºÅÛ¿¡ ´ëÇؼ­´Â multiprocessor ½Ã½ºÅÛ°ú ¹ÐÁ¢ÇÑ °ü·ÃÀÌ Àֱ⠶§¹®¿¡ ´Ù·çÁö ¾Ê°Ú´Ù.

¿ì¼±, 8259A ÄÁÆ®·Ñ·¯¿¡ ´ëÇؼ­ ¾Ë¾Æº¸µµ·Ï ÇÏ°Ú´Ù.

8259A/82C59A-2 ÄÁÆ®·Ñ·¯µéÀº IR0 - IR7 ±îÁöÀÇ 8 °³ÀÇ ÀÎÅÍ·´Æ® ÇÉÀ» °¡Áö°í ÀÖ´Ù. I/O ÀåÄ¡µéÀÌ cpu ÀÇ Ã³¸®°¡ ÇÊ¿äÇÒ ¶§¿¡´Â ÀÌ Çɵé Áß Çϳª¿¡ ½Ã±×³ÎÀ» º¸³½´Ù. ±×·¯¸é, 8259 ÄÁÆ®·Ñ·¯´Â ÀÚ½ÅÀÇ INT ÇÉÀ» activate ½ÃÅ°´Âµ¥, ÀÌ ÇÉÀº CPU ÀÇ INTR ¶óÀο¡ ¿¬°áµÇ¾î ÀÖ´Ù. INTR ¶óÀÎÀÌ active µÇ¸é, CPU ´Â ½ÇÇàÇÏ´ø instruction ÀÇ ¼öÇàÀ» ¿Ï·áÇÏ°í, 8259 ÀÇ INTA ¶óÀο¡ INTR ½ÅÈ£¸¦ ¹Þ¾Ò´Ù´Â ¶æÀ¸·Î (acknowledge) ½ÅÈ£¸¦ ÇØ ÁØ´Ù. ÀÚ½ÅÀÇ INTA ¶óÀο¡ CPU ¿¡¼­ ÁØ ½ÅÈ£¸¦ ¹ÞÀº 8259 ÄÁÆ®·Ñ·¯´Â ÀڽŰú ¿¬°áµÇ¾î ÀÖ´Â µ¥ÀÌÅÍ ¹ö½º¿¡ ÀÎÅÍ·´Æ® ¼­ºñ½º ·çƾÀÇ ÁÖ¼Ò (8-bit) ¸¦ ½Ç¾î ÁØ´Ù. CPU ÀÇ Á¾·ù¿¡ µû¶ó¼­ ÀÌó·³ µ¥ÀÌÅÍ ¹ö½º(D0 - D7) ¿¡ µ¥ÀÌÅ͸¦ ½Ç¾îÁÖ´Â phase °¡ µÎ¹ø ȤÀº Çѹø ÀϾ ¼ö ÀÖ´Ù. ±×·¯¸é, CPU ´Â µ¥ÀÌÅ͹ö½º¿¡ ½Ç¸° ³»¿ëÀ» Àо interrupt type number ¸¦ °áÁ¤ÇÏ°í, ÇØ´çµÇ´Â ÀÎÅÍ·´Æ® ¼­ºñ½º ·çƾ(ISR) À» ½ÇÇà½ÃŲ´Ù.

ÀϹÝÀûÀ¸·Î ¿ì¸®°¡ »ç¿ëÇÏ´Â ibm pc ¿¡¼­´Â 8259 Ĩ µÎ°³¸¦ cascade ½ÃÄѼ­ ÃÑ 15 °³ÀÇ IRQ ¶óÀÎÀ» »ç¿ëÇÏ°Ô µÈ´Ù. IRQ ¶óÀÎ Áß Çϳª´Â µÎ°³ÀÇ ÄÁÆ®·Ñ·¯¸¦ ¼­·Î cascade ÇÒ ¶§¿¡ »ç¿ëÇÑ´Ù. µÎ°³ÀÇ 8259 ÄÁÆ®·Ñ·¯´Â ´ÙÀ½ ±×¸²°ú °°ÀÌ cascade Çؼ­ »ç¿ëÇÒ ¼ö ÀÖ´Ù : (±×¸²¿¡¼± ¼¼°³¸¦ cascade ½ÃŲ °æ¿ì¸¦ º¸¿´´Âµ¥, ¿©±â¼­ Çϳª¸¸ »èÁ¦ÇÑ »óÅ·ΠÀÌÇØÇϱ⠹ٶõ´Ù)

그림 3-4. cascaded 8259A [2]

ÀÌó·³ cascade µÇ¾úÀ» °æ¿ì, slave ÀÇ INT ¶óÀÎÀÌ master ÀÇ IRQ ¶óÀÎ Áß Çϳª·Î µé¾î°¡°Ô µÈ´Ù.

ÀÌó·³ 8259 ÀÇ IRQ ¶óÀο¡ ½ÅÈ£°¡ µé¾î¿À°í¼­, CPU ¿¡¼­ INT ½ÅÈ£¸¦ 8259°¡ ¹ÞÀº ÈÄ, µ¥ÀÌÅÍ ¹ö½º¿¡ ½Ç¾î ÁÖ´Â ³»¿ë°ú, ±×°ÍÀ» CPU °¡ ¾î¶»°Ô Çؼ®Çؼ­ µ¿ÀÛÇϴ°¡¿¡ ´ëÇÑ ³»¿ëÀº, ÀڷḦ ÀÚ¼¼È÷ ÀоÁö ¾Ê¾Æ¼­ Àß ¸ð¸£°Ú½À´Ï´Ù. Ȥ½Ã ¾Æ½Ã´Â ºÐ²²¼­´Â, ȤÀº, °ü½ÉÀÌ À־ Àú ´ë½Å Á¶»çÇϽŠºÐµé²²¼­´Â Á¦°Ô °¡¸£Ä§À» ÁÖ½Ã¸é °¨»çÇÏ°Ú½À´Ï´Ù. :) ¾Æ¸¶µµ, ¾î´À³¯¿£°¡ Á¦°¡ ¿©À¯°¡ »ý±â¸é Á¶»çÇØ º¸°ÚÁö¸¸, ¾ðÁ¦°¡ µÉÁö´Â Àå´ãÇϱ⠾î·Æ±º¿ä :(

3.3.2.2. init_IRQ() ÇÔ¼ö

ÀÌÁ¦, IRQ n ¿¡ ÇØ´çÇÏ´Â º¤Å͵é°ú ¼­ºñ½º ·çƾµéÀ» ÃʱâÈ­ ½ÃÅ°´Â ÇÔ¼öÀÎ init_IRQ() ÇÔ¼ö·Î µé¾î°¡ º¸µµ·Ï ÇÏ°Ú´Ù.

ù ´Ü°è·Î, init_IRQ() ÇÔ¼ö¸¦ ¸®½ºÆ®ÇØ º¸µµ·Ï ÇÏ°Ú´Ù :

----------------------------------------------------------
/usr/src/linux/arch/i386/kernel/i8259.c
----------------------------------------------------------
void __init init_IRQ(void)
{
	int i;

#ifndef CONFIG_X86_VISWS_APIC
	init_ISA_irqs();
#else
	init_VISWS_APIC_irqs();
#endif
	/*
	 * Cover the whole vector space, no vector can escape
	 * us. (some of these will be overridden and become
	 * 'special' SMP interrupts)
	 */
	for (i = 0; i < NR_IRQS; i++) {
		int vector = FIRST_EXTERNAL_VECTOR + i;
		if (vector != SYSCALL_VECTOR) 
			set_intr_gate(vector, interrupt[i]);
	}
		:
		:
¿©±â¿¡ ³ª¿À´Â set_intr_gate() ÇÔ¼ö´Â ¾Õ¼­ ¼³¸íÇß´ø, set_trap_gate() ÇÔ¼ö¿Í ÀÎÀÚ°ª¸¸ ´Þ¸®ÇÏ¿©¼­ _set_gate() ÇÔ¼ö¸¦ ÄÝÇÏ´Â ¸ÅÅ©·Î·Î Á¤ÀǵǾî ÀÖ´Ù. ±×·¯¸é, ¾î¶²°ªÀÌ interrupt descriptor table ¿¡ µé¾î°¡°Ô µÇ´ÂÁö ¾Õ¿¡¼­ ¼³¸íÇÏ¿´´Ù.

¿ì¼±, ÀÎÅÚ ¾ÆÅ°ÅØó¿¡¼­ÀÇ ÀÎÅÍ·´Æ®´Â 0x00 - 0x1f ±îÁö 32°³ÀÇ ÀÎÅÍ·´Æ®´Â ÇÁ·Î¼¼¼­°¡ ¿ëµµ¸¦ ¹Ì¸® ÁöÁ¤ÇØµÎ°í¼­ »ç¿ëÇÏ°Ô µÇ¾î ÀÖ´Ù´Â »ç½ÇÀ» ÁÖÁöÇØ¾ß ÇÑ´Ù. ±×·¯¸é, ºñ¾îÀÖ´Â ÃÖÃÊÀÇ º¤ÅÍÀÎ 0x20 ¹ø º¤ÅͷκÎÅÍ´Â ¿ÜºÎ ÀÎÅÍ·´Æ®, Áï, ÇÁ·Î¼¼¼­ÀÇ INTR ÇÉÀ¸·ÎºÎÅÍ signalling µÇ´Â ÀÎÅÍ·´Æ®µé, Áï, ¿ÜºÎ ÀÎÅÍ·´Æ® ¸®Äù½ºÆ® ¶óÀÎÀ¸·ÎºÎÅÍÀÇ ÀÎÅÍ·´Æ®¸¦ ó¸®ÇÏ´Â º¤ÅÍ°¡ µé¾î°¡°Ô µÈ´Ù. Áï, IRQ(Interrupt ReQuest Line) 0 ¹øÀº, ÇÁ·Î¼¼¼­ÀÇ ÀÎÅÍ·´Æ® °ÔÀÌÆ® 20¹ø° ¿£Æ®¸®¿¡¼­ Á¤ÀÇÇÏ´Â º¤ÅÍ¿¡¼­ ó¸®ÇÏ°Ô µÇ´Â °ÍÀÌ´Ù.

±×·³, ´Ù½Ã ÇÔ¼ö·Î µ¹¾Æ°¡¼­ ³»¿ëÀ» Çϳª¾¿ »ìÆ캸µµ·Ï ÇÏÀÚ. NR_IRQS °ª¸¸Å­ ·çÇÁ¸¦ µ¹¸é¼­ FIRST_EXTERNAL_VECTOR ¹ø° °ÔÀÌÆ®·ÎºÎÅÍ Çϳª¾¿ interrupt[] ¹è¿­¿¡ Á¤ÀÇµÈ ÇÔ¼ö Æ÷ÀÎÅ͸¦ º¤ÅÍ·Î ÇÒ´çÇÏ°í ÀÖ´Ù. Àü¿ªº¯¼ö interrupt ´Â °°Àº ÆÄÀÏ¿¡ ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :

----------------------------------------------------------
/usr/src/linux/arch/i386/kernel/i8259.c
----------------------------------------------------------
#define IRQ(x,y) \
	IRQ##x##y##_interrupt

#define IRQLIST_16(x) \
	IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
	IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
	IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
	IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)

void (*interrupt[NR_IRQS])(void) = {
	IRQLIST_16(0x0),

#ifdef CONFIG_X86_IO_APIC
			 IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
	IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
	IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
	IRQLIST_16(0xc), IRQLIST_16(0xd)
#endif
};
¿©±â¼­ °¢°¢ÀÇ #define ¸ÅÅ©·Î¸¦ expand ½ÃÅ°´Â °Í±îÁö´Â À̾߱âÇÏÁö ¾Ê°Ú´Ù. °á°ú¸¸ À̾߱âÇÏÀÚ¸é, interrupt[] ¹è¿­ÀÇ °¢ ¿£Æ®¸®´Â °¢°¢ IRQ0xNN_interrupt() ¶ó´Â ¾î¼Àºí¸® ÇÔ¼ö(·¹À̺í)¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ·Î ±¸¼ºµÇ°Ô µÈ´Ù.

´Ù½ÃÇѹø ¼Ò½º¸¦ Àо °Ú´Ù. (CONFIG_X86_VISWS_APIC ¿É¼ÇÀº, SGI Visual Workstation À» ¼±ÅÃÇßÀ» ¶§¸¸ »ý±â´Â ¿É¼ÇÀÌ´Ù. Áö±Ý x86 À» ´Ù·ç°í ÀÖÀ¸¹Ç·Î ¹«½ÃÇÏ°í ³Ñ¾î°¡ÀÚ) ¿ì¼±, init_ISA_irqs() ÇÔ¼ö¿¡¼­´Â ´ÙÀ½°ú °°ÀÌ ³ªÁß¿¡ ½ÇÁ¦ ÀÎÅÍ·´Æ® Çڵ鸵½Ã¿¡ »ç¿ëÇÒ irq_desc[] ¹è¿­À» ÃʱâÈ­ ÇÑ´Ù :

----------------------------------------------------------
/usr/src/linux/arch/i386/kernel/i8259.c
----------------------------------------------------------
void __init init_ISA_irqs (void)
{
	int i;

	init_8259A(0);

	for (i = 0; i < NR_IRQS; i++) {
		irq_desc[i].status = IRQ_DISABLED;
		irq_desc[i].action = 0;
		irq_desc[i].depth = 1;

		if (i < 16) {
			/*
			 * 16 old-style INTA-cycle interrupts:
			 */
			irq_desc[i].handler = &i8259A_irq_type;
		} else {
			/*
			 * 'high' PCI IRQs filled in on demand
			 */
			irq_desc[i].handler = &no_irq_type;
		}
	}
}
ÀÌ ÇÔ¼ö¿¡¼­´Â irq_desc[] ¹è¿­ÀÇ ÃʱâÈ­¸¦ Çϴµ¥, irq_desc[] ¹è¿­¿¡ °üÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀº ³ªÁß¿¡ À̾߱âÇϵµ·Ï ÇÏ°í, ÀÏ´Ü, °£´ÜÇÑ »çÇ׸¸ À̾߱âÇÏ°í ³Ñ¾î°¡°Ú´Ù. irq_desc[] ¹è¿­Àº ´ÙÀ½°ú °°ÀÌ ¼±¾ðµÇ¾î ÀÖ´Ù :
----------------------------------------------------------
/usr/src/linux/include/linux/interrupt.h
----------------------------------------------------------
struct irqaction {
	void (*handler)(int, void *, struct pt_regs *);
	unsigned long flags;
	unsigned long mask;
	const char *name;
	void *dev_id;
	struct irqaction *next;
};

----------------------------------------------------------
/usr/src/linux/include/linux/irq.h
----------------------------------------------------------
/*
 * Interrupt controller descriptor. This is all we need
 * to describe about the low-level hardware. 
 */
struct hw_interrupt_type {
	const char * typename;
	unsigned int (*startup)(unsigned int irq);
	void (*shutdown)(unsigned int irq);
	void (*enable)(unsigned int irq);
	void (*disable)(unsigned int irq);
	void (*ack)(unsigned int irq);
	void (*end)(unsigned int irq);
	void (*set_affinity)(unsigned int irq, unsigned long mask);
};

typedef struct hw_interrupt_type  hw_irq_controller;

/*
 * This is the "IRQ descriptor", which contains various information
 * about the irq, including what kind of hardware handling it has,
 * whether it is disabled etc etc.
 *
 * Pad this out to 32 bytes for cache and indexing reasons.
 */
typedef struct {
	unsigned int status;		/* IRQ status */
	hw_irq_controller *handler;
	struct irqaction *action;	/* IRQ action list */
	unsigned int depth;		/* nested irq disables */
	spinlock_t lock;
} ____cacheline_aligned irq_desc_t;

extern irq_desc_t irq_desc [NR_IRQS];
ÀÌ ±¸Á¶Ã¼ ¹è¿­Àº °¢°¢ÀÇ irq ¶óÀÎÀÇ »óÅ¿¡ °üÇÑ Á¤º¸¿Í ±×¿¡ µû¸¥ Çڵ鷯µéÀÇ Æ÷ÀÎÅ͸¦ °¡Áö°í ÀÖ°Ô µÈ´Ù. ÃÖÃÊ¿¡´Â, init_ISA_irqs() ÇÔ¼ö¿¡¼­ º¸À̵íÀÌ, status ¿¡ IRQ_DISABLED ¶ó´Â °ªÀ» ³Ö°í, 0 - 15 ¹øÀÇ ¿ø¼ÒÀÇ handler °ªÀº ¸ðµÎ i8259A_irq_type À» °¡¸®Å°´Â Æ÷ÀÎÅÍ·Î ÃʱâÈ­µÈ´Ù. i8259A_irq_type Àº ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :
----------------------------------------------------------
/usr/src/linux/arch/i386/kernel/i8259.c
----------------------------------------------------------

static struct hw_interrupt_type i8259A_irq_type = {
	"XT-PIC",
	startup_8259A_irq,
	shutdown_8259A_irq,
	enable_8259A_irq,
	disable_8259A_irq,
	mask_and_ack_8259A,
	end_8259A_irq,
	NULL
};
ÀÚ¼¼ÇÑ °ÍÀº µÚ¿¡¼­ ´Ù·ç±â·Î ÇÏ°í, ´Ù½Ã init_IRQ() ÇÔ¼ö·Î µ¹¾Æ°¡ÀÚ.

¾Õ¼­ À̾߱âÇÑ °Íó·³ IDT ÀÇ °¢°¢ÀÇ ¿ø¼ÒÀÇ º¤Å͸¦ IRQ0xNN_interrupt() ·¹À̺íÀ» °¡¸®Å°µµ·Ï ¼³Á¤ÇÏ°í, ¸®ÅÏÇÑ´Ù. IRQ0xNN_interrupt() ·¹À̺íÀº ¾î¶»°Ô Á¤ÀǵǾî ÀÖ´ÂÁö µû¶ó°¡ º¸°Ú´Ù. i8259.c ÆÄÀÏÀÇ Ã¹ºÎºÐ¿¡ º¸¸é ´ÙÀ½°ú °°Àº ¸ÅÅ©·Î°¡ Á¤ÀǵǾî ÀÖ´Ù :

----------------------------------------------------------
/usr/src/linux/arch/i386/kernel/i8259.c
----------------------------------------------------------
/*
 * Common place to define all x86 IRQ vectors
 *
 * This builds up the IRQ handler stubs using some ugly macros in irq.h
 *
 * These macros create the low-level assembly IRQ routines that save
 * register context and call do_IRQ(). do_IRQ() then does all the
 * operations that are needed to keep the AT (or SMP IOAPIC)
 * interrupt-controller happy.
 */

BUILD_COMMON_IRQ()

#define BI(x,y) \
	BUILD_IRQ(x##y)

#define BUILD_16_IRQS(x) \
	BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
	BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
	BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
	BI(x,c) BI(x,d) BI(x,e) BI(x,f)

/*
 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
 * (these are usually mapped to vectors 0x20-0x2f)
 */
BUILD_16_IRQS(0x0)
óÀ½ ³ª¿À´Â BUILD_COMMON_IRQ() ¸ÅÅ©·Î´Â ´ÙÀ½Ã³·³ Á¤ÀǵǾî ÀÖ´Ù :
----------------------------------------------------------
/usr/src/linux/include/asm-i386/hw_irq.h
----------------------------------------------------------

#define BUILD_COMMON_IRQ() \
asmlinkage void call_do_IRQ(void); \
__asm__( \
	"\n" __ALIGN_STR"\n" \
	"common_interrupt:\n\t" \
	SAVE_ALL \
	"pushl $ret_from_intr\n\t" \
	SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
	"jmp "SYMBOL_NAME_STR(do_IRQ));

주석

[1]

gcc ÀÇ ÀζóÀÎ ¾î¼Àºí¸®¿¡ ´ëÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀº, ÀÌÈ£¾¾ÀÇ Assembly Example, ÇãÅÂÁؾ¾ÀÇ GCC Inline Assembly, ±×¸®°í, º»ÀÎÀÌ ¹ø¿ªÇÑ Assembly Howto ¸¦ ÂüÁ¶Çϱ⠹ٶõ´Ù. ¸ðµÎ kldp¿¡¼­ ±¸ÇÒ ¼ö ÀÖ´Ù. ±×¸®°í, ¹æ±Ý ¾ð±ÞÇÑ ¹®¼­µé¿¡¼­ ¼³¸íÇÏÁö ¾Ê´Â gcc inline assembly ÀÇ modifier ¿¡ °üÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀº gcc ¸Å´º¾ó¿¡¼­ º¼ ¼ö ÀÖ´Ù : http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_16.html#SEC175

[2]

ÀÎÅÚÀÇ ¹®¼­¿¡¼­ Çã¶ô¾øÀÌ ÀüÁ¦ÇßÀ½