ソフトウェア割り込みのc⌒っ゜д゜)っφ メモメモ...

オレオレカーネル用のソフトウェア割り込みにやっと手を出したたので、メモっときます。
まぁ、今更なネタだし面白くないですけど。
ソースはいつもながらgithubに。

流れ的には、こんな感じです。
1.設定
2.(どっかから)システムコール呼び出し
3.アセンブラコードで割り込みを受ける
4."2"で呼び出しを受けたシステムコールの呼び出し

設定部分は、まず、割り込みハンドラの構造体にsoft_intr_handler()をセットしときます。
場所は、0x80番目で、int $0x80のソフトウェア割り込みを受けるようにしてます。

struct handler_define  handler_info[HANDLER_INFO_NUM] = {
	{ (u_int32_t) isr_gate0, SEL_KERN_CS, GATE_TYPE_INTR_GATE },
	{ (u_int32_t) isr_gate1, SEL_KERN_CS, GATE_TYPE_INTR_GATE },
	{ (u_int32_t) isr_gate2, SEL_KERN_CS, GATE_TYPE_INTR_GATE },
        〜略〜	
        { (u_int32_t) 0, SEL_KERN_CS, GATE_TYPE_INTR_GATE },
	{ (u_int32_t) soft_intr_handler, SEL_KERN_CS, GATE_TYPE_INTR_GATE },
        〜略〜

この構造体はirqの割り込みでも使ってます。
set_handler()とset_interrupt_handler()でidtディスクリプタに必要な値をセットしてます。

/**
 * Setup interrupt handler to Interrupt descriptor table.
 */
static void set_interrupt_handler(void)
{
	int i;
	int size = sizeof(handler_info) / sizeof(handler_info[0]);
	struct handler_define *p = &handler_info[0];

	for (i = 0; i < size; i++, p++)
		set_handler(i, p->base, p->selector, p->type);

}
static void set_handler(int idx, u_int32_t base,
			u_int16_t selector, u_int8_t type)
{
	struct gate_descriptor *p = &intr_table[idx];

	p->offsetL = base & 0xffff;
	p->offsetH = (base >> 16) & 0xffff;
	p->selector = selector;
	p->type = type;
	p->count = 0; // unused.
}

ソフトウェア割り込み発生時に、割り込みを受けるのはこれです。
やってることは普通の割り込み発生時とそんなに変わりません。eaxをpushしてるところの、eaxの中身はシステムコールの番号です。

.globl soft_intr_handler
soft_intr_handler:
	cli
	pushal
	pushl 	%esp
	pushl 	%eax
	call 	software_interrupt_handler
	addl 	$8, %esp
	popal
	sti
	iret

call命令で呼ばれるのは以下の関数です。今は何もしてません。
そのうちシステムコールのテーブル作って、システムコール番号で示されたシステムコールを呼ぶようにします。

void software_interrupt_handler(u_int32_t int_no, struct registers regs)
{
	printk("0x%x : %s\n", int_no, __FUNCTION__);
}

そしたら、こんなコードを使ってテストしてみます。

	__asm__ ("xorl %eax, %eax\n\t"
		 "movl $0xbeef, %eax\n\t"
		 "int $0x80\n\t");

実行するとこんな感じになります。