前言
一个本硕双非的小菜鸡,备战24年秋招,计划学习操作系统并完成6.0S81,加油!
本文总结自B站【哈工大】操作系统 李治军(全32讲)
老师课程讲的非常好,感谢
【哈工大】操作系统 李治军(全32讲)
系统调用的实现
操作系统在内存中,应用程序也在内存中,应用程序想访问操作系统的功能为什么不能直接访问?
如果能的话安全性被破坏。
系统调用就是提供一种能够进入内核中的手段。
通过硬件设计将内核程序和用户程序隔离。把内存隔成了用户态和核心态,对应内核段和用户段。内核段只能在核心态中运行。
DPL表示目标内存段的特权级,CPL表示当前特权级。等级已然规定好了,0代表内核态,3为用户态。系统初始化dps表的时候就已经置为0了。
每次访问的时候都要看一下当前特权级和目标访问的特权级,只有当前的特权级大于等于目标的特权级,指令才能被允许执行。
硬件也提供了主动进入内核的方法:中断。
int 0x80,这条中断指令才能进入
展开一段包含init中断的汇编代码,因为init中断是进入内核的唯一方式,所以需要包含一段需要展开成这一段的代码,而这段代码是需要靠宏来展开的。系统调用就从这个宏开始。(_syscall3)
这里展开用的是内切汇编:“=a(res):”是输出,=a就是ex,将来要把ex置给res,ex要放的是返回值,不填代表默认 “”(_NR##name*)是输入,NRname置给ex。*
实际上就是把一个数字置给ex,这个数字就叫系统调用号(因为都是从0x80进入到这个系统中,例如open,read等, 就靠这个区别)
int指令也是一样,查idt表。根据idt表取出中断处理函数,要转到哪里去执行,处理函数处理完了再回来。int 0x80工作完成。
把表的低四位和高四位分别贴上ex和edx,ex与edx已经组装好了。并且把DPL组装为3
这也是为什么只有0x80才能进入内核,因为此时DPL故意设置为3
用段和偏移设置成pc,cs为8,ip=system_call
为什么cs为8:因为cs最后对应的CPL为0,cs的最后两位就是CPL。
为了再次执行中断处理的时候,特权级为0。
完整的故事:初始化的时候0x80中断的DPL设置为3,故意让此时的CPL为3的用户代码进来,一旦进来就设置成0了,就变为内核。
保护模式下是根据cs查表得到段基址,然后加上ip来确定物理内存地址的,用户态下的指令的cs最后两位都是1(cpl的值就是这两位),如果想跳转到其他代码段执行就需要先查表和目标表项的dpl进行对比。
_sys_call_table是一个函数指针形成的表。
通过中断进入的内核程序,然后通过call _sys_call_table这一指令调用了系统调用