swtch.S swtch
トップページ
jupiteroak.hatenablog.com
swtch.S
https://github.com/mit-pdos/xv6-public/blob/master/swtch.S
.globl swtch swtch: movl 4(%esp), %eax movl 8(%esp), %edx pushl %ebp pushl %ebx pushl %esi pushl %edi movl %esp, (%eax) movl %edx, %esp popl %edi popl %esi popl %ebx popl %ebp ret
swtchサブルーチンは、ハードウェアコンテキストの切り替えを行います。
ここでは、①scheduler関数から呼び出されるswtchサブルーチンと②sched関数から呼び出されるswtchサブルーチン の2つのケースについて、具体的に説明します。
目次
①scheduler関数から呼び出されるswtchサブルーチン
scheduler関数から呼び出されるswtchサブルーチン(swtch(&(c->scheduler), p->context):第1引数が&(c->scheduler)、第2引数がp->context)について説明します。
scheduler関数から呼び出されるswtchサブルーチンは、現在実行されているカーネルスレッドにおけるハードウェアコンテキストをカーネルスレッドのスタックに退避させ、切り替え先となるプロセスのカーネルスタックからハードウェアコンテキストを復帰させます。
swtch(&(c->scheduler), p->context)を呼び出した直後のスタックの状態
アドレス | 格納されている値 |
---|---|
... | ... |
下位アドレス側 | |
... | ... |
swtchサブルーチンのコールスタックにおける先頭アドレス | |
scheduler関数のコールスタックにおける終端アドレス | リターンアドレスの値 |
switchサブルーチンの第1引数の値 | |
switchサブルーチンの第2引数の値 | |
... | ... |
scheduler関数のコールスタックにおける先頭アドレス | mpmain関数のコールスタックにおける先頭アドレスの値 |
mpmain関数のコールスタックにおける終端アドレス | リターンアドレスの値 |
... | ... |
mpmain関数のコールスタックにおける先頭アドレス | ... |
... | ... |
上位アドレス側 | |
... | ... |
また、swtch(&(c->scheduler), p->context)を呼び出した直後のespレジスタには、scheduler関数のコールスタックにおける終端アドレスの値がセットされています(スタックポインタの値は、scheduler関数のコールスタックにおける終端アドレスの値になっています)。
第1引数の値をeaxレジスタにセットし、第2引数の値をedxレジスタにセットする
movl 4(%esp), %eax movl 8(%esp), %edx
movl 4(%esp), %eax
movl命令によって、switchサブルーチンの第1引数の値&(c->scheduler)をeaxレジスタにセットします。
&(c->scheduler)は、context構造体へのポインタschedulerを指定するアドレスです。
ポインタschedulerは、カーネルスレッドにおいて使用されるスタックのトップアドレスの値を保存するために使用されます。
movl 4(%esp), %eaxは、espレジスタ(スタックポインタ)が指定するアドレスから上位アドレス側へ4バイト進めたメモリ領域にある値を、eaxレジスタにセットします。
espレジスタ(スタックポインタ)が指定するアドレスはscheduler関数のコールスタックにおける終端アドレスです(espレジスタの値(スタックポインタの値)は、scheduler関数のコールスタックにおける終端アドレスの値です)。
よって、scheduler関数のコールスタックにおける終端アドレスから上位アドレス側へ4バイト進めたメモリ領域にある値は、switch関数の第1引数の値&(c->scheduler)となります。
movl 8(%esp), %edx
movl命令によって、switchサブルーチンの第2引数の値p->contextをedxレジスタにセットします。
p->contextは、切り替え先プロセスにおけるカーネルスタックのトップアドレスの値です。
movl 8(%esp), %edxは、espレジスタ(スタックポインタ)が指定するアドレスから上位アドレス側へ8バイト進めたメモリ領域にある値を、edxレジスタにセットします。
espレジスタ(スタックポインタ)が指定するアドレスはscheduler関数のコールスタックにおける終端アドレスです(espレジスタの値(スタックポインタの値)は、scheduler関数のコールスタックにおける終端アドレスの値です)。
よって、scheduler関数のコールスタックにおける終端アドレスから上位アドレス側へ8バイト進めたメモリ領域にある値は、switch関数の第2引数の値p->contextとなります。
カーネルスレッドのハードウェアコンテキストをカーネルスレッドのスタックに退避させる
pushl %ebp pushl %ebx pushl %esi pushl %edi
pushl命令によって、ebpレジスタの値、ebxレジスタの値、esiレジスタの値、ediレジスタの値をカーネルスレッドにおいて使用されるスタックに退避させます。
ebpレジスタには、swtchサブルーチンの呼び出し元であるscheduler関数が使用するコールスタックの先頭アドレス値が格納されています。
pushl %ebpは、scheduler関数が使用するコールスタックの先頭アドレス値を、swtchサブルーチンが使用するコールスタックに退避させます。
カーネルスレッドのスタックからプロセスのカーネルスタックへ切り替える
movl %esp, (%eax) movl %edx, %esp
現在使用しているカーネルスレッドのスタックから切り替え先プロセスのカーネルスタックへ切り替えます。
espレジスタ(スタックポインタ)が指定するアドレスを変更することで、スタックを切り替えることができます。
movl %esp, (%eax)
movl命令によって、カーネルスレッドのスタックのトップアドレスをc->schedulerに格納します。
movl %esp, (%eax)は、espレジスタの値を、eaxレジスタにセットされたアドレスが指定するメモリ領域に格納します。
espレジスタの値は、現在実行されているカーネルスレッドにおけるスタックのトップアドレスの値です。
eaxレジスタにセットされたアドレスは、context構造体へのポインタschedulerを指定するアドレス&(c->scheduler)です。
そのため、movl %esp, (%eax)は、カーネルスレッドにおけるカーネルスタックのトップアドレスをc->scheduler(&(c->scheduler)が指定するメモリ領域)に格納します。
movl %edx, %esp
movl命令によって、切り替え先プロセスにおけるカーネルスタックのトップアドレスの値を、espレジスタにセットします。
edxレジスタには、p->contextの値(プロセスにおけるカーネルスタックのトップアドレス値:allocproc関数で用意される)がセットされています。
movl命令が実行された後は、プロセスが持つカーネルスタックが利用されます。