实验目的:
1.了解第一个用户进程创建过程
2.了解系统调用框架的实现机制
3.了解ucore如何实现系统调用sys_fork/sys_exec/sys_exit/sys_wait来进行进程管理
练习0 填写已有实验
利用meld软件进行对比,截图如下
找到要修改的地方:
proc.c
default_pmm.c
pmm.c
swap_fifo.c
vmm.c
trap.c
kdebug.c
题目并没有结束,还要将代码进一步改进
idt_init函数
/* LAB5 YOUR CODE */
//you should update your lab1 code (just add ONE or TWO lines of code), let user app to use syscall to get the service of ucore
//so you should setup the syscall interrupt gate in here
extern uintptr_t __vectors[];
int i;
for (i = 0; i < sizeof(idt) / sizeof(struct gatedesc); i ++) {
SETGATE(idt[i], 0, GD_KTEXT, __vectors[i], DPL_KERNEL);
}
SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);//设置相应中断门即可
lidt(&idt_pd);
改进SETGATE(idt[T_SYSCALL], 1, GD_KTEXT, __vectors[T_SYSCALL], DPL_USER);//设置相应中断门即可
在上述代码中,可以看到在执行加载中断描述符表lidt指令前,专门设置了一个特殊的中断描述符idt[T_SYSCALL],它的特权级设置为DPL_USER,中断向量处理地址在__vectors[T_SYSCALL]处。这样建立好这个中断描述符后,一旦用户进程执行“INT T_SYSCALL”后,由于此中断允许用户态进程产生(注意它的特权级设置为DPL_USER),所以CPU就会从用户态切换到内核态,保存相关寄存器,并跳转到__vectors[T_SYSCALL]处开始执行,形成如下执行路径:
vector128(vectors.S)--\>
\_\_alltraps(trapentry.S)--\>trap(trap.c)--\>trap\_dispatch(trap.c)----\>syscall(syscall.c)-
在syscall中,根据系统调用号来完成不同的系统调用服务。
trip_dispatch函数
/* LAB5 YOUR CODE */
/* you should upate you lab1 code (just add ONE or TWO lines of code):
* Every TICK_NUM cycle, you should set current process's current->need_resched = 1
*/
ticks ++;
if (ticks % TICK_NUM == 0) {
assert(current != NULL);
current->need_resched = 1;//时间片用完设置为需要调度
}
代码改进current->need_resched = 1;//时间片用完设置为需要调度
alloc_proc函数
//LAB5 YOUR CODE : (update LAB4 steps)
/*
* below fields(add in LAB5) in proc_struct need to be initialized
* uint32_t wait_state; // waiting state
* struct proc_struct *cptr, *yptr, *optr; // relations between processes
*/
proc->state = PROC_UNINIT;//设置进程为未初始化状态
proc->pid = -1; //未初始化的进程id=-1
proc->runs = 0; //初始化时间片
proc->kstack = 0; //初始化内存栈的地址
proc->need_resched = 0; //是否需要调度设为不需要
proc->parent = NULL; //置空父节点
proc->mm = NULL; //置空虚拟内存
memset(&(proc->context), 0, sizeof(struct context));//初始化上下文
proc->tf = NULL; //中断帧指针设置为空
proc->cr3 = boot_cr3; //页目录设为内核页目录表的基址
proc->flags = 0; //初始化标志位
memset(proc->name, 0, PROC_NAME_LEN);//置空进程名
proc->wait_state = 0; //初始化进程等待状态
proc->cptr = proc->optr = proc->yptr = NULL;//进程相关指针初始化
代码改进
proc->wait_state = 0; //初始化进程等待状态
proc->cptr = proc->optr = proc->yptr = NULL;//进程相关指针初始化
实验涉及到用户进程,所以会用涉及调度问题,进程相关指针会被初始化
do_fork函数
//LAB5 YOUR CODE : (update LAB4 steps)
/* Some Functions
* set_links: set the relation links of process. ALSO SEE: remove_links: lean the relation links of process
* -------------------
* update step 1: set child proc's parent to current process, make sure current process's wait_state is 0
* update step 5: insert proc_struct into hash_list && proc_list, set the relation links of process
*/
if ((proc = alloc_proc()) == NULL) {
goto fork_out;
}
proc->parent = current;
assert(current->wait_state == 0); //确保当前进程为等待进程
if (setup_kstack(proc) != 0) {
goto bad_fork_cleanup_proc;
}
if (copy_mm(clone_flags, proc) != 0) {
goto bad_fork_cleanup_kstack;
}
copy_thread(proc, stack, tf);
bool intr_flag;
local_intr_save(intr_flag);
{
proc->pid = get_pid();
hash_proc(proc);
set_links(proc);//设置进程的相关链接
}
local_intr_restore(intr_flag);
wakeup_proc(proc);
ret = proc->pid;
代码改进
assert(current->wait_state == 0); //确保当前进程为等待进程