linux-0.01 読み (10)

読むマターで言うとシステムコールあたりも掘削始点かな。
例えば kernel/sched.c の sched_init 手続きで 0x80 な割り込みの設定されてて

	set_system_gate(0x80,&system_call);

上記 system_call な手続きの定義は kernel/system_call.s にある。てか先に set_system_gate なのか。

難解

詳解 Linux カーネルとか見ると簡単げに解説してあるんだけどねぇ。横着せずに intel のマニュアル見ないといかんのだろうなぁ。
ええと include/asm/system.h にて以下な定義か。

#define set_system_gate(n,addr) \
	_set_gate(&idt[n],15,3,addr)

ええと、15 とか 3 とかについては詳解 Linux カーネルで以下な記述がある

タイプ
15 が設定されます。このフィールドは、例外がトラップのため、対応するハンドラはマスク可能割り込みを無効にしないことを意味します。
ディスクリプタ特権レベル (DPL)
3 が設定されます。ユーザモードプロセスに例外ハンドラを呼び出すことを許可します (4 章の 4.2.4 を参照)

詳解 Linux カーネルより引用
以下なカンジになるのか。

?????????????????1101111000****

1110 というか 14 なら割り込みゲートって事になるのか。
で、_set_gate なマクロの定義が以下。

#define _set_gate(gate_addr,type,dpl,addr) \
__asm__ ("movw %%dx,%%ax\n\t" \
	"movw %0,%%dx\n\t" \
	"movl %%eax,%1\n\t" \
	"movl %%edx,%2" \
	: \
	: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
	"o" (*((char *) (gate_addr))), \
	"o" (*(4+(char *) (gate_addr))), \
	"d" ((char *) (addr)),"a" (0x00080000))

えーと解読してみます。とりあえず

  • %0 は即値で ((short) (0x8000+(dpl<<13)+(type<<8)))
  • %1 は (*((char *) (gate_addr)))
  • %2 は (*(4+(char *) (gate_addr)))
  • edx レジスタには ((char *) (addr)) が格納
  • eax レジスタには (0x00080000) が格納

うーん、最後らへんが微妙。で、命令なナニですが以下にて

  • ((char *) (addr)) の前半分 (0-15 bit) を ax に格納
    • eax の中身の 0008xxxx の xxxx な部分が addr な前半分に
  • edx の前の命令で移送した部分に ((short) (0x8000+(dpl<<13)+(type<<8))) が格納
  • それぞれを idt[n] に格納

こーゆーナニを

資料を見ながら確認したり、今のカーネルと比較してみたい訳ですよ。ちなみに手元の 2.6.35 なソースだと arch/x86/kernel/traps.c の trap_init 手続きの最後らへんで以下な処理が書いてある。

	set_system_trap_gate(SYSCALL_VECTOR, &system_call);

set_system_trap_gate は inline なナニで定義が以下。

static inline void set_system_trap_gate(unsigned int n, void *addr)
{
	BUG_ON((unsigned)n > 0xFF);
	_set_gate(n, GATE_TRAP, addr, 0x3, 0, __KERNEL_CS);
}

GATE_TRAP は 0xf で定義されてます。__KERNEL_CS は arch/x86/include/asm/segment.h で定義されてて以下。

#define __KERNEL_CS	(GDT_ENTRY_KERNEL_CS * 8)

8 だしw
そして 2.6.35 のここから先は略、てか勉強会でもごもごしたいッス、って事にて。