【操作系统】实验楼实验五——基于内核栈的进程切换

载入实验环境

首先配置环境

cd /home/shiyanlou/oslab
tar -zxvf hit-oslab-linux-20110823.tar.gz -C /home/shiyanlou

实验过程截图

分别对/kernel/fork.ckernel/system_call.s/kernel/sched.c/include/linux/sched.h

进行修改,截图如下:

注释掉原来switch_to宏函数,将新的switch_to()函数作为一个系统调用函数重写在汇编文件system_call.s中:

让所有进程共用一个TSS(这里使用0号进程的TSS)需要定义一个全局指针变量tss(放在system_call.s中)来执行0号进程的TSS:

在内核栈指针重写指令中有宏定义ESP0,所以在上面需要提前定义好 ESP0 = 4,(是因为TSS中内核栈指针ESP0放在偏移为4的地方)

修改以后的fork()要使得父子进程共享同一块内存空间、堆栈和数据代码块。

首先需要将first_return_kernel设置在全局可见,然后再在fork.c中添加该函数声明:

sched.h中的task_struct(也就是pcb)中添加kernelstack

最后,将first_return_kernel(属于系统调用,而且是一段汇编代码)写在system_call.s头文件里,回到~/oslab目录下:

make all
cd linux-0.11
../run

实验结果截图

问题回答

问题 1

针对下面的代码片段:

movl tss,%ecx
addl $4096,%ebx
movl %ebx,ESP0(%ecx)

回答问题:

  • (1)为什么要加 4096;
  • (2)为什么没有设置 tss 中的 ss0。
回答1

**(1)**由于Linux 0.11进程的内核栈和该进程的PCB在同一页内存上,而此内存大小为4KB(4*1024)。PCB位于这页内存的低地址,栈位于这页内存的高地址,如果要得到内核栈地址就需要加4096。

**(2)**tss.ss0是内核数据段,进程的切换不依靠tss,但CPU的机制让所有寄存器都会有tss字段。所以可以让所有的进程都共用tss0的空间,不需要设置tss0。

问题 2

针对代码片段:

*(--krnstack) = ebp;
*(--krnstack) = ecx;
*(--krnstack) = ebx;
*(--krnstack) = 0;

回答问题:

  • (1)子进程第一次执行时,eax=?为什么要等于这个数?哪里的工作让 eax 等于这样一个数?
  • (2)这段代码中的 ebx 和 ecx 来自哪里,是什么含义,为什么要通过这些代码将其写到子进程的内核栈中?
  • (3)这段代码中的 ebp 来自哪里,是什么含义,为什么要做这样的设置?可以不设置吗?为什么?
回答2

**(1)**eax=0,即返回值。以便用if(!fork())来判断是不是子进程。最后一行(–krnstack) = 0完成了这件事。

**(2)**ebx和ecx来自copy_process()的形参,是段寄存器。为了让父子的内核栈在回到用户态初始化时完全一致。

**(3)**ebp也是来自copy_process()函数传进来的参数,存放的是父进程的用户栈指针。即在fork()刚刚执行完copy_process()的时候,它的用户栈是父进程的用户栈;当子进程执行其他操作的时候,需要的栈与父进程不同时,才会创建自己的用户栈。这样系统不用分配额外的空间给闲置子进程。不可以不设置,因为它存放了用户栈,虽然也可以创建子进程为它分配一个新的栈,esp指向新的栈顶,但是对于父进程是不可删除的。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值