Minixでコンテキストスイッチする部分は,処理内容的にkernel/mpx386.sのrestart()っぽいのでこれを見ます.
実装はアセンブラだけど,cからも呼べるようにkernel/proto.hにプロトタイプ宣言があります.
_PROTOTYPE( void restart, (void) );
といっても,実際にcのファイルからrestart()を呼ぶのは,kernel/main.cのmain()の最後のところだけです.
!*===========================================================================* !* restart * !*===========================================================================* _restart: ! Restart the current process or the next process if it is set. cmp (_next_ptr), 0 ! see if another process is scheduled jz 0f
まず_next_ptrは何かと言うと,kernel/glo.hで宣言されてます.
EXTERN struct proc *next_ptr; /* next process to run after restart() */
restart()の後に動くプロセス(コンテキストスイッチの結果,処理が始まる/再開)ですね.
最初に次のプロセスがあるかをチェックします._next_ptrがNULLでなければ,次のプロセスがあるという感じで.
無ければ,ラベル0に飛びます.
cmp命令で_next_ptrと0を比較して,_next_ptrが0なら,ゼロフラグが1になるので,次のjz命令でラベル0に飛びます.
もし_next_ptrが0でなければ,下の処理を実行します.
_proc_ptrもglo.hにてextern付きで宣言されてます.
EXTERN struct proc *proc_ptr; /* pointer to currently running process */
proc_ptrはカレントプロセスを示すので,_next_ptrで示すプロセスがカレントプロセスになるようにしてます.
mov eax, (_next_ptr) mov (_proc_ptr), eax ! schedule new process mov (_next_ptr), 0
next_ptrをproc_ptrにセットしたら,next_ptrはNULLにされます.
0: mov esp, (_proc_ptr) ! will assume P_STACKBASE == 0 lldt P_LDT_SEL(esp) ! enable process' segment descriptors
P_LDT_SELはマクロで,scont.hに定義があります.
これによるとstruct procの先頭からのオフセットを定義しているようです.
proc_ptrは当然struct proc型の構造体なので,これの先頭からのオフセットから,ldtセグメントディスクリプタの場所を示しているはずです.というか,そうじゃないとlldtでエラーになるので.
lldtで使用している変数は,proc構造体のp_ldt_selですね.
struct proc { struct stackframe_s p_reg; /* process' registers saved in stack frame */ #if (CHIP == INTEL) reg_t p_ldt_sel; /* selector in gdt with ldt base and limit */ struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS and remote segments */ #endif
次は,lltdの時と同様に,proc構造体のP_STACKTOPで示す変数にアクセスして,そのアドレスをeaxに入れておいて,
それをtss構造体のメンバ変数sp0に代入します.
lea eax, P_STACKTOP(esp) ! arrange for next interrupt mov (_tss+TSS3_S_SP0), eax ! to save state in process table
tss構造体は,protect.cで定義があります.TSS3_S_SP0は以下のように4となってます.
reg_tはunsigned intなので,x86なら4バイトってことで,tss構造体の先頭アドレス+4でsp0を指すようになってます.
struct tss_s { reg_t backlink; reg_t sp0; /* stack pointer to use during interrupt */ reg_t ss0; /* " segment " " " " */ reg_t sp1;
#define TSS3_S_SP0 4
最後に,各種レジスタをpopしてから,iret命令を使うことでrestart()を抜けるとproc_ptrで示されるプロセスに処理が遷移します.
restart1: decb (_k_reenter) o16 pop gs o16 pop fs o16 pop es o16 pop ds popad add esp, 4 ! skip return adr iretd ! continue process