操作系统是如何工作的?
注:作者:臧文君,原创作品转载请注明出处,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、函数调用堆栈
1、计算机的三个法宝:存储程序计算机,函数调用堆栈和中断机制。
2、堆栈
3、堆栈寄存器和堆栈操作
4、函数调用堆栈的框架
call指令:将eip中下一条指令的地址A保存在栈顶,设置eip指向被调用程序代码开始处。
ret指令:将地址A恢复到eip中。
5、举例分析函数调用堆栈
使用gcc -g命令生成test.c的可执行文件test,
然后使用objdump -S命令获得test的反汇编代码。
6、函数参数的存储和调用传递方式
将参数传递给p2函数:
先用变址寻址的方式,将y、x的值存入堆栈中,push的是局部变量,再call,存入cs:eip,push ebp。
add $0x8,%esp的目的是将存储x、y的空间清除,有压栈必有出栈!
函数的返回值通过eax寄存器传递,mow %eax,0xfffffffc(%ebp)
7、观察局部变量的存储机制
sub $0x18,%esp的命令是在堆栈中预留出0x18字节的一段空间,用来存储局部变量。
总结:
分析:
二、借助Linux内核部分源代码模拟存储程序计算机工作模型及时钟中断
1、利用mykernel实验模拟计算机硬件平台
一个程序切换到另一个程序:
当一个中断信号发生时,CPU把当前的eip、esp、ebp都压栈到内核堆栈中,把eip指向中断处理程序的入口,执行中断处理程序。
由CPU和内核代码共同实现了保存现场和恢复现场。
2、实验
my_start_kernel函数是操作系统的入口
my_timer_handler时钟中断程序
三、在mykernel基础上构造一个简单的操作系统内核
1、C代码中嵌入汇编代码的写法
例:
%1指val1,%2指val2,“c”(val1)表示val1的值存在ecx寄存器中。
=m表示写到内存中去
movl %%eax,%0表示把eax的值直接放到内存的变量val3中去
练习:
输出结果是:0 1(temp=0,output=1)
2、在mykernel基础上构造一个简单的操作系统内核
(1)mypcb.h
定义Thread用于存储eip、esp
PCB中定义进程的id、状态state、堆栈stack、入口entry,把进程用链表*next链起来
(2)mymain.c
初始化0号进程的数据结构
状态0表示正在运行,-1表示没有运行
fork more process创建更多的进程
%0表示第0号参数thread.ip
%1表示第1号参数thread.sp,d表示edx
push %1相当于push ebp,因为当前栈是空的,ebp=esp
ret之后0号进程正式启动
(3)myinterrupt.c
进程切换的关键代码:
操作系统的“两把剑”:中断上下文和进程上下文的切换。
切换到一个新进程的方法:
时间片设置小一些调度的更频繁。
总结:
这次课的主要内容是介绍操作系统是如何工作的,根据课程学习加上我的理解,我认为操作系统利用中断来进行进程的切换,当前进程触发另一个进程时,先将当前的eip、esp、ebp都压栈到内核堆栈中,再把eip指向中断处理程序的入口,执行中断处理程序。并且由CPU和内核代码共同实现保存现场和恢复现场。
实验:
1、输入命令cd LinuxKernel/linux-3.9.4和qemu -kernel arch/x86/boot/bzImage加载内核
2、输入命令cd mykernel,进入mymain.c,可以对时间进行修改
3、进入myinterrupt.c
4、添加mypcb.h头文件
5、修改mymain.c和myinterrupt.c,然后再运行,可以看到多进程切换运行