start_kernel() ÇÔ¼ö´Â ¸î°¡Áö Ãʱâȸ¦ ÇÏ°í, trap_init() ÇÔ¼ö¿Í init_IRQ() ÇÔ¼ö¸¦ Â÷·Ê·Î È£ÃâÇؼ ÇÁ·Î¼¼¼ÀÇ IDT ¿¡ trap gate ¿Í interrupt gate ¸¦ ÃʱâȽÃŲ´Ù. start_kernel() ÇÔ¼ö´Â /usr/src/linux/init/main.c ¿¡ ÀÖ´Ù.
trap_init() ÇÔ¼ö´Â ´ÙÀ½°ú °°´Ù :
¿©±â ³ª¿À´Â set_xxxx_gate() ÇÔ¼ö´Â ¸ðµÎ ´ÙÀ½°ú °°Àº _set_gate() ¸ÅÅ©·Î·Î ¸ÅÇεȴ٠:
--------------------------------------- /usr/src/linux/arch/i386/kernel/traps.c --------------------------------------- void __init trap_init(void) { set_trap_gate(0,÷_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); : : }
--------------------------------------- /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() µîÀÇ ÇÔ¼ö´Â ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :
ÀÌÁ¦ trap_init() ÇÔ¼ö¿¡¼ Á¤ÀÇÇÏ´Â °ÔÀÌÆ®µé Áß set_intr_gate(14,&page_fault); ¸¦ ¼±ÅÃÇؼ ¾î¶»°Ô È®ÀåÀÌ µÇ¸ç, ¾î¶°ÇÑ °á°ú¸¦ ³º°Ô µÇ´ÂÁö »ý°¢ÇØ º¸°Ú´Ù. ÀÌ ¶óÀÎÀº ´ÙÀ½°ú °°ÀÌ È®ÀåµÈ´Ù : (ÆíÀÇ»ó ÅÇ(\t) °ú °³Ç๮ÀÚ(\n), Çà°è¼ÓÇ¥½Ã(\), µû¿ÈÇ¥ ÀϺδ »ý·«ÇÏ°Ú´Ù)
--------------------------------------- /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); }
_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]
±×¸®°í, movw %4, %%dx ¿¡ ÀÇÇؼ 4¹ø° ¿ÀÆÛ·£µå, Áï, ((short)(0x8000+(dpl<<13)+(type<<8))) ÀÌ dx ·¹Áö½ºÅÍ¿¡ º¹»çµÇ´Âµ¥, ÀÎÅÍ·´Æ® °ÔÀÌÆ®ÀÇ °æ¿ì, dpl Àº 0, type Àº 14 À̹ǷÎ, º¹»çµÇ´Â °ªÀº, 0x8e00 ÀÌ µÈ´Ù. ±×·¯¸é, eax ¿Í edx ÀÇ °ªÀº ´ÙÀ½ ±×¸²°ú °°´Ù :
±×¸®°í ³ª¼, eax ·¹Áö½ºÅÍÀÇ °ªÀº gate_addr ¹øÁö¿¡, edx °ªÀº gate_addr+1 ¹øÁö¿¡ °¢°¢ ÀúÀåÇÏ°Ô µÇ´Âµ¥, ÀÌ°ÍÀ» ÀÎÅÚ¿¡¼ Á¦°øÇÏ´Â ¸Å´º¾óÀÇ ÀÎÅÍ·´Æ® °ÔÀÌÆ® µð½ºÅ©¸³ÅÍ¿Í ºñ±³ÇØ º¸µµ·Ï ÇÏÀÚ. ÀÎÅÚ ÇÁ·Î¼¼¼µéÀÇ 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 ÀνºÆ®·°¼ÇÀ» ÀÌ¿ëÇÏ¿© ±¸ÇöµÈ´Ù´Â °ÍÀ» ¾Ë ¼ö ÀÖ´Ù.
¾Õ Àý¿¡¼ 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() À¸·Î ¸ÅÇνÃÄÑ ÁØ´Ù.
ÀÎÅÚÀÇ ÇÁ·Î¼¼¼µé¿¡´Â ¿ÜºÎ ÀÎÅÍ·´Æ® ½Ã±×³ÎÀ» ¹Þ¾ÆµéÀ̱â À§ÇØ ÁغñµÈ ÇɵéÀÌ ÀÖ´Ù(´Ù¸¥ ÇÁ·Î¼¼¼µµ ¸¶Âù°¡Áö´Ù -¤µ-) ƯÈ÷ 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]
ÀÌó·³ 8259 ÀÇ IRQ ¶óÀο¡ ½ÅÈ£°¡ µé¾î¿À°í¼, CPU ¿¡¼ INT ½ÅÈ£¸¦ 8259°¡ ¹ÞÀº ÈÄ, µ¥ÀÌÅÍ ¹ö½º¿¡ ½Ç¾î ÁÖ´Â ³»¿ë°ú, ±×°ÍÀ» CPU °¡ ¾î¶»°Ô Çؼ®Çؼ µ¿ÀÛÇϴ°¡¿¡ ´ëÇÑ ³»¿ëÀº, ÀڷḦ ÀÚ¼¼È÷ ÀоÁö ¾Ê¾Æ¼ Àß ¸ð¸£°Ú½À´Ï´Ù. Ȥ½Ã ¾Æ½Ã´Â ºÐ²²¼´Â, ȤÀº, °ü½ÉÀÌ ÀÖ¾î¼ Àú ´ë½Å Á¶»çÇϽŠºÐµé²²¼´Â Á¦°Ô °¡¸£Ä§À» ÁÖ½Ã¸é °¨»çÇÏ°Ú½À´Ï´Ù. :) ¾Æ¸¶µµ, ¾î´À³¯¿£°¡ Á¦°¡ ¿©À¯°¡ »ý±â¸é Á¶»çÇØ º¸°ÚÁö¸¸, ¾ðÁ¦°¡ µÉÁö´Â Àå´ãÇϱ⠾î·Æ±º¿ä :(
ÀÌÁ¦, IRQ n ¿¡ ÇØ´çÇÏ´Â º¤Å͵é°ú ¼ºñ½º ·çƾµéÀ» ÃʱâÈ ½ÃÅ°´Â ÇÔ¼öÀÎ init_IRQ() ÇÔ¼ö·Î µé¾î°¡ º¸µµ·Ï ÇÏ°Ú´Ù.
ù ´Ü°è·Î, init_IRQ() ÇÔ¼ö¸¦ ¸®½ºÆ®ÇØ º¸µµ·Ï ÇÏ°Ú´Ù :
¿©±â¿¡ ³ª¿À´Â set_intr_gate() ÇÔ¼ö´Â ¾Õ¼ ¼³¸íÇß´ø, set_trap_gate() ÇÔ¼ö¿Í ÀÎÀÚ°ª¸¸ ´Þ¸®ÇÏ¿©¼ _set_gate() ÇÔ¼ö¸¦ ÄÝÇÏ´Â ¸ÅÅ©·Î·Î Á¤ÀǵǾî ÀÖ´Ù. ±×·¯¸é, ¾î¶²°ªÀÌ interrupt descriptor table ¿¡ µé¾î°¡°Ô µÇ´ÂÁö ¾Õ¿¡¼ ¼³¸íÇÏ¿´´Ù.
---------------------------------------------------------- /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]); } : :
¿ì¼±, ÀÎÅÚ ¾ÆÅ°ÅØó¿¡¼ÀÇ ÀÎÅÍ·´Æ®´Â 0x00 - 0x1f ±îÁö 32°³ÀÇ ÀÎÅÍ·´Æ®´Â ÇÁ·Î¼¼¼°¡ ¿ëµµ¸¦ ¹Ì¸® ÁöÁ¤ÇØµÎ°í¼ »ç¿ëÇÏ°Ô µÇ¾î ÀÖ´Ù´Â »ç½ÇÀ» ÁÖÁöÇØ¾ß ÇÑ´Ù. ±×·¯¸é, ºñ¾îÀÖ´Â ÃÖÃÊÀÇ º¤ÅÍÀÎ 0x20 ¹ø º¤ÅͷκÎÅÍ´Â ¿ÜºÎ ÀÎÅÍ·´Æ®, Áï, ÇÁ·Î¼¼¼ÀÇ INTR ÇÉÀ¸·ÎºÎÅÍ signalling µÇ´Â ÀÎÅÍ·´Æ®µé, Áï, ¿ÜºÎ ÀÎÅÍ·´Æ® ¸®Äù½ºÆ® ¶óÀÎÀ¸·ÎºÎÅÍÀÇ ÀÎÅÍ·´Æ®¸¦ ó¸®ÇÏ´Â º¤ÅÍ°¡ µé¾î°¡°Ô µÈ´Ù. Áï, IRQ(Interrupt ReQuest Line) 0 ¹øÀº, ÇÁ·Î¼¼¼ÀÇ ÀÎÅÍ·´Æ® °ÔÀÌÆ® 20¹ø° ¿£Æ®¸®¿¡¼ Á¤ÀÇÇÏ´Â º¤ÅÍ¿¡¼ ó¸®ÇÏ°Ô µÇ´Â °ÍÀÌ´Ù.
±×·³, ´Ù½Ã ÇÔ¼ö·Î µ¹¾Æ°¡¼ ³»¿ëÀ» Çϳª¾¿ »ìÆ캸µµ·Ï ÇÏÀÚ. NR_IRQS °ª¸¸Å ·çÇÁ¸¦ µ¹¸é¼ FIRST_EXTERNAL_VECTOR ¹ø° °ÔÀÌÆ®·ÎºÎÅÍ Çϳª¾¿ interrupt[] ¹è¿¿¡ Á¤ÀÇµÈ ÇÔ¼ö Æ÷ÀÎÅ͸¦ º¤ÅÍ·Î ÇÒ´çÇÏ°í ÀÖ´Ù. Àü¿ªº¯¼ö interrupt ´Â °°Àº ÆÄÀÏ¿¡ ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :
¿©±â¼ °¢°¢ÀÇ #define ¸ÅÅ©·Î¸¦ expand ½ÃÅ°´Â °Í±îÁö´Â À̾߱âÇÏÁö ¾Ê°Ú´Ù. °á°ú¸¸ À̾߱âÇÏÀÚ¸é, interrupt[] ¹è¿ÀÇ °¢ ¿£Æ®¸®´Â °¢°¢ IRQ0xNN_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 };
´Ù½ÃÇѹø ¼Ò½º¸¦ Àо °Ú´Ù. (CONFIG_X86_VISWS_APIC ¿É¼ÇÀº, SGI Visual Workstation À» ¼±ÅÃÇßÀ» ¶§¸¸ »ý±â´Â ¿É¼ÇÀÌ´Ù. Áö±Ý x86 À» ´Ù·ç°í ÀÖÀ¸¹Ç·Î ¹«½ÃÇÏ°í ³Ñ¾î°¡ÀÚ) ¿ì¼±, init_ISA_irqs() ÇÔ¼ö¿¡¼´Â ´ÙÀ½°ú °°ÀÌ ³ªÁß¿¡ ½ÇÁ¦ ÀÎÅÍ·´Æ® Çڵ鸵½Ã¿¡ »ç¿ëÇÒ irq_desc[] ¹è¿À» ÃʱâÈ ÇÑ´Ù :
ÀÌ ÇÔ¼ö¿¡¼´Â irq_desc[] ¹è¿ÀÇ Ãʱâȸ¦ Çϴµ¥, irq_desc[] ¹è¿¿¡ °üÇÑ ÀÚ¼¼ÇÑ ³»¿ëÀº ³ªÁß¿¡ À̾߱âÇϵµ·Ï ÇÏ°í, ÀÏ´Ü, °£´ÜÇÑ »çÇ׸¸ À̾߱âÇÏ°í ³Ñ¾î°¡°Ú´Ù. 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 ¶óÀÎÀÇ »óÅ¿¡ °üÇÑ Á¤º¸¿Í ±×¿¡ µû¸¥ Çڵ鷯µéÀÇ Æ÷ÀÎÅ͸¦ °¡Áö°í ÀÖ°Ô µÈ´Ù. ÃÖÃÊ¿¡´Â, init_ISA_irqs() ÇÔ¼ö¿¡¼ º¸À̵íÀÌ, status ¿¡ IRQ_DISABLED ¶ó´Â °ªÀ» ³Ö°í, 0 - 15 ¹øÀÇ ¿ø¼ÒÀÇ handler °ªÀº ¸ðµÎ i8259A_irq_type À» °¡¸®Å°´Â Æ÷ÀÎÅÍ·Î ÃʱâȵȴÙ. i8259A_irq_type Àº ´ÙÀ½°ú °°ÀÌ Á¤ÀǵǾî ÀÖ´Ù :
---------------------------------------------------------- /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];
ÀÚ¼¼ÇÑ °ÍÀº µÚ¿¡¼ ´Ù·ç±â·Î ÇÏ°í, ´Ù½Ã init_IRQ() ÇÔ¼ö·Î µ¹¾Æ°¡ÀÚ.
---------------------------------------------------------- /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 };
¾Õ¼ À̾߱âÇÑ °Íó·³ IDT ÀÇ °¢°¢ÀÇ ¿ø¼ÒÀÇ º¤Å͸¦ IRQ0xNN_interrupt() ·¹À̺íÀ» °¡¸®Å°µµ·Ï ¼³Á¤ÇÏ°í, ¸®ÅÏÇÑ´Ù. IRQ0xNN_interrupt() ·¹À̺íÀº ¾î¶»°Ô Á¤ÀǵǾî ÀÖ´ÂÁö µû¶ó°¡ º¸°Ú´Ù. i8259.c ÆÄÀÏÀÇ Ã¹ºÎºÐ¿¡ º¸¸é ´ÙÀ½°ú °°Àº ¸ÅÅ©·Î°¡ Á¤ÀǵǾî ÀÖ´Ù :
óÀ½ ³ª¿À´Â BUILD_COMMON_IRQ() ¸ÅÅ©·Î´Â ´ÙÀ½Ã³·³ Á¤ÀǵǾî ÀÖ´Ù :
---------------------------------------------------------- /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)
---------------------------------------------------------- /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] | ÀÎÅÚÀÇ ¹®¼¿¡¼ Çã¶ô¾øÀÌ ÀüÁ¦ÇßÀ½ |