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 * */