什麼是接口。
以生活中常見的插座爲例,咱們怎麼使用的呢?咱們只須要將插頭插入到插座內部,就能夠輕鬆地使用,咱們沒必要知道里面哪些是火線,哪些是零線。。。shell
因此這是一個抽象化的概念,它將功能封裝好,而後方便別人調用。
咱們要進行學習的有兩個安全
簡單來講,操做系統是鏈接上層用戶和操做系統軟件的函數
好比咱們鍵入一個hello命令,屏幕上顯示了hello,它方便了使用,屏蔽了細節。學習
咱們日常使用計算機經過以下方式。spa
咱們進行深層次的剖析,究竟哪些是操做系統給咱們的接口呢?操作系統
首先從命令行開始,從咱們在計算機中敲入命令,內部究竟發生了什麼呢?命令行
什麼是命令?
命令其實就是一段用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,這個是一個循環,不斷的讀取。要從操做系統裏面把這些消息一個一個的讀取出來。根據拿出來的消息來進行相應的操做,好比是鼠標按下的消息,執行相應的函數。
因此圖形界面也是沒有那麼複雜,主要仍是調用函數,應用程序經過函數的調用來獲取消息隊列中的消息,經過調用一些函數。來進行文件的讀寫功能。等等。
因此不管是命令行仍是圖形界面,都是一些普通的C代碼加上一些重要的函數。好比你要使用顯示器 就使用print函數,若果要使用鍵盤,就須要getMessage函數。等等
因此說操做系統就是提供這樣的重要的函數,這個就是操做系統的接口了,接口表現爲函數調用,又由系統提供,因此稱爲系統調用。
以前咱們提到的printf不算是一個接口,它實際上是包裝了一個write函數,咱們不須要徹底背下來這些接口,咱們須要知道去哪裏查。
POSIX,這個是統一的接口。
用戶程序調用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越小越好調用其餘的內存段。
當操做系統啓動的時候,head.s會針對內核態的代碼和內核態的數據創建GDT表象,對應的DPL就設置爲0,初始化好了以後,就進入到用戶態執行,當用戶態執行的時候,啓動一個用戶程序,好比咱們啓動一個PPT,它中的CPL就等於3,因此不能直接訪問內核態的數據。
硬件提供了「主動進入內核的方法」,對於Intel X86,那就是中斷指令int,固然只有一部分的指令能夠進入內核態
int指令將使Cs中CPL改成0,「進入內核」
這是用戶程序發起的調用內核代碼的惟一方式。
經過調用庫函數printf()展開write的宏,而後在調用write,包含int 0x80中斷,從而進入了內核態。
下面好好說一下這個宏都作了什麼事情
之前講過經過查GDT表來查詢跳轉到哪裏去執行,而int指令則要查詢IDT表
中斷的意思就是將停下來,跳到另外一個地方去執行,執行完再回來。
如今cs = 8 ip = system_call
以前的代碼jmp 0,8
中的8和這個8是同樣的,這個要跳到8,就是查詢GDT表,找到內核的代碼段。
_sys_call_table: