プロセス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のバイナリファイルがロードされています。