.\" -*- buffer-file-coding-system: euc-jp; -*-
.\" 文字コードを上の行でセットします．
.\"
.\" .TH "HURD hacking" 1 "2001年3月13日" "Junichi Uekawa" "Hurd hack"
.+c
.(l C
.sz 24
.b "HURDのハック記録"
.sz 18
.sp 2
人生無駄な事なんて存在しない．
やりたいようにやるべし．
ハックしたいならハックしろ．
後悔する事は無いだろう，
思う存分にハックしたのなら．
.sp 2
上川純一 
.i <dancer@debian.org>
.sz 
.)l
.\" なんか，ここで，ちゃぷたーの名称を策定するのだろう．
.++ "C" "章"
.+c "諸元"
.pp
この文章はHURDのハッキングへの導入です．
.pp
HURDの構造を解明します．
まず，初歩の段階として，起動までのプロセスを解説します．
なお，この文書は，2001年3月13日時点の情報であり，そしてその時点でも既
に現状とは違っているかも知れない
.i hurd
の20010111版と
.i gnumach
のv.1.2についての解説であるという事を断っておきます．
.pp
この文書の作者は上川純一
.i <dancer@debian.org>
です．作成日は，2001年3月13日です．
2001年3月14日，15日に更新されています．
.+c "HURDのOSとしての基本要素"
.sh 1 "起動のプロセス"
.sh 2 "概説"
.pp
.i hurd
の起動を語るには，それ以前の段階から追う必要があります．
実際には，
.i "hurd"
が起動するより先に
.i "gnumach"
が起動します．さらにいうと，
.i "gnumach"
は
.i "grub"
から起動されます．
まず，
.i "grub"
の詳細に付いては，
.i "grub" 
についてくる文章が詳しく説明してますので，そちらに譲ります．重要な点は，
.i "grub"
が
.i "gnumach"
をopenbootプロトコルというプロトコルで起動していると言う事です．このこ
とにより，
.i "gnumach"
がロードされる時点では，すでにia32のリニアモードに移行しています．ia32
のアーキテクチャ，およびリニアモードが何なのかについては，
.b "Intel"
からの情報がより詳しいですので，そちらを参照してください．具体的には，
.i "gnumach"
は，自分自身をロードするという手間を省いています．その点で，起
動部分が
.i "Linux/ia32"
ほど複雑では無いです．特に，
.i "grub"
が圧縮されたカーネルの解凍という作業も行っているようです．
.sh 2 "gnumachの起動"
.\" GNUMACHの起動をソースレベルで追跡．
.sh 3 "スレッド以前の黎明期"
.pp
.i "gnumach"
は，まず
.b "i386/i386at/boothdr.S"
にあるコードから実行されるようです．この時点では，もうすでにリニアアド
レスのフラットな空間が展開されています．実際には， Multiboot
Specification によって要求されているデータと，スタックを自前のものにす
ると言う事と，次のCの関数である
.b "c_boot_entry"
を呼び出すという事をやっているようです．
.pp
.b "i386/i386at/model_dep.c"
の中に
.b "c_boot_entry"
は存在します．そこでは，multiboot specificationによって，コマンドライ
ンが与えられた場合にはそれを取得するという事をしています．そして，
.b "i386at_init()"
という関数を呼び出し，CPU情報等を
.b "machine_slot"
という構造体に設定した後，
.b "setup_main()"
という関数を呼び出しています．
.pp
.b "i386at_init()"
では，ia32のプロテクトモードに移行するためのGDT，TLB，割り込み等の設定
が行われています．その実態は
.b "i386/i386/gdt.c"
などにあります．
.(f
.b "i386/i386/gdt.c" 
等は，Cのソースファイルですが，実際には，structをCで使っているだけで，
あとは，inline assemblerで書いてある所が多いです． 
.)f
.pp
.b "setup_main()"
という関数は
.b "kern/startup.c"
に入っています．どうやら，ここから機種依存が無くなるようです．いきなり
スレッドについての言及などがあり，
.b "gnumach"
がいかにスレッドを重視しているかと言う事がうかがい知れます．この方針は，
.b "Linux"
のLinux Torvaldsがスレッドとかロックとかを非常に嫌う事とは良い対照であ
ると思えます．SMP対応のためのコードが散見されますが，
.b "gnumach"
としては，SMPは対応していないということになっていたはずです．
.b "NCPUS"
というシンボルが定義されていて，それが 1 以上である時にはSMP対応のコー
ドがコンパイルされるようになっています．
この関数で，大体IPC関係，スレッド関係，そして仮想メモリ関係の初期化が
行われているようです．
.b "thread_init()"
は  
.b "kern/thread.c" 
にあります．
その後，カーネルスレッドが初期化されます．
.b "start_kernel_threads()"
という関数をスレッドとして実行するようです．
.b "start_kernel_threads()"
は，
.b "reaper_thread()"
と
.b "swapin_thread()"
と
.b "sched_thread()"
をスレッドとして作成するようです．
そして，
.b "device_service_create()"
を呼び出します．設定によっては，
.b "norma_ipc_init()"
と
.b "norma_vm_init()"
も呼び出すようになっているように見えるのですが，それが定義されている所
が見当たらないので，おそらく
.i "gnumach" 
には存在しないのでしょう．
それからちょこっとカーネルのスレッドのデータを整えて，
.b "bootstrap_create()"
を呼び出します．どうやら，
.b "bootstrap_create()"
がユーザ空間を始動するようです．
.b "spl0()"
という謎の関数がありますが，どうやらハードウェア依存のinterruptを止め
るための命令のようです．おそらく
.b "bootstrap_create()"
がシャットダウンまでかえってこない関数のようなので，無視して良いと思います．
.pp
.sh 3 "カーネルスレッドの解説"
.pp
カーネルスレッドとして最初に起動されている関数は，何故か全部，
.b "kernel_thread()"
というような関数が最初にあったら，その関数が，ただ
.b "kernel_thread_continue()"
というような関数を呼び出すだけであると言うようになっています．
これは，おそらく，スタックがちゃんと作成されていないために，
ローカル変数を利用できないというような理由があるのだろうと考えられます．
そして，
.b "kernel_thread_continue()"
という関数は絶対に終了しないようになっています．これは，終了しても，戻
るアドレスが全く設定されてないという状況があるような気もします．これら
は基本的なサービスなので，実際には，カーネルが動いている間は常に動いて
いる必要のある物ばかりですので，問題ではないのかも知れませんが．
.pp
.b "reaper_thread()"
は，
.b "kern/thread.c"
にあります．どうやら，終了したスレッドを掃除するためのスレッドのようで
す．
.b "splx()"
等の関数は，どうやら
.b "i386/i386/spl.S"
にあるようです．iplというものをいじる物らしいですが，ちょっと見ただけ
ではなにをやりたいのかが不明確です．ロック関係だと思うのですが．
splchedの意味がいまいち分かりません．もしかすると，「待ち」の関数かも
知れません．異様に多くの場所で利用されてます．
.pp
.b "swapin_thread()"
は
.b "kern/thread_swap.c"
にあります．内容としては，必要とされているスレッドをswap inするという
事をしています．
.b "thread_swapin(thread)"
という関数があり，その関数がキューにswap in要求を置いて行き，
swapin_threadがそのようきゅうに基づいてswap inをするということのようで
す．ここでのswap inは，どうやらもうすでにメモリにはロードされているよ
うに思えます．ただ，実行キューに突っ込むという行為のために，スレッドが
あるように感じられます．とりあえずinterruptの中でスレッドの実行キュー
をいじる事はできないから，独自のスレッドを作っているという印象を受けま
す．
.pp
.b "sched_thread()"
は
.b "kern/sched_prim.c"
にあります． この内容は，どうやら，ブロックしてしまったスレッドを救出
するというような事にあるようです．ここの技術には非常に深遠なテーマが眠っ
ているように見えます．
.sh 3 "デバイスドライバの初期化"
.pp
.b "device_service_create()"
と言うのが
.b "device/device_init.c"
にあります．内容としては，
.b "master_device_port"
として利用するIPCポートの獲得と，
.b "ds_init()"
と
.b "dev_lookup_init()"
と
.b "net_io_init()"
と
.b "device_pager_init()"
と
.b "chario_init()"
を呼び出すことをしてから，
.b "io_done_thread"
と
.b "net_thread"
というスレッドの起動をするという事のようです．
.pp
.b "ds_init()"
は
.b "device/ds_routines.c"
にあります．ここで利用されている
.b "simple_lock"
という関数はどうやらもとをただすと，Linuxのソースから来ているようです．
かなり複雑にLinuxに依存したシステムだと言えるように思えます．また，
.b "ds_init"
は
.b "ds_trap_init"
を呼びます．二つの関数とも，
.b "zinit"
という関数を呼び出しています．
これは，
.b "zalloc.c"
というファイルで定義されていますが，とりあえずメモリをがっぽりと確保して
いるようです．
.pp
.b "dev_lookup_init()"
TODO
.pp 
.b "net_io_init()"
TODO
.pp 
.b "device_pager_init()"
TODO
.pp
.b "chario_init()"
TODO
.pp
.b "io_done_thread()"
TODO
.pp
.b "net_thread()"
TODO
.\" 
.\" 
.\" 
.\" 
.sh 3 "ユーザ空間の始動"
.pp
.b "bootstrap_create()"
は
.b "kern/bootstrap.c"
で定義されています．ロード時に一緒に読み込まれたプログラムを実行するという実装になっているようです．Multiboot specificationに依存しているようなので，
.i grub
が実際にロードしてくるところまでやってくれているようです．つまり，このmoduleをロードするまでの所は，grubがやってくれているので，ここまででハードディスクをアクセスするとか，ファイルシステムとか，そういう物を扱う必要が全く無いというのは強い実装ですね．Multiboot のヘッダから情報を抽出して，そのアドレスを呼び出すということをやっています．
.(q
bootstrap_exec ((void *)phystokv(bmod->mod_start));
.)q
という所がありますが，そこで，「モジュール」を起動しているようです．この「モジュール」というのは，どうやら
.i grub
で指定されているものの事のようです．
そこで，moduleが一体どこで定義されていて，そうして実装されているのか，
と言う事に興味がひかれる事になります．
.pp
とりあえず，
.b "bootstrap_exec"
という関数を確認します．その関数は，
.b "kern/bootstrap.c"
にあります．基本的に，ただtaskとthreadを生成して，IPCポートの設定をして，
お茶を濁しているようです．ただ，ここでロードされる物が一体何なのかが不明．
もう少し良く見ないと分からないです．
