为何要有操作系统接口
为了使用户不能随时随地的访问内存中内核部分的数据(使用jmp,mov等指令),需要提供给用户操作内核的方法。
内核程序和用户程序隔离
通过硬件将此时的状态分为内核态,用户态。内存分为内核段,用户段。
内核态可以访问任何数据,用户态不能访问内核数据
通过CS,DS两个段寄存器的信息来区分此时的状态
DPL:目标内存段的特权级->在GDT表中,GDT表中用来描述一段内存,操作系统初始化时,就把操作系统内存段的DPL制成0
CPL:当前内存段的特权级
CS:IP是当前指令,用CS的最低两位来表示程序执行在什么态,0是内核态,3是用户态
在操作系统启动时,内核段的DPL被置为0,在用户态进行系统调用,此时CPL为3,无法进入内核
硬件提供的主动进入内核的方法
中断指令int:int指令将CS中的CPL改成0,进入内核,中断是进入内核的唯一方法。
系统调用的核心:
- 用户程序中包含一段包含int指令的代码
- 操作系统写中断处理,获取想要调程序的编号
- 操作系统根据编号执行相应代码
一个系统调用实际上是通过syscall宏展开,将系统调用号放入eax中(eax同样也存放返回值),其他通用寄存器存放参数,然后调用int 0x80进入系统内核。
int 0x80中断处理
首先在操作系统初始化时,会通过set_system_gate函数将0x80中断的中断处理函数设置成system_call(就是初始化IDT表),IDT表中的DPL为3(这就是为什么在用户态可以调用该指令的原因),int 0x80中断会转去IDT表进行查找,找到中断处理函数的位置,将CS=8(CPL=0), IP=&system_call,转去执行,此时就进入了内核态,在系统调用返回的时候又会把CPL置为3。
system_call
根据系统调用号,查找系统调用表,找到对应的处理函数后执行。