The GNU Hurd hacking memo
解析情報いろいろ
呼び出し関係の tree 構造
+-----------+
|GRUB | (load gnumach & serverboot IPL time)
+-----------+
↓
+-----------+
|gnumach | kernel initialization
+-----------+
↓
+-----------+
|serverboot | user bootstrap (/boot/servers.boot processing)
+-----------+
↓
+-----------+ +-----------+
| fs server | | exec | (fs & exec are described in servers.boot)
+-----------+ +-----------+
ufs,ext2,iso
↓
+-----------+
| init | ----------------+
+-----------+ ↓
↓
+-----+ +-----+ +-----+ +-------------+
|proc | |auth | |term | | /libexec/rc | (rc script, multi user mode)
+-----+ +-----+ +-----+ +-------------+
./hurd-0.2 で grep ^makemode `find . -name 'Makefile' -print` した結果.
これだけサーバとして make されるものがあることになる.
(しかし,I/O サーバってどれ? storeio かな?)
./auth/Makefile:makemode := server X
./exec/Makefile:makemode := server X
./init/Makefile:makemode := server X
./proc/Makefile:makemode := server X
./term/Makefile:makemode := server X
./ufs/Makefile:makemode := servers X
./nfs/Makefile:makemode := server
./trans/Makefile:makemode := servers
./storeio/Makefile:makemode := server
./ext2fs/Makefile:makemode := servers X
./pflocal/Makefile:makemode := server
./pfinet/Makefile:makemode := server
./serverboot/Makefile:makemode := utility X
./ftpfs/Makefile:makemode := server
./hostmux/Makefile:makemode := server
./isofs/Makefile:makemode := server X
./usermux/Makefile:makemode := server
(X をつけたものは呼び出し関係を確認したもの)
とりあえず gnumach-1.1.3 のソースツリーを見ながらとったメモ
Assume current is ./gnumach-1.1.3/
boothdr.S (in./i386/i386at/)
ブートアップルーチン
こいつの最後で,c_boot_entry() が呼ばれる.
c_boot_entry() (in ./i386/i386at/model_dep.c)
C で書かれたブートエントリルーチン.
32bitで動くが,まだページングはしない.
・ブートイメージの位置を boot_info に退避.
・first message を表示(本当に printf なんかしていいんだろうか?)
・kernel debugger の初期化(その1)
・i386at_init() (in ./i386/i386at/model_dep.c)を呼び出し,
アーキ依存な初期化をする.
・kernel debugger の初期化(その2)
・最初のCPUの初期化? (struct machine_slot[0] に情報設定)
・最後にsetup_main() (in ./kern/starup.c)を呼び出し,
kernel 初期化 phase に移行する.
(復帰しない)
i386at_init() (in ./i386/i386at/model_dep.c)
アーキ依存な初期化をする.
・pic_init()
割り込みベクタ,割り込みレベル,割り込みマスク各種テーブルの
作成と初期化
・mem_size_init()
・pmap_bootstrap()
・i386 protect mode としての初期化
gdt_init() (in ./i386/i386/gdt.c)
idt_init() (in ./i386/i386/idt.c)
int_init() (in ./i386/i386/int.c)
ldt_init() (in ./i386/i386/ldtt.c)
ktss_init() (in ./i386/i386/ktss.c)
・割り込みスタックを物理アドレスの最後に設定する(テンポラリ)
startup_main() (in ./kern/startup.c)
カーネルの初期化を行う.
・panic, printf ルーチンを初期化する.
・sched_init() (in ./kern/sched_prim.c)を呼び出してスケジューラの
初期化????
・vm サブシステムと IPC サブシステムの初期化
vm_mem_bootstrap()
ipc_bootstrap()
vm_mem_init()
ipc_init()
・pmap_bootstrap() (in ./i386/intel/pmap.c)
カーネル用のページディレクトリとページテーブルを作成し,
全物理メモリをマップする.
・タイマの初期化
init_timers()
init_timeout()
timestamp_init()
・machine_init() (in ./i386/i386at/model_dep.c)
コンソール,FPU,各種デバイスの初期化
・ CPU数,物理メモリ,kernel version を machine_info に設定.
・task, thread, swapper サブシステムの初期化
task_init()
thread_init()
swapper_init()
・preemptive に動きはじめる.
recompute_priorities()
computre_mach_factors()
・kernel thread を起動する.
具体的には,まず
thread_create()を呼び出して最初の thread (startup_thread) を作る.
次に,start_kernel_threads() (in ./kern/starup.c) をエントリにして
thread_start()を呼び出して,この thread (starup_thread) を動かす.
start_kernel_threads()中で,startup_thread 以外の kernel thread の
起動処理をしている.
なお,startup_thread は kernel_task にくっついている.
・復帰してきたら,startup_thread をパラメタに thread_doswapin() を
呼び出し,kernel stack を allocate し,run queue につなげる.
・最後に,startup_thread をパラメタにして
cpu_launch_first_thread() (in ./kern/startup.c) を呼び出す.
(復帰しない)
cpu_launch_first_thread() (in ./kern/startup.c)
・
・最後に load_context() (in ./i386/i386/pcb.c) を呼び,パラメタ
に与えられた thread を dispatch する.
(復帰しない)
load_context() (in ./i386/i386/pcb.c)
制御を自分が動いている CPU の最初の thread に切替える?
・与えられた thread の pcb をパラメタに switch_ktss() を呼び出す.
・Load_context() (in ./i386/i386/cswitch.S)
アセンブラの context switch ルーチン.TSS struct の退避とか
をしている.
start_kernel_threads() (in ./kern/starup.c)
kernel thread と bootstrap task の起動を行う.
・CPU ごとに各種 idle_thread を準備しておく.
・kernel_thread() (in ./kern/thread.c) を使い,次の thread を
kernel thread として起動する.
reaper_thread
swapin_thread
sched_thread
・MP の時だけ,action_thread をつくり,他の CPU をスタートする.
・device_service_create() (in ??) を呼び,device serviceを
開始する???
・bootstrap_create() (in ./kern/bootstrap.c)を呼び,
user bootstrap を起動する.
・spl0() を呼ぶ (なんかの level 設定???)
・最後に vm_pageout() を呼び,自分は pageout thread になる.
(復帰しない)
bootstrap_create() (in ./kern/bootstrap.c)
・boot の時に読み込んだ bootstrap record の仮想アドレスを
調べて,bootstrap_exec() (in ./kern/bootstrap.c) で起動する.
real address は boot_info->mods_addr に入っている.
たぶん,この延長で各種サーバが動くはず.(まだ見てない)
--> ./hurd-0.2/serverboot/bootstrap.c の main() が
起動されるらしい.(モジュールは /boot/serverboot)
bootstrap_exec() (in ./kern/bootstrap.c)
・task_create() と thread_create() を呼びだし,
bootstrap task と bootstrap thread を作成する.
・bootstrap task に,master host port と device port への
send 権を与える.
・thread_start() を使って user_bootstrap() を起動する.
user_bootstrap() (in ./kern/bootstrap.c)
・起動オプションをとってきて,user bootstrap へ渡す形に
整える.
・user (current) thread に制御を渡す.
thread_bootstrap_return() (in ./i386/i386/locore.S) を使う.
(復帰しない)
hurd-0.2 を見ながらとったメモ
assume current directory is ./hurd-0.2/
user bootstrap
カーネルの初期化が終了した後,GRUB で module= に指定したもの,
普通は /boot/serverboot が呼び出される.
serverboot から script file として /boot/servers.boot が読まれ,
普通は fs サーバと exec サーバが起動される.
main() (in ./serverboot/bootstrap.c)
・
・最後に,自分は dafault_pager() (in ./serverboot/defaut_pager.c)を
呼び出して default pager になる.
/hurd/init が呼ばれるまで
/hurd/init は diskfs_start_bootstrap() (in ./libdiskfs/boot-start.c)
から呼ばれており,これはさらに,
diskfs_starup_diskfs() (in ./libdiskfs/init-startup.c) から呼び出される.
diskfs_starup_diskfs は,/hurd/ext2fs または /hurd/ufs または,
/hurd/isofs の bootstrap 時に呼ばれる.
系統的に見ると,
カーネル初期化後,user bootstrap が /boot/servers.boot を読み込んで処理
する過程で,root device のマウント時(diskfs bootstrap)に,かならず
ファイルサーバが動く.このタイミングで init サーバが起動され,
rcファイル等が処理されることになる.
server.boot script の最後で,exec サーバも起動されている.
ちなみに,init の中では /hurd/proc と /hurd/auth,/hurd/term が
起動されている.
/libexec/rc スクリプトは,マルチユーザモードに移行したのを
init が signal で検出して起動している.
しかし...
この構造だと,新しいファイル(システム)サーバをつくるたんびに,
そのファイルシステムがルートかどうかをきりわて,ルートなら
init を起動するようなコードをかかなくちゃいけないんだよね..
なんかきちゃない...(苦笑)
gnumach-1.1.3-19970630 の directory structure
./bogus
./chips
./ddb
./device
./ipc
./kern
./mig
./scsi
./util
./vm
./include
./include/mach
./include/mach/exec
./include/device
./include/mach_debug
./include/sys
./i386
./i386/aux
./i386/bogus
./i386/chips
./i386/dos
./i386/dos/i16
./i386/i386
./i386/i386at
./i386/i386at/gpl
./i386/i386at/gpl/linux
./i386/i386at/gpl/linux/block
./i386/i386at/gpl/linux/include
./i386/i386at/gpl/linux/include/asm
./i386/i386at/gpl/linux/include/linux
./i386/i386at/gpl/linux/include/net
./i386/i386at/gpl/linux/net
./i386/i386at/gpl/linux/pci
./i386/i386at/gpl/linux/scsi
./i386/i386at/boot
./i386/imps
./i386/include
./i386/include/mach
./i386/include/mach/sa
./i386/include/mach/sa/sys
./i386/include/mach/i386
./i386/include/mach/i386/exec
./i386/intel
./i386/pc
./i386/pc/i16
./i386/pc/rv86
./i386/util
./i386/util/i16
hurd-0.2-19971029 の directory structure
./libshouldbeinlibc
./libihash
./libiohelp
./libports
./libthreads
./libthreads/i386
./libpager
./libfshelp
./libdiskfs
./libtrivfs
./libps
./libnetfs
./libpipe
./libstore
./libmom
./libhurdbugaddr
./libftpconn
./auth
./boot
./exec
./fstests
./init
./proc
./term
./ufs
./utils
./sutils
./nfs
./trans
./ufs-fsck
./storeio
./ufs-utils
./ext2fs
./benchmarks
./pflocal
./defpager
./login
./pfinet
./pfinet/linux-inet
./pfinet/linux
./pfinet/asm
./daemons
./nfsd
./serverboot
./hurd
./doc
./config
./release
./include
./ftpfs
./hostmux
./isofs
./usermux
Mach の task と thread
thread の状態遷移図
/*
* State machine
*
* states are combinations of:
* R running
* W waiting (or on wait queue)
* S suspended (or will suspend)
* N non-interruptible
*
* init action
* assert_wait thread_block clear_wait suspend resume
*
* R RW, RWN R; setrun - RS -
* RS RWS, RWNS S; wake_active - - R
* RN RWN RN; setrun - RNS -
* RNS RWNS RNS; setrun - - RN
*
* RW W R RWS -
* RWN WN RN RWNS -
* RWS WS; wake_active RS - RW
* RWNS WNS RNS - RWN
*
* W R; setrun WS -
* WN RN; setrun WNS -
* WNS RNS; setrun - WN
*
* S - - R
* WS S - W
*
*/