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