【操作系统学习】操作系统接口

接口

什么是接口。
以生活中常见的插座为例,我们怎么使用的呢?我们只需要将插头插入到插座内部,就可以轻松地使用,我们不必知道里面哪些是火线,哪些是零线。。。

所以这是一个抽象化的概念,它将功能封装好,然后方便别人调用。
我们要进行学习的有两个

  1. 什么是操作系统接口?
  2. 上层应用调用接口时,在内部是究竟怎么运作的?

操作系统接口

简单来说,操作系统是连接上层用户和操作系统软件的

比如我们键入一个hello命令,屏幕上显示了hello,它方便了使用,屏蔽了细节。

clipboard.png

我们平常使用计算机通过如下方式。

clipboard.png

我们进行深层次的剖析,究竟哪些是操作系统给我们的接口呢?

命令行

首先从命令行开始,从我们在计算机中敲入命令,内部究竟发生了什么呢?

什么是命令?
命令其实就是一段用c语言写的程序而已。当我在命令行输入如下命令./output "hello"(实际上没有这个命令,是自己实现的)
其实这个命令实际是我们写的这样一段程序:

#include <stdio.h>
int main(int argc,char * argv[]) {
    printf("ECHO:%S\n",argv[1]);

}

执行我们的命令就会在屏幕中打出:

ECHO:hello

将上面的程序经过下面的编译

gcc -o output output.c

然后就可以通过这个可执行文件来进行执行命令了。
那么敲入命令发生了什么呢?其实敲入的命令都是在shell里的。
其实shell也是一段程序:/bin/sh

在之前的学习过程中,知道了操作系统的启动,在启动之后,就会执行/bin/sh这个就是shell

int main(int argc,char* argv[]){
    char cmd[20];
    while(1) {
        scanf("%s",cmd);
        if(!fork()) {
            exec(cmd);
        }
        else {
            wait();
        }
    
    }

}

这个现在可以不用先完全搞懂。后面会学。
总结一下,我们从输入到输出,内部做了哪些事情。首先通过shell的函数,调用output,然后通过可执行文件,将这个结果输出。

图形按钮

当鼠标点下去的时候,通过中断,放到系统消息队列里面,应用程序要写一个getMessage,这个是一个循环,不断的读取。要从操作系统里面把这些消息一个一个的读取出来。根据拿出来的消息来进行相应的操作,比如是鼠标按下的消息,执行相应的函数。

所以图形界面也是没有那么复杂,主要还是调用函数,应用程序通过函数的调用来获取消息队列中的消息,通过调用一些函数。来进行文件的读写功能。等等。

clipboard.png

所以无论是命令行还是图形界面,都是一些普通的C代码加上一些重要的函数。比如你要使用显示器 就使用print函数,若果要使用键盘,就需要getMessage函数。等等
所以说操作系统就是提供这样的重要的函数,这个就是操作系统的接口了,接口表现为函数调用,又由系统提供,所以称为系统调用。

常见的接口

之前我们提到的printf不算是一个接口,它其实是包装了一个write函数,我们不需要完全背下来这些接口,我们需要知道去哪里查。

POSIX,这个是统一的接口。

系统调用的实现

实现一个whoami系统调用

用户程序调用whoami,一个字符串“lizhijun”放在操作系统中,取出来打印。

用户程序:

main(){
    whoami();
}
-------------------
内存中
whoami(){
    printf(100,8);
}

"lizhijun"

进入内核取出”lizhijun“,打印出来。
思考一个问题,为什么我写的用户程序,一定要通过whoami()来获取呢?这些都存在内存中,为什么不可以直接调用printf(100,8);来直接打印出来呢?

同理应用程序在内存中,操作系统也在内存中,应用程序访问操作系统提供的功能,为什么不能直接“跳”进去?

答案是不允许的。
不能随意的调用数据,不能随意的jmp。如果可以的话,可以看到root的密码,可以修改它,可以通过显存看到别人word的内容。
这是相当危险的!

如何实现这种安全的系统

要将内核程序和用户程序隔离!要区分内核态和用户态,需要处理器硬件的实现。
处理器将内存割了很多区域,分为用户态和内核态。在内存中叫做用户段和内核段。处于用户态的程序不能使用内核段的内存。

DPL是用来描述目标内存段的特权级,上面我们所说的whoami()就是一个目标内存段,通俗的理解为是要访问的目标段。操作系统初始化时,硬件设置成0表示内核态,3是用户态。实际上这个DPL就初始化在GDT表中,等于0

也就是说head.s在初始化GDT表的时候,就把DPL置为0。

RPL是当前的特权级,这个取决于你执行的是什么指令,如果我们执行的是上面所说的那个main()函数的话,需要CS:IP来确定指令所在的地址,这里面的CS的最低两位,就代表着这个内存段的特权级。

所以要检查DPL是不是大于CPL,也就是说CPL越小越好调用其他的内存段。

clipboard.png

总结一下:

当操作系统启动的时候,head.s会针对内核态的代码和内核态的数据建立GDT表象,对应的DPL就设置为0,初始化好了之后,就进入到用户态执行,当用户态执行的时候,启动一个用户程序,比如我们启动一个PPT,它中的CPL就等于3,所以不能直接访问内核态的数据。

我们应该怎么进入内核态

硬件提供了“主动进入内核的方法”,对于Intel X86,那就是中断指令int,当然只有一部分的指令可以进入内核态
int指令将使Cs中CPL改为0,“进入内核”
这是用户程序发起的调用内核代码的唯一方式。

clipboard.png

通过调用库函数printf()展开write的宏,然后在调用write,包含int 0x80中断,从而进入了内核态。

下面好好说一下这个宏都做了什么事情

clipboard.png

int0x80做了什么??

以前讲过通过查GDT表来查询跳转到哪里去执行,而int指令则要查询IDT表
中断的意思就是将停下来,跳到另一个地方去执行,执行完再回来。
clipboard.png

现在cs = 8 ip = system_call
之前的代码jmp 0,8中的8和这个8是一样的,这个要跳到8,就是查询GDT表,找到内核的代码段。

System_call要干的事情

clipboard.png

_sys_call_table:

clipboard.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值