清华大学操作系统实验lab1实验报告 下载本文

idt_init(void) { 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); }//初始化每一条IDT项 // 设置内核态到用户态的转换 SETGATE(idt[T_SWITCH_TOK], 0, GD_KTEXT, __vectors[T_SWITCH_TOK], DPL_USER); } // 载入IDT lidt(&idt_pd); 2. 请编程完善kern/trap/trap.c中对中断向量表进行初始化的函数idt_init。

3. 请编程完善trap.c中的中断处理函数trap,在对时钟中断进行处理的部分填写trap函数中处理时钟中断的部分,使操作系统每遇到100次时钟中断后,调用print_ticks子程序,向屏幕上打印一行文字”100 ticks”。

case IRQ_OFFSET + IRQ_TIMER: ticks ++; if (ticks % TICK_NUM == 0) { print_ticks(); }//当有100次时钟中断输出一次 break;

练习7、增加syscall功能,即增加一用户态函数(可执行一特定系统调用:获得时钟计数值),当内核初始完毕后,可从内核态返回到用户态的函数,而用户态的函数又通过系统调用得到内核态的服务。

先附上两个最重要的图,分别是内核态切换到用户态、用户态切换到内核

态的过程。

这部分是最花时间的,光是看代码就有很多疑问。

为什么需要构建一个临时的trapframe来实现切换栈,切换栈说白了不就是需要修改那几个寄存器吗? 2、

PPT上两个切换过程中的的两个老栈顶是一个地址吗?老栈顶是什么意思? 1、

3、 切换到用户态的过程中,trapframe的tf_esp为什么要指向原来的内核栈?有什么意义吗?

4、 切换到内核态的过程中,CPU压入的ss和esp是用户栈的还是内核栈的?

种种疑惑都出现在我的脑海里,加上不同的同学对这些问题有不同的理解,我也不想再去回想他们的理解了。直到看到“在执行int 120之前,系统在核心态,int不会引起切换,切换工作需在iret中完成。在执行int 121之前,系统在用户态,int引起切换,iret不需要再切换。”,感觉好像明白了一点。

说一下我对上述两个过程的理解。

? 内核到用户: 首先,我认为esp-8这个步骤不是必要的,因为从后续的过

程看来,空出来的8个字节从来没有被使用过。然后开始中断,由于是在内核态,所以ss和esp暂时还不需要改变,在原来的内核栈里就可以处理。然后通过CPU压入和操作系统压入内核栈的寄存器数据,构造了一个临时trapframe——switchk2u,通过pop esp跳到switchk2u,然后修改switchk2u的tf_esp,tf_ds,tf_es,tf_cs,tf_eflags,再通过一系列的pop和iret实现了对这些寄存器的修改——即实现了堆栈段、代码段和数据段的切换。

? 用户到内核:因为是int 121的关系,ss和esp在执行中断例程之前就已经切

换到了内核态,此后的操作都是在内核栈,还是由压入的寄存器状态构造了一个临时的trapframe——switchk2u,把tf_cs,tf_ds,tf_es,tf_eflags改掉之后,听过一系列pop和iret跳到了正确的代码段和数据段,堆栈段就不用跳了,因为中断的时候就已经跳到内核堆栈了。