完成一个简单的时间片轮转多道程序内核代码(李鹏举)

Linux操作系统是如何工作并看时间片轮转多道程序内核代码

攥写人:李鹏举  学号:20132201

( *原创作品转载请注明出处*)

( 学习课程:《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 )

一、计算机是如何工作的

1.1 计算机的三个法宝

存储程序计算机、函数调用堆栈、中断机制。

堆栈是C语言程序运行时必须记录调用路径和参数的空间。(函数调用框架、传递参数、保存返回地址、提供局部变量空间)

1.2 深入理解函数堆栈

(1)push栈顶减少4个字节

pop栈顶增加4个字节

ebp在C语言中用作记录当前函数调用基址

(2)其他关键寄存器:

1、堆栈用到的寄存器

  1. esp,指向栈顶
  2. ebp,指向栈底,在C语言中用作记录当前函数调用基址。

2、EIP寄存器

cs:eip:总是指向下一条的指令地址

顺序执行:总是指向地址连续的下一条指令

跳转/分支:cs : eip的值会根据程序需要被修改

3、1 C代码中嵌入汇编代码的写法

完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第1张图片  完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第2张图片

汇编代码模板

完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第3张图片

具体来讲就是:

寄存器前双%                   例子:movl $3,%%ebp;

%加数字,代表代码末的输出或输入   例子:addl %1,%%eax;    

                 :"d"(val1)     /*d代表edx寄存器*/

                 :"c"(val2)      /*c代表ecx寄存器*/

                即为把val2赋给eax

二、实验要求:

完成一个简单的时间片轮转多道程序内核代码,代码见视频中或从mykernel找。

mykernel实验指导(操作系统是如何工作的)

运行并分析一个精简的操作系统内核,理解操作系统是如何工作的

使用实验楼的虚拟机打开shell
cd LinuxKernel/linux-3.9.4
qemu -kernel arch/x86/boot/bzImage
然后cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

使用自己的Linux系统环境搭建过程参见mykernel,其中也可以找到一个简单的时间片轮转多道程序内核代码

三、实验过程:

首先通过:cd LinuxKernel/linux-3.9.4   qemu -kernel arch/x86/boot/bzImage

完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第4张图片

 

看到了程序的执行结果:

完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第5张图片

之后通过cd mykernel 您可以看到qemu窗口输出的内容的代码mymain.c和myinterrupt.c

完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第6张图片

四、操作系统内核源代码的分析

首先是mypcb.c代码:

 

这个代码的目的是定义一个进程控制块。先定义了一个Thread来存储ip和sp,也就是用于eip和esp的保存。PCB中定义了进程管理相关的数据结构。最后的函数my_schedule表示的是调度器。

 接下来是mymain.c代码:

 完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第7张图片

先是include mypcb。声明了一个数组task,然后声明了当前task的一个指针,第20行处定义了一个标志,用来判断是否需要调度。然后定义了一个函数my_process。

 完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第8张图片

my_start_kernel函数中先初始化一个进程0,第32行为定义进程0的入口为my_process,因为一开始系统里只有进程0,所以第34行代码表示的是pid的next还是指向自己。接下来就创建更多其他的进程,在初始化这些进程的时候可以直接把0号进程的代码拷贝过来,第41行表示每个进程都有自己的堆栈,然后把创建好的新进程放到进程列表的尾部,这样就完成了创建。

创建好了之后就可以开始执行0号进程,第48行处到之后的几行代码表示的是一段嵌入式汇编代码。其中的%0表示的是参数thread.ip,%1表示的是参数thread.sp。第49行表示的就是把参数thread.sp放到esp中;接下来push %1,又因为当前栈为空,esp=ebp,所以等价于push ebp;然后push thread.ip;ret等价于pop thread.ip;最后pop ebp。

ret之后0号进程就正式启动了。

 函数my_process定义所有进程的工作。这个函数里面定义了一个循环,if语句表示循环1000万次才有机会判断是否需要调度。这是一个主动调度的机制。

最后是myinterrupt.c的代码:

 

接着是一个函数my_timer_handler,用于设置时间片的大小,时间片用完时设置一下调度标志。当时钟中断发生1000次,并且my_need_sched!=1时,把my_need_sched赋为1。因为当进程发现my_need_sched=1时,就会执行my_schedule。

 完成一个简单的时间片轮转多道程序内核代码(李鹏举)_第9张图片

If语句表示task为空,即发生错误时返回。第52行开始介绍my_scheduel的工作,先把当前进程的下一个进程赋给next,当前进程为prev。

第54行表示如果下一个进程的状态是正在执行的话,就运用if语句中的代码表示的方法来切换进程,这些代码为嵌入式汇编代码,与mymain.c代码中的相似。

%0表示prev->thread.sp,%1表示prev->thread.ip,%2表示next->thread.sp,%3表示next->thread.ip。push ebp为保存当前进程的ebp;然后保存当前进程的esp;把下一个进程的sp放到esp中;接下来保存eip,$1表示后面的标号1:的位置;然后把下一个进程的eip push到栈里面。

ret之后下一个进程就开始执行了。这是进程切换的关键代码。

 

与上一段代码不同的是如果下一个进程为新进程时,就运用else中的这一段代码。首先将这个进程置为运行时状态,将这个进程作为当前正在执行的进程。

五、实验总结:

本次实验首先总结了一下linux操作系统的工作方式,并且了解到了计算机工作的三大法宝,而且了解了堆栈的工作方式和如何在C语言中嵌套汇编语言的方法。

懂得了如何在Linux系统中查看相应的代码,然后进行了一段时间片轮转的操作系统内核代码的分析,跟着学习视频一步步的进行学习,虽然这样的分析挺难的

但是还是成功的完成了。

你可能感兴趣的:(完成一个简单的时间片轮转多道程序内核代码(李鹏举))