【操做系統學習】操做系統接口

接口

什麼是接口。
以生活中常見的插座爲例,咱們怎麼使用的呢?咱們只須要將插頭插入到插座內部,就能夠輕鬆地使用,咱們沒必要知道里面哪些是火線,哪些是零線。。。shell

因此這是一個抽象化的概念,它將功能封裝好,而後方便別人調用。
咱們要進行學習的有兩個安全

  1. 什麼是操做系統接口?
  2. 上層應用調用接口時,在內部是究竟怎麼運做的?

操做系統接口

簡單來講,操做系統是鏈接上層用戶和操做系統軟件的函數

好比咱們鍵入一個hello命令,屏幕上顯示了hello,它方便了使用,屏蔽了細節。學習

clipboard.png

咱們日常使用計算機經過以下方式。spa

clipboard.png

咱們進行深層次的剖析,究竟哪些是操做系統給咱們的接口呢?操作系統

命令行

首先從命令行開始,從咱們在計算機中敲入命令,內部究竟發生了什麼呢?命令行

什麼是命令?
命令其實就是一段用c語言寫的程序而已。當我在命令行輸入以下命令./output "hello"(實際上沒有這個命令,是本身實現的)
其實這個命令實際是咱們寫的這樣一段程序:code

#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

相關文章
相關標籤/搜索