一、什么是操作系统接口(OS Interface)
1、上层应用到操作系统——接口
用户是怎么使用计算机的:
命令行、图形按钮、应用程序等等
命令行:在用户敲入命令后,在shell(/bin/sh)内部执行
应用程序:基于消息机制,可以通过消息机制来处理。硬件输入通过中断放入系统的消息队列,应用程序将这些消息队列从操作系统内核获取。通过获得的消息来确认要执行什么样的函数,来实现功能。
2、接口是通过重要函数来实现对系统的使用,也叫做系统调用(system_call)
3、POSIX(IEEE定义的标准接口)
二、系统调用的实现
1、为了安全,不能进入
- 内核中的信息能够随意被用户获取,或者修改是一件危险的事情
- whoami是一个系统调用函数,它的功能是取出某段内核中存放的一个字符串,打印显示在屏幕上
- 用户不能直接获取内核中的这段字符串比如mov取地址后获取,而需要通过whoami这个系统调用来获取——这是为了操作系统的安全
- 为此硬件将内存分为内核态和用户态……可能还有其他区域但是这里暂且不涉及。
- 内核态可以访问任何数据,而用户态不能访问内核数据。对于指令跳转也一样实现了隔离
2、硬件是如何实现内核态和用户态的隔离的
- 在内存中用段来存储,硬件使用了两个段寄存器(CS,DS)来实现这个功能,这两个段寄存器中存放了重要信息。DPL(目标特权级)和CPL(当前特权级)
- 特权等级用CS的最低两位表示:0是内核态,3是用户态
- 比如head.s在初始化gdt表项的时候会把里面的DPL全部置0,也就相当于把操作系统置为内核态;
- 我们都知道在x86框架的操作系统下面,处理器只认CS:IP,只执行段地址和偏移地址合成的物理地址指向的指令。在用户发出一道指令的时候,在计算机内部实际上就是执行了CS:IP指向的指令,这个时候在CS的低两位表示了特权级,只有当DPL≥CPL的时候,才能够访问内核态内存。
- 显然操作系统的DPL权限为0,而用户程序所生成的指令中CS:IP中存放的CPL等于3,就可以知道用户态为什么不能访问内核了。
3、进入内核的方法
- 对于intel x86,操作系统提供了进入内核的唯一方法——中断(int)int指令将CS中的CPL改成0
- 系统调用的核心
(1) 要有int指令的代码
(2) 操作系统接收到中断,开始中断处理,获取程序编号
(3) 操作系统根据编号处理相应代码 - 通过系统调用到int 0x80,这就是进入门内的钥匙了;
4、操作系统调用实现的细节
- 讲到这里用宏来展开一段汇编代码(C内键)大概意思应该是一个内嵌汇编,内容在花括号中。_syscall3()会执行int 0x80,将write()的参数代入,再来返回值处理。这个int是汇编中的中断指令,所以叫做C语言的内嵌汇编。
- int 0x80查询IDT表找到对应的中断处理函数来处理这个中断,处理完后再回来
- 详细的处理过程分析如下:
(1)其对应的sched_init(void)函数设置了一个中断处理门,这个中断处理门初始化了IDT表,让80能够进入到中断处理函数
(2)中断处理门是如何运行:
在这之后进入到了操作系统内核的代码段,cs=0x0008能够进入内核主要还是看CPL(此时的CPL=0,因为8的二进制为1000,最后两位为0),而偏移地址是system_call,这个cp指向的指令就是要执行内核中system_call的代码段。
(3)中断处理程序system_call做了什么:
它将ds和es设为0x10,也就是10进制的16,16是内核的数据段,存放着内核代码,从现在开始执行内核代码。
(4)怎么执行内核代码段的,还是通过地址查表:
_sys_call_table(,%eax,4)就是相应的系统调用处理函数入口,%eax存放着系统调用号,这里的4是四个字节,每个系统调用(函数)占四个字节,我理解查找表_sys_call_table偏移4*%eax个字节后的内容。
(5) 我们在sys_call_table这个指针表(数组)中对应的位置找到了sys_write - 最后,接口的故事就到此结束了,操作系统的故事还在继续。