Appearance
proc.h
TIP
专用于内核上下文切换时保存的寄存器。 RISC-V的调用约定中,callee-saved寄存器(s0-s11)由被调用函数负责保存和恢复。 ra 是返回地址(return address),sp 是栈指针(stack pointer)。 当一个函数(调用者)调用另一个函数(被调用者)时,被调用者不能随意修改这些寄存器, 如果需要使用,必须在函数开始时将它们的值保存在栈上,在函数返回前再从栈上恢复。 这样做可以确保调用者函数在子函数返回后,其寄存器状态保持不变。
struct context {
uint64 ra;
uint64 sp;
TIP
Callee-saved registers (被调用者保存的寄存器)
uint64 s0;
uint64 s1;
uint64 s2;
uint64 s3;
uint64 s4;
uint64 s5;
uint64 s6;
uint64 s7;
uint64 s8;
uint64 s9;
uint64 s10;
uint64 s11;
};
TIP
每个CPU核心维护一个cpu结构体,记录其自身的状态信息。
struct cpu {
struct proc *proc;
struct context context;
int noff;
int intena;
};
extern struct cpu cpus[NCPU];
TIP
trapframe结构体用于在用户态和内核态之间切换时,保存和恢复进程的上下文。 当发生系统调用、异常或中断时,硬件或软件会将用户进程的寄存器等状态保存在这个结构体中, 以便在内核处理完毕后,能够精确地恢复到用户态的执行点。 uservec (定义于 trampoline.S) 会将用户寄存器保存到trapframe, 然后从trapframe中加载kernel_sp, kernel_hartid, kernel_satp等内核关键信息, 并跳转到kernel_trap开始内核处理流程。 usertrapret和userret (定义于 trampoline.S) 则执行相反的操作, 它们设置trapframe中的kernel_*字段,恢复用户寄存器,切换回用户页表,然后返回用户空间。 trapframe也保存了callee-saved寄存器 (s0-s11),因为从内核态返回用户态的过程 不会经过完整的函数调用栈返回,需要手动恢复这些寄存器。
struct trapframe {
/* 0 */ uint64 kernel_satp;
/* 8 */ uint64 kernel_sp;
/* 16 */ uint64 kernel_trap;
/* 24 */ uint64 epc;
/* 32 */ uint64 kernel_hartid;
/* 40 */ uint64 ra;
/* 48 */ uint64 sp;
/* 56 */ uint64 gp;
/* 64 */ uint64 tp;
/* 72 */ uint64 t0;
/* 80 */ uint64 t1;
/* 88 */ uint64 t2;
/* 96 */ uint64 s0;
/* 104 */ uint64 s1;
/* 112 */ uint64 a0;
/* 120 */ uint64 a1;
/* 128 */ uint64 a2;
/* 136 */ uint64 a3;
/* 144 */ uint64 a4;
/* 152 */ uint64 a5;
/* 160 */ uint64 a6;
/* 168 */ uint64 a7;
/* 176 */ uint64 s2;
/* 184 */ uint64 s3;
/* 192 */ uint64 s4;
/* 200 */ uint64 s5;
/* 208 */ uint64 s6;
/* 216 */ uint64 s7;
/* 224 */ uint64 s8;
/* 232 */ uint64 s9;
/* 240 */ uint64 s10;
/* 248 */ uint64 s11;
/* 256 */ uint64 t3;
/* 264 */ uint64 t4;
/* 272 */ uint64 t5;
/* 280 */ uint64 t6;
};
TIP
定义进程可能处于的几种状态
enum procstate {
UNUSED,
USED,
SLEEPING,
RUNNABLE,
RUNNING,
ZOMBIE
};
TIP
proc结构体是进程控制块(PCB),包含了单个进程的所有状态信息。
struct proc {
struct spinlock lock;
TIP
p->lock 保护以下字段:
enum procstate state;
void *chan;
int killed;
int xstate;
int pid;
TIP
wait_lock 保护以下字段(用于父子进程间的等待关系):
struct proc *parent;
TIP
以下字段为进程私有,通常只在进程自己的上下文中修改,因此大多时候不需要锁保护
uint64 kstack;
uint64 sz;
pagetable_t pagetable;
struct trapframe *trapframe;
struct context context;
struct file *ofile[NOFILE];
struct inode *cwd;
char name[16];
};