mpmain()
、scheduler()
、swtch()
とプロセス切り替えできるまで、
エミュレータの開発が進んだ。
xv6のコードproc.c
の334行目sti
命令をずっと発行していて、どうやらループに入っているようなので、
ここでスケジューリング、コンテキストスイッチ周りをまとめたい。
切り替え先のプロセスは、切り替えられた直後forkret()
、iinit()
関数内にて、IOを行っている。
ここで、スリープ状態に入り、割り込みを待っているようだ。
proc構造体
xv6では各プロセスはproc
構造体で管理される。
context
には、コンテキストスイッチのためのレジスタを格納する。
CSなどセグメントレジスタは、プロセス間で共通なので、保存する必要がない。
EAX、ECS、EDXなどは関数呼び出し時に自動的にスタックに保存されるため、context
に含めない。
最初のユーザプロセスは、userinit
関数とallocproc
関数で作成する。
proc
構造体のコメントには、最初のユーザプロセスのデータをメモしておく。
トラップフレームは、ハードウェアとtrapasm.S
によりスタック上に積まれるもので、
trap
関数へと引き渡される。
forkret
関数のreturn先は、trapret
に設定する。
struct proc {
uint sz; // Size of process memory (bytes)
pde_t* pgdir; // Page table
char *kstack; // このプロセスのカーネルスタックの底
enum procstate state; // プロセスの状態:EMBRYO
int pid; // PID:1
struct proc *parent; // 親プロセス:NULL
struct trapframe *tf; // トラップフレーム
struct context *context; // このプロセスのコンテキスト
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // カレントディレクトリ:/
char name[16]; // プロセス名:initcode
};
struct context {
uint edi;
uint esi;
uint ebx;
uint ebp;
uint eip; // forkret
};
struct trapframe {
// registers as pushed by pusha
uint edi, esi, ebp, oesp, ebx, edx, ecx, eax;
// rest of trap frame
ushort gs, padding1, fs, padding2, es, padding3, ds, padding4;
uint trapno;
// below here defined by x86 hardware
uint err;
uint eip;
ushort cs;
ushort padding5;
uint eflags;
// below here only when crossing rings, such as from user to kernel
uint esp;
ushort ss;
ushort padding6;
};
struct {
struct spinlock lock;
struct proc proc[NPROC];
} ptable;
カーネルスタック
proc->kstack
の中身を図示しておく。
swtchでは、esp
をproc->context
として、edi、esi、ebx、ebp
をpopする。
そして、最後にret
命令で、eip
を復元する。
(lower address)
-------------------
| | <= proc->kstack
| |
-------------------
-------------------
| edi | <= proc->context
| esi |
| ebx |
| ebp |
| eip = forkret |
-------------------
-------------------
| | <= trapret(関数ポインタ)
-------------------
-------------------
| | <= proc->tf
-------------------
<= proc->kstack + KSTACKSIZE(4096)
(upper address)
|—————-| | |