プロセス1実行編⑩(システムコール) trapret (Xv6を読む~OSコードリーディング~)
前回
jupiteroak.hatenablog.com
トップページ
jupiteroak.hatenablog.com
trapasm.S
https://github.com/mit-pdos/xv6-public/blob/master/trapasm.S#L20
#include "mmu.h" # vectors.S sends all traps here. .globl alltraps alltraps: ... # Call trap(tf), where tf=%esp pushl %esp call trap addl $4, %esp # Return falls through to trapret... .globl trapret trapret: popal popl %gs popl %fs popl %es popl %ds addl $0x8, %esp # trapno and errcode iret
execのシステムコール(exe関数の終了→sys_exec関数の終了→syscall関数の終了)が終わったら、alltrapsサブルーチンで呼び出したtrap関数から制御が戻ってきます。
処理の内容
call trap || execシステムコールの成功・失敗に関わらず、trap関数から制御が戻ってきます。 >|| addl $4, %esp
add命令により、espレジスタ(スタックポインタ)の値に4を加算します。これは、スタックのトップアドレスを4バイト分上位アドレスの方向へ戻す = スタックに退避されているtarp関数の引数の値(call trapの前にあるpushl %espでスタックに退避させた値)を復帰させずに無視すること を意味します。
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レジスタの値を復帰させ、割り込み・例外が発生したプロセスへ処理を戻します。
しかし、今回のようにinitcode.Sでexecシステムコールを呼び出した場合、iret命令実行後は、ユーザモードプロセスにロードされたinit.cのmain関数から処理が始まります。
exec関数の処理で見たように、eipレジスタにはinit.cのmain関数のアドレス値(elf.entryの値)が、csレジスタにはユーザコードセグメントを指定するセレクタ値が設定されているので、iret命令実行後は、ユーザモードプロセスとして、init.cのmain関数から処理が始まります。