曹朋辉
原创作品转载请注明出处
《Linux内核分析》MOOC课程
首先用老师提供的代码运行一下,可以看到她跑起来的最终样子。
确实没啥好看的,还是去分析代码吧。
刚看到作业时以为是要自己写代码,操作系统还没系统学过的我,一下懵了,上完课才知道老师已经提供了代码理解就好。
实验中我们用到了三个文件
mymain.c 此文件中包含操作系统的入口函数,最终我们通过此函数拉起一个进程,完成操作系统的初始化
myinterrupt.c 此文件中包含终端处理函数和进程调度函数
mypcb.h 定义了进程调度用到的数据结构
本次实验的重点分别为如下几个过程
一 . 操作系统的初始化, my_start_kernel函数会创建多个进程并拉起第一个进程,实现思路为通过嵌入式汇编修改eip,与esp
asm volatile(
"movl %1,%%esp\n\t" /* set task[pid].thread.sp to esp */
"pushl %1\n\t" /* push ebp */
"pushl %0\n\t" /* push task[pid].thread.ip */
"ret\n\t" /* pop task[pid].thread.ip to eip */
"popl %%ebp\n\t"
:
: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp) /* input c or d mean %ecx/%edx*/
);
}
二、进程的切换
进程切换的主要问题就是如何保存和恢复函数栈帧及改变eip的值。
下面既是实现进程切换的主要代码
/* switch to next process */
asm volatile(
"pushl %%ebp\n\t" /* save ebp */
"movl %%esp,%0\n\t" /* save esp */
"movl %2,%%esp\n\t" /* restore esp */
"movl $1f,%1\n\t" /* save eip */
"pushl %3\n\t"
"ret\n\t" /* restore eip */
"1:\t" /* next process start here */
"popl %%ebp\n\t"
: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
: "m" (next->thread.sp),"m" (next->thread.ip)
);
"pushl %%ebp\n\t" /* save ebp */
执行后esp中就就存储了ebp的值,因为我们只存储了esp的值因此这是了解如何恢复ebp的关键。
"movl $1f,%1\n\t" /* save eip */
保存"1:\t" /* next process start here */
代码的地址到当前进程的thread.ip, 下次切换回来时从此处接着继续执行。
"pushl %3\n\t"
"ret\n\t" /* restore eip */
将eip指向下一进程的代码继续执行。
以上代码为一个进程切换到一个已经运行的程序,如果是切换到一个新进程,代码会有些许不同,主要是新进程没有之前保存的栈帧信息,大体思路还是一样的。
总结
这次实验懂得了嵌入式汇编的基本用法,了解进程是如何切换的。