MOBLOG | indiakiloの記録

モブでできている

UNIX fork (2) | セキュリティキャンプ2017 選-A-4

前回

indiakilo.hatenablog.com

前回のまとめ

  1. forkはプロセスの情報(struct proc)をまとめている配列procから空きのエントリーを見つけて新しいプロセスに割り当てている(ようだった)
  2. newproc関数によって新しいプロセスを生成している(ようだ)
  3. struct proc構造体を使ってプロセスの情報を管理している
  4. struct user構造体を使ってプロセスのデータを管理している
  5. struct procごとにstruct userが割り当てられている 

前回までの疑問

  1. struct proc, struct userを使って、どうやってプロセスを管理しているのか
  2. newprocは何をやっているのか
  3. forkはどうやって返り値を返しているのか
  4. struct user u, struct proc procへは、どうやってアクセスするのか(なぜアクセスできる??)

今回

1. UNIX V6の汎用レジスタ (PDP-11での環境)

UNIX V6はPDP-11という計算機でOSとして使用されていたいたらしい(Version 6 Unix - Wikipedia)。
PDP-11は1ワード16bitの計算機で、
UNIX V6は汎用レジスタとしてr0~r7までの8個のレジスタを扱っている。
そのレジスタの用途を以下に示す(参考[1]より)。

(アキュムレータとSP, PCが汎用?と思ってしまった)

レジスタ 用途
r0, r1 計算用, 関数の戻り値 (つまりアキュムレータ??)
r2, r3, r4 ローカル処理
r5 フレームポインタ, 環境ポインタ
r6 スタックポインタ(sp)
r7 プログラムカウンタ(pc)
r0~r4はともかく、r5, r6, 7は重要だと述べられている。
r6は各プロセスごとのスタックの先頭を指し、r7はフェッチサイクルに使われる。
r5のフレームポインタは、関数呼び出しの際のスタック(コンテキスト保存の際ということ??)の関数のデータの先頭ポインタを指スらしい。

2. struct userと汎用レジスタ

struct userはu_r0というint型のポインタを持っていた(行52)。
(address of users saved R0 とコメントされている)
(address of registeerということか??)

UNIX V6 struct user in /usr/sys/user.h .

このu_ar0は、fork関数でも使われている。

UNIX V6 fork system call in /usr/sys/ken/sys1.c .

プロセスのレジスタの値を保存するために、u_ar0を使っているらしく、つまりu.u_ar0[R0]は関数の返り値を表すのだろうか?? (いつかPDP-11をエミュレーションして試してみたい)

R0という定数を調べてみると、reg.hにたどり着いた。

snipet from UNIX V6 /usr/sys/reg.h .

R5の(-6)だとかっていうのは、アドレスを遡ってアクセスするということか?? (u.u_ar0[R5]とすると, *(u.u_ar + (-6))になるから…)
いつかUNIX V6を動かして、アドレスを比較してみたい。

ところで肝心なu_ar0のアドレスなのだが、これはnewproc関数を見ないとわからないっぽいので、また後で。。。

3. forkの返り値

u.u_ar0を使ってレジスタにアクセスすることがわかった。
 (なぜu.u_ar0がレジスタにリンクしているかはまだわからないが)
 (uとprocがなぜ他のファイルからもグローバルなのかも調べていない)

ところで、forkがvoidなのになぜPIDを返しているのか、という疑問だが、u.u_ar0[R0]を設定することで実現しているのだと思う。
 (これはアセンブラを見ればわかるのだと思う)

forkでは、newprocを呼び出したあと、u.u_ar0[R0]をp1->p_pidもしくはp2->p_pidに設定している。
p1は元プロセスのprocで、p2はprocへと新たに配置されたprocエントリである。
ということは元プロセスのprocのエントリでu.u_cstimeだとかを初期化しているので、子プロセスと親プロセスのprocエントリの位置が入れ替わっていないか??

よくわからないが、PIDを返す方法がわかった。

まとめ

わかったこと

  • forkがu.u_ar0[R0]を使って返り値を設定している(なぜそんなめんどくさいことを?)。

疑問

  • u.u_ar0がどうしてレジスタにリンクしているのか。
    (メモリマップドIOだからレジスタのアドレスを設定してるのかもしれない)

以上、
次回はnewprocについて調べたい。

参考

UNIXにおけるプロセスについて調べていると、以下の本が出てきた。
とても参考になっている。

[1]青柳隆宏 著 はじめてのOSコードリーディング ――UNIX V6で学ぶカーネルのしくみ
gihyo.jp