练习0
填写已有实验
本实验依赖实验1~3.请把已做的实验1~实验3的代码填入本实验中代码中有lab1、lab2、lab3的注释相应部分
首先利用meld工具比较两个文件的差异
发现缺失的是kdebug.c、trap.c、default_pmm.c、pmm.c、swap_fifo.c vmm.c
四个文件的相关代码,补全后进行下一练习
练习1
分配并初始化一个进程控制块(需要编程)
alloc_proc函数(位于kern/process/proc.c中)负责分配并返回一个新的struct proc_struct结构,用于存储新建立的内核线程的管理信息。ucore需要对这个结构进行最基本的初始化,本练习要求完成这个初始化过程
首先简单说明一下内核线程与用户进程的区别:
内核线程只运行在内核态。用户进程会在在用户态和内核态交替运行所有内核线程共用ucore内核内存空间,不需为每个内核线程维护单独的内存空间,而用户进程需要维护各自的用户内存空间。
首先在kern/process/proc.h
中定义了进程控制块的结构体proc_struct
proc_struct
struct proc_struct {
enum proc_state state; // Process state
int pid; // Process ID
int runs; // the running times of Proces
uintptr_t kstack; // Process kernel stack
volatile bool need_resched; // bool value: need to be rescheduled to release CPU?
struct proc_struct *parent; // the parent process
struct mm_struct *mm; // Process's memory management field
struct context context; // Switch here to run process
struct trapframe *tf; // Trap frame for current interrupt
uintptr_t cr3; // CR3 register: the base addr of Page Directroy Table(PDT)
uint32_t flags; // Process flag
char name[PROC_NAME_LEN + 1]; // Process name
list_entry_t list_link; // Process link list
list_entry_t hash_link; // Process hash list
};
这里简单介绍下各个参数:
- mm:内存管理的信息,包括内存映射列表、页表指针等,即实验三中的描述进程虚拟内存的结构体. mm 里有个很重要的项pgdir,记录的是该进程使用的一级页表的物理地址。
state:进程所处的状态。
PROC_UNINIT // 未初始状态 PROC_SLEEPING // 睡眠(阻塞)状态 PROC_RUNNABLE // 运行与就绪态 PROC_ZOMBIE // 僵死状态
pid:进程id号。
- parent:用户进程的父进程(创建它的进程)。在所有进程中,只有一个进程没有父进程,就是内核创建的第一个内核线程 idleproc。内核根据这个父子关系建立进程的树形结构,用于维护一些特殊的操作,例如确定哪些进程是否可以对另外一些进程进行什么样的操作等等。
- context:进程的上下文,用于进程切换。 在ucore 中,所有的进程在内核中也是相对独立的(例如独立的内核堆栈以及上下文等等)。使用context保存寄存器的目的就在于在内核态中能够进行上下文之间的切换。
- tf:中断帧的指针,总是指向内核栈的某个位置:当进程从用户空间跳到内核空间时,中断帧记录了进程在被中断前的状态。当内核需要跳回用户空间时,需要调整中断帧以恢复让进程继续执行的各寄存器值。除此之外,ucore 内核允许嵌套中断。因此为了保证嵌套中断发生时 tf 总是能够指向当前的 trapframe, ucore 在内核桟上维护了 tf 的链。
- cr3: cr3 保存页表的物理地址,目的就是进程切换的时候方便直接使用 lcr3 实现页表切换,避免每次都根据 mm 来计算 cr3。 mm 数据结构是用来实现用户空间的虚存管理的,但是内核线程没有用户空间,它执行的只是内核中的一小段代码(通常是一小段函数),所以它没有 mm 结构,也就是 NULL。当某个进程是一个普通用户态进程的时候, PCB 中的 cr3 就是 mm 中页表( pgdir)的物理地址;而当它是内核线程的时候, cr3 等于 boot_cr3。 而 boot_cr3 指向了 ucore 启动时建立好的栈内核虚拟空间的页目录表首地址。
- kstack:每个进程都有一个内核桟,并且位于内核地址空间的不同位置。对于内核线程, 该桟就是运行时的程序使用