FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

MITのxv6を読もう - 第3章 trapの処理方法 -

http://pdos.csail.mit.edu/6.828/2014/xv6/book-rev8.pdf

トラップを処理するのも大変だなー。

xv6ではperlを使って、ベクタテーブルを作っているみたいだ。まあそこは問題じゃなくて、trapが発生すると、それを処理するためにまずalltrapsというルーチンに飛ぶ。 このルーチンでは、ユーザプロセスのレジスタのありとあらゆる情報を保存してスタックに書き込んでいる。alltrapsはカーネルモードで実行されるのかな? これにより、カーネルスタック上に次々とレジスタ値が保存されていく。こんな感じらしい。

f:id:msyksphinz:20150605022510j:plain

この図のことを、トラップフレームと読んでいる。さらに、trapというCで記述されている関数に飛ぶ。これには引数を設定する必要があるのだが、これもスタック上に積み上げている。

3270 # Call trap(tf), where tf=%esp
3271 pushl %esp
3272 call trap
3273 addl $4, %esp

trap(tf)内では、割り込みの種類に応じて処理を切り替える。

  • システムコールの場合: T_SYSCALLを設定してsyscallを呼び出す。
  • ハードウェアの割り込みの場合: それに応じた処理
  • それ以外: 異常なトラップと判断してユーザプロセスをクリーンアップ
  • カーネルがtrapを発生させ、どのトラップなのか分からない: OSの異常として強制終了

以下が、ベクタテーブルの生成perlスクリプトになっている。

3200 #!/usr/bin/perl −w
3201
3202 # Generate vectors.S, the trap/interrupt entry points.
3203 # There has to be one entry point per interrupt number
3204 # since otherwise there’s no way for trap() to discover
3205 # the interrupt number.
3206
3207 print "# generated by vectors.pl − do not edit\n";
3208 print "# handlers\n";
3209 print ".globl alltraps\n";
3210 for(my $i = 0; $i < 256; $i++){
3211 print ".globl vector$i\n";
3212 print "vector$i:\n";
3213 if(!($i == 8 || ($i >= 10 && $i <= 14) || $i == 17)){
3214 print " pushl \$0\n";
3215 }
3216 print " pushl \$$i\n";
3217 print " jmp alltraps\n";
3218 }
3219
3220 print "\n# vector table\n";
3221 print ".data\n";
3222 print ".globl vectors\n";
3223 print "vectors:\n";
3224 for(my $i = 0; $i < 256; $i++){
3225 print " .long vector$i\n";
3226 }
3227
3228 # sample output:
3229 # # handlers
3230 # .globl alltraps
3231 # .globl vector0
3232 # vector0:
3233 # pushl $0
3234 # pushl $0
3235 # jmp alltraps
3236 # ...
3237 #
3238 # # vector table
3239 # .data
3240 # .globl vectors
3241 # vectors:
3242 # .long vector0
3243 # .long vector1
3244 # .long vector2
````