Kernel Mode 與 User Mode 的概念

為什麼要有 Kernel Mode 與 User Mode?

首先我們先從為什麼要有 Kernel Mode 與 User Mode 談起。大家桌機或者是筆電用的作業系統,不論是 Windows 或者是 Linux,都可以 在同一個時間執行很多程式。 然而,當我們可以執行多個程式,我們如何確保二個程式不會相互干 擾?我們如何確保 A 使用者的程式不會更動 B 使用者程式的變數? 我們如何確保一個使用者不會佔著資源不放手(CPU、RAM…)?我們如何確保一個使用者的程式不會惡意的更動作業系統內部的資料結構以竊取更多的資源?我們如何確保硬體可以被正確地操作?

為了避免一個使用者的程式修改其他使用者的程式甚至是系統核心, 並且更進一步,讓作業系統可以壟斷所有的硬體資源,大部分的機器(或者 CPU)至少會有二個執行特權(privilege):Kernel mode (又稱 System mode) 與 User mode。

以 x86 為例:一般是使用 ring 0 做為 Kernel mode,ring 0 擁有最 多的特權,可以直接操縱所有的硬體,包括可以存取所有的實體記憶體 位址、處理鍵盤中斷..等;而 User mode 的部分,一般是使用 ring 3 做為 User mode,不但所有存取記憶體的行為都會有邊界檢查(用硬體 實作的,所以很快),而且很多 ring 0 專用的指令也都不能執行,例如:在 User mode 你就不能執行關機指令。 以上廢話這麼多,看不懂沒有關係,反正 OS 會再學一次,現在只要 記住以下三點就可以了:

1. 之所以要有 Kernel mode 和 User mode 之分,是因為我們希望作業系統可以壟斷所有的硬體操作,讓一般的程式不能亂搞。

2. Kernel mode 就是萬能的,只要是 CPU 能管的硬體,Kernel mode 的程式就可以透過 machine code 來操作該硬體。

3. User mode 基本上就是「受限」的模式。除了一些沒有傷害的行為之外什麼都不能做。

從 Kernel Mode 到 User Mode

如果 Kernel mode 可以操作硬體,那麼在 User mode 執行的指令如何執行一些需要特權的指令呢?例如:關機需要特權、寫入檔案需要特權、輸入輸出要特權、另外多要更多記憶體空間也要特權,沒有特權的 User mode 程序(process)要怎麼做這些工作呢?

這時我們就要使用作業系統的 System call。不過在討論 System call 之前,請容我先介紹中斷(或者例外)的概念,因為他和 System call 息息相關。

…..

================ ================ ================ ================

此文章為轉貼,想閱讀詳細內容請參考原文

文章來源:Link

================ ================ ================ ================

軟體中斷

當然,事實上不是只有硬體能產生中斷,我們也可以透過 instruction來觸發中斷,我們稱之為軟體中斷。在不同的機器上,我們對能產生軟體中斷的指令也有不同的稱呼,在 x86 我們就是使用 int,在 mips就是使用 syscall,當然還有一些機器是叫做 trap。而軟體中斷就是 System Call 可以從 User mode 跳到 Kernel mode的祕密。一般的作業系統都會提供一個用 Assembly 寫的,但是可以和 C object file 連結在一起的函式庫。為了可以和 C object file 連結在一起,這個 Assembly 寫的函式庫會符合一些調用規範(Calling Convention),以便和 C 的函式呼叫銜接在一起。

還記得在組合語言課堂中所學到的 Function call 與 Stack 嗎?在 Jump 到一個函式之前,我們必須先把引數(argument) 等等推入堆疊,再呼叫 Jump 指令跳到該函式。對於 C compiler 而言,他們也要做類似的事情,當 Compiler 看到以下的函式:


extern void logan_write(void const *, int);
int main()
{
logan_writes("hello world\n", 12);
}

其中一種編譯結果就是:


main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $12, 4(%esp)
movl $.LC0, (%esp)
call logan_write
movl $0, %eax
leave
ret

ps. 當選用的 Calling Convention 不同,會產生不同的結果。參見wikipedia: x86 calling convention。

除此之外,Compiler 什麼都不會做。接下來是作業系統開發人員的工作。這部分就要使用組合語言來撰寫。這裡的函式必需設定
register 的值,然後觸發軟體中斷。

例如我自己亂寫的函式:(使用 GAS syntax 與 Linux System Call)


.globl logan_write
logan_write:
movl $4, %eax ; Linux 系統呼叫: Write
movl $1, %ebx ; File descriptor (stdout)
movl $LOGANSTR, %ecx ; 字串
movl $7, %edx ; 字串長度
int $0x80 ; 觸發軟體中斷 (進入作業系統)
movl $4, %eax
movl $1, %ebx
movl 4(%esp), %ecx
movl 8(%esp), %edx
int $0x80 ; 觸發軟體中斷 (進入作業系統)
ret

如同老師在上課所說的,在 MS-DOS 之中,如果要做系統呼叫,就必需設定好 register 之後使用 int 21 觸發軟體中斷,讓作業系統接手之後的工作。當然,作業系統接手之後,Privilege 就會從 User mode 晉升到 Kernel mode,進而讓沒有特權的程式可以執行被作業系統壟斷的一些指令。

最後,如果 Exception Handler 執行完畢,視中斷的種類,有些會return 到原來中斷發生前的同一個指令,有些會 return 到下一個
指令。當然,一旦所有的 Exception Handler 執行完畢,特權會從Kernel mode 降回 User mode,因此在 User mode 執行的程式是無法用 System Call API 之外的方法得到 Kernel mode 的執行機會。

================ ================ ================ ================

此文章為轉貼,想閱讀詳細內容請參考原文

文章來源:Link

================ ================ ================ ================

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s