初めての方はこちらを参照 http://d.hatena.ne.jp/takahirox/20101024/1287923014
はじめに
今回は10章に出てくるコードの詳細を追っていきます。
fuiword
まずは通常動作を見ていきます。
通常動作
- 845 : この時点でスタックの先頭にはfuiwordを呼んだ命令(の次の命令)へのリターンアドレス、fuiwordに対する引数が積んであります。
sp |
stack |
|
|
-> |
PC(return to fuiword caller) |
|
arg for fuiword |
|
|
- 846 : fuiwordに対する引数をr1へ保存
- 848 : PC(return address)をスタックに積んでgwordへジャンプ
line#はunix v6の行番号を表します。
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to 849) |
|
848 |
|
PC(return to fuiword caller) |
|
|
|
arg for fuiword |
-> r1 |
846 |
|
|
|
|
- 852 : PSをスタックに積む
- 853 : PSのプロセッサ優先度を7にして割り込みを防ぐ
- 854 : nofaultをスタックに積む
- 855 : nofaultにerr(trap handler)を設定
sp |
stack |
register |
line# |
|
|
|
|
-> |
nofault |
|
854 |
|
PS |
|
852 |
|
PC(return to 849) |
|
|
|
PC(return to fuiword caller) |
|
|
|
arg for fuiword |
|
|
|
|
|
|
variable |
value |
line# |
nofault |
<- address to err |
855 |
- 856-857 : r1を引数にmfpiを実行。結果はスタックに積まれる。その結果をr0に移す
- 876 : スタックに積んでいたnofaultの元の値を復帰
- 877 : スタックに積んでいたPSを復帰(プロセッサ優先度も元に戻る=割り込み可)
- 878 : スタックの先頭に積んであるPC(return to 849)を用いてfwordに戻る
- 849 : スタックの先頭に積んであるPCを用いてfuiwordの呼び出し元へ戻る
sp |
stack |
register |
line# |
|
|
|
|
|
result of mfpi(r1) |
-> r0 |
856, 857 |
|
nofault |
-> nofault |
876 |
|
PS |
-> PS |
877 |
|
PC(return to 849) |
|
878 |
|
PC(return to fuiword caller) |
|
849 |
-> |
arg for fuiword |
|
|
|
|
|
|
variable |
value |
line# |
nofault |
<- address to err |
855 |
mfpi(856)でバスタイムエラーが起きた場合
次はmfpi(856)でバスタイムエラーが起きた場合を見ていきます。
mfpi(856)が実行される時点のスタック、nofaultは以下の状態です。
sp |
stack |
register |
line# |
|
|
|
|
-> |
nofault(original) |
|
|
|
PS |
|
|
|
PC(return to 849) |
|
|
|
PC(return to fuiword caller) |
|
|
|
arg for fuiword |
|
|
|
|
|
|
variable |
value |
line# |
nofault |
address to err |
|
- 856 : mfpiでバスタイムエラー。結果はスタックに積まれない(と思う)。(おそらくこのタイミングで)現在のPS, PCがスタックに積まれる。PCは512を差し512へジャンプ
- 512 : この文はよくわからない。ここで現在のPC, PSがvector addressから設定される? 現モード、前モードはカーネルモードになる。fuiwordはカーネルモードで実行されるので、モードは変わらない。使用するスタックもカーネルスタックのまま変わらない。trap(755)へジャンプ
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to gword(857?)) |
|
856 ? |
|
PS |
|
856 ? |
|
nofault(original) |
|
|
|
PS |
|
|
|
PC(return to 849) |
|
|
|
PC(return to fuiword caller) |
|
|
|
arg for fuiword |
|
|
|
|
|
|
variable |
value |
line# |
nofault |
address to err |
|
- 756 : PSをスタックの先頭の2word前へ積む。何のためかはよくわからない
- 757, 758 : nofaultが偽か(?)調べる。errへのアドレスが入っているので764へ分岐
- 766 : SSRを初期化してメモリ管理を有効に。なんのため?
- 767 : スタックの先頭に積んであるgwordへのリターンアドレスをnofault(errのアドレス)に置き換える
- 768 : スタックの先頭からPC, PSを復帰。PCにはerrが入るのでerr(880)へジャンプ
sp |
stack |
register |
line# |
|
|
|
|
|
PS |
|
|
|
|
|
|
|
address to err |
-> PC |
767, 768 |
|
PS |
-> PS |
768 |
-> |
nofault(original) |
|
|
|
PS |
|
|
|
PC(return to 849) |
|
|
|
PC(return to fuiword caller) |
|
|
|
arg for fuiword |
|
|
|
|
|
|
variable |
value |
line# |
nofault |
address to err |
|
- 881 : スタックに積んでおいたnofaultの元の値を復帰
- 882 : スタックに積んでおいたPSの元の値を復帰
- 883 : fuword(849)へのリターンアドレスをスキップ。なぜtst命令? つまりfuiwordへは戻らない
- 884 : mfpi命令の結果(=fuiwordの結果)が格納されるr0に-1を入れる。これがエラーを示す
- 885 : fuiwordの呼び出し元へ戻る
sp |
stack |
register |
line# |
|
|
|
|
|
nofault(original) |
-> nofault |
881 |
|
PS |
-> PS |
882 |
|
PC(return to 849) |
|
883 |
|
PC(return to fuiword caller) |
|
885 |
-> |
arg for fuiword |
|
|
|
|
|
|
register |
value |
line# |
r0 |
-1 |
884 |
トラップハンドラ(err)がやっている処理は、トラップの共通処理を除けば「884のr0に-1を入れる」だけと言えるかもしれません。
クロック割り込み
クロック割り込みが発生するとvector addressからPS, PCが設定される。ユーザーモードのプロセスに対して割り込んでいる可能性もあるので、スタックによるデータの受け渡しは使えない。PCは570を指す。
クロックに割り込まれた時のカーネルスタックの状態。割り込まれたプロセスのPC, PSが積まれている。
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to the interrupted process) |
|
570? |
|
PS(of the interrupted process) |
|
570? |
|
|
|
|
- 570 : jsr命令により、r0をスタックに積み、PCにはcallのアドレス(776)が入る。また、r0には_clockのアドレスが入る
sp |
stack |
register |
line# |
|
|
|
|
-> |
r0 |
|
570 |
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
<- address to _clock(3725) |
570 |
- 777 : PSをスタックに積む
- 779 : r1をスタックに積む。(r1には何が入っている?)
- 780 : 割り込まれたプロセスのspを積む?
sp |
stack |
register |
line# |
|
|
|
|
-> |
sp(of the interrupted process) |
|
780 |
|
r1 |
|
779 |
|
PS |
|
777 |
|
r0 |
|
570 |
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
address to _clock(3725) |
|
- 781 : 777でスタックに積んだPSをさらにスタックに積む
- 782 : 先頭にあるPSの下位5bitを除いてマスク(八進数の37は二進数で11111)
- 783 : 前モード(割り込まれたプロセスのモード)をチェック(PSの[13:12])
sp |
stack |
register |
line# |
|
|
|
|
-> |
PS(masked) |
|
781, 782 |
|
sp(of the interrupted process) |
|
|
|
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
address to _clock(3725) |
|
ここから前モードがカーネルモードかユーザーモードかで分岐します。
- 784 : 797へ分岐
- 798 : 前モードをユーザーモードに設定(なぜ?)
- 799 : r0(_clock(3725))へジャンプ。スタックの先頭にPCを積む
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to _call(800) |
|
799 |
|
PS(masked) |
|
|
|
sp(of the interrupted process) |
|
|
|
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
address to _clock(3725) |
|
_clock(3725)は次章で扱います。_clockから戻ってきた後の処理を追います。
- 800 : スタックの先頭から二つ(PS(masked)とsp(of the interrupted process))を取り除きます。
- 802 : スタックに積んでおいたr1を復帰
- 803 : スタックに積んでおいたPSをスキップ
- 804 : スタックに積んでおいたr0を復帰
- 805 : rtt命令で割り込まれたプロセスに戻る
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to _call(800) |
|
|
|
PS(masked) |
|
800 |
|
sp(of the interrupted process) |
|
800 |
|
r1 |
-> r1 |
802 |
|
PS |
|
803 |
|
r0 |
-> r0 |
804 |
|
PC(return to the interrupted process) |
-> PC |
805 |
|
PS(of the interrupted process) |
-> PS |
805 |
|
|
|
|
- 784 : 前モードがユーザーモードなので分岐しない
- 785 : r0(_clock(3725))へジャンプ。スタックの先頭にPCを積む
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to _call(786) |
|
785 |
|
PS(masked) |
|
|
|
sp(of the interrupted process) |
|
|
|
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
address to _clock(3725) |
|
上記のスタックの状態はLions本344Pのものです。(スタックの先頭方向が逆なので注意)
Lions本でも書かれている通り、Cの関数内でcsv(1420)が呼び出されてr2-5がスタックに積まれます。csvについては以前のエントリでも少し触れています。
clockから戻ってきた後の処理を追います。
- 787 : プロセッサ優先度(PS[7:5])を7にして割り込みを防ぐ
- 788 : runrunフラグがセットされているかチェック
sp |
stack |
register |
line# |
|
|
|
|
|
PC(return to _call(786)) |
|
|
-> |
PS(masked) |
|
|
|
sp(of the interrupted process) |
|
|
|
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
まずはrunrunフラグがセットされていない場合を追います。
- 789 : セットされていなければ793へ
- 794 : スタックに積んでおいたmasked PSをスキップ
- 795 : スタックに積んでおいたspを割り込まれたプロセスのspに移す?
sp |
stack |
register |
line# |
|
|
|
|
|
PS(masked) |
|
794 |
|
sp(of the interrupted process) |
|
795 |
-> |
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
ここからは前モードがカーネルモードのときの場合と同じです。
続いてrunrunフラグがセットされていた場合の処理を追います。
- 789 : セットされていないので分岐しない
- 790 : プロセッサ優先度を0に戻す
- 791 : swtchを呼び出して実行プロセスの切り替え。(最も優先度の高いプロセスが選択される)
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to 792) |
|
|
|
PS(masked) |
|
|
|
sp(of the interrupted process) |
|
|
|
r1 |
|
|
|
PS |
|
|
|
r0 |
|
|
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
このプロセスが再活性したときは796 -> 786と移り、runrunフラグのチェックを再度行う。
ユーザープログラムのトラップ(システムコール)
現モードはカーネルモードになる。システムコールはユーザープログラム(ユーザーモードで実行されているプロセス)から呼び出さえれるので、前モードはユーザーモード。なので、スタックによるデータの受け渡しは使えない。PCは570を指す。
システムコールが呼び出された時のカーネルスタックの状態。ユーザープログラムのPC, PSが積まれている。
sp |
stack |
register |
line# |
|
|
|
|
-> |
PC(return to the interrupted process) |
|
570? |
|
PS(of the interrupted process) |
|
570? |
|
|
|
|
- 518 : vector addressからPC, PSをロード。755へジャンプ
- 756 : PSをスタックの先頭から2word前にコピー。PSにはトラップ種別情報を含んでいるので、すぐに保存する必要がある
- 757 : nofaultをチェック
- 758 : nofaultには何も入っていないので分岐しない
- 759-761 : SSRの設定(なぜ必要?)
- 762 : jsr命令でcall1(771)へジャンプ
- 772 : spを756で積んだPSを指すようにする
- 773 : プロセッサ優先度を0に設定(割り込みok)
sp |
stack |
register |
line# |
|
|
|
|
-> |
PS(includes trap kind) |
|
756, 772 |
|
r0 |
|
762 |
|
PC(return to the interrupted process) |
|
|
|
PS(of the interrupted process) |
|
|
|
|
|
|
register |
value |
line# |
r0 |
address to _trap(2693) |
762 |
ここから先は割り込み処理と同じです。785でr0(_trap)にジャンプします。前モードは必ずユーザーモードなので798-のパスは通りません。
終わりに
コードのメモだけではわかりづらいと思いスタックの状態も併せて書いてみました。いかがでしょうか。結構大変だったので次からはやらないかもしれません笑
次は11章。クロック割り込み処理を追っていきます。