3.1. startup_32() 함수에서의 IDT 의 초기화

startup_32() 함수에서는 다음과 같이 setup_idt() 함수를 호출한다 :

--------------------------------------
/usr/src/linux/arch/i386/kernel/head.S
--------------------------------------
startup_32:
	:
	:
/*
 * start system 32-bit setup. We need to re-do some of the things done
 * in 16-bit mode for the "real" operations.
 */
	call setup_idt
	:
	:

그럼 이제 setup_idt() 함수를 보도록 하자. 이 함수에서는 모든 IDT 의 엔트리가 ignore_int() 으로 점프하도록 세팅한다. 실제 쓰이는 인터럽트 디스크립터 테이블의 세팅은 뒤에 paging_init() 함수가 호출 되고서 페이징이 활성화 된 후에 수행한다. setup_idt() 의 코드는 /usr/src/linux/arch/i386/kernel/head.S 에서 찾아볼 수 있다 :

--------------------------------------
/usr/src/linux/arch/i386/kernel/head.S
--------------------------------------
setup_idt:
	lea ignore_int,%edx
	movl $(__KERNEL_CS << 16),%eax
	movw %dx,%ax		/* selector = 0x0010 = cs */
	movw $0x8E00,%dx	/* interrupt gate - dpl=0, present */

	lea SYMBOL_NAME(idt_table),%edi
	mov $256,%ecx
rp_sidt:
	movl %eax,(%edi)
	movl %edx,4(%edi)
	addl $8,%edi
	dec %ecx
	jne rp_sidt
	ret

위의 것과 똑같은 어셈블리 코드가 뒤의 섹션에서 설명할 _set_gate() 함수에 나온다. 코드의 설명은 그때 하도록 하고, 그때 설명하지 않을 루프를 도는 부분을 잠시 설명하겠다.

코드에서,

	lea SYMBOL_NAME(idt_table),%edi
부분에서, idt_table 이라는 변수가 저장된 실주소(effective address)를 edi 레지스터에 load 했다. 인텔에서 edi 레지스터는 통상적으로 블록 move 등을 할 때 destination index 로 쓰이는 레지스터이다. 그리고,
	mov $256,%ecx
통상적으로 카운터로 쓰이는 ecx 레지스터에 idt_table 의 엔트리의 갯수인 256 을 넣고는 rp_sidt: 루프로 넘어가서 이 루프를 256번 반복하면서, 인텔의 인터럽트 게이트의 사이즈(8바이트)만큼 edi 레지스터를 증가시키면서 edi 가 가리키는 곳에 이미 만들어진 인터럽트 게이트를 세팅해 준다. 이 인터럽트 게이트는 모두다 동일하게 ignore_int 함수를 가리키는 것으로써, ignore_int 함수는 그냥 "Unknown interrupt" 를 화면에 출력하고 리턴하는 함수이다. 다음과 같이 정의되어 있다 :
--------------------------------------
/usr/src/linux/arch/i386/kernel/head.S
--------------------------------------
int_msg:
	.asciz "Unknown interrupt\n"
	ALIGN
ignore_int:
	cld
	pushl %eax
	pushl %ecx
	pushl %edx
	pushl %es
	pushl %ds
	movl $(__KERNEL_DS),%eax
	movl %eax,%ds
	movl %eax,%es
	pushl $int_msg
	call SYMBOL_NAME(printk)
	popl %eax
	popl %ds
	popl %es
	popl %edx
	popl %ecx
	popl %eax
	iret