プロセス1実行編②(カーネルモード) trapret (Xv6を読む~OSコードリーディング~)

前回
jupiteroak.hatenablog.com
トップページ
jupiteroak.hatenablog.com




trapasm.S(一部抜粋)
https://github.com/mit-pdos/xv6-public/blob/master/trapasm.S#L24

.....

.globl trapret
trapret:
  popal
  popl %gs
  popl %fs
  popl %es
  popl %ds
  addl $0x8, %esp  # trapno and errcode
  iret

trapretサブルーチンは、割り込み・例外ハンドラに相当する処理の一部です。
trapretサブルーチンは、割り込み・例外ハンドラの終了手続きを行います(割り込み・例外ハンドラ から 割り込み・例外が発生したプロセス へ制御を戻す前に、ハードウェアコンテキストを復帰させます)。


処理の内容

popal

popal命令により、汎用レジスタ(edi esi ebp esp ebx edx ecx eax)の値を復帰させます。

popl %gs

pop命令により、gsレジスタの値を復帰させます。

popl %fs

pop命令により、fsレジスタの値を復帰させます。

popl %es

pop命令により、esレジスタの値を復帰させます。

popl %ds

pop命令により、dsレジスタの値を復帰させます。

addl $0x8, %esp

add命令により、espレジスタ(スタックポインタ)の値に8を加算します。これは、スタックのトップアドレスを8バイト分上位アドレスの方向へ進める(スタックに退避されている割り込みベクタ番号の値(4バイト)とハードウェアエラーコードの値(4バイト)を復帰させずに無視する)ことを意味します。

iret

iret命令により、スタックに退避されているeip、cs、eflagsレジスタの値を復帰させ、割り込み・例外が発生したプロセスへ処理を戻します。
しかし、userinit関数によって新規に作成されたプロセスを実行する場合、iret命令実行後はプロセスのユーザー空間にあるアドレス0x0000 0000からinitcode.Sの処理が始まります。
userinit関数の処理で見たように、eipレジスタには0x0000 0000の値が、csレジスタにはユーザコードセグメントを指定するセレクタ値が設定されているので、iret命令実行後はユーザモードのプロセスとして0x0000 0000から処理が始まります。
そして、inituvm関数の処理で見たように、0x0000 0000にはinitcode.Sのバイナリファイルがロードされています。




次回
jupiteroak.hatenablog.com