プロセス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関数から処理が始まります。




次回
jupiteroak.hatenablog.com