2013-06-20 220 views
7

我很困惑內核和用戶空間的結構以及佔用哪些內存部分。 我的電流(可能是錯誤的)的理解是這樣的:Linux內核空間和用戶空間

  1. 創建一個進程,該進程的虛擬存儲器被分成一個用戶空間和內核空間區域,其中在用戶空間區域包含數據,代碼,堆棧,堆等,內核空間區域包含諸如進程和內核代碼的頁表等。我不確定內核代碼是什麼......驅動程序代碼或類似的東西?

  2. 另外,系統調用表是否總是映射到進程的內核空間中的同一個區域? (是否說「過程的內核空間」是正確的?

  3. 如果我編寫自己的驅動程序/模塊並插入它,那麼驅動程序代碼會自動複製到每個新進程的內核空間所創建的嗎?如果不是......究竟是如何工作的呢?

預先感謝任何輸入,文學/鏈接,可以幫助澄清我的問題是好的,以及。

乾杯, 磚

回答

27

您的總體想法大部分都是正確的,但要做出調整:整個機器只有一個「內核空間」,所有進程都共享它。

當進程處於活動狀態時,它可以在「用戶模式」或「內核模式」下運行。

在用戶模式下,CPU執行的指令位於內存映射的用戶空間一側。該程序正在運行自己的代碼或來自用戶空間庫的代碼。在用戶模式下,一個進程的能力有限。 CPU中有一個標誌,告訴它不允許使用特權指令,而內核內存雖然存在於進程的內存映射中,但是無法訪問。 (你不希望讓任何程序只讀寫內核的內存 - 所有的安全性都將消失。)

當一個進程想要執行某些操作而不是在自己的(用戶空間)虛擬內存中移動數據時例如打開一個文件,它必須進行系統調用。每個CPU體系結構都有自己獨特的使系統調用的獨特方法,但它們都歸結爲:一個神奇的指令被執行,CPU打開「特權模式」標誌,並跳轉到內核空間中的特殊地址,「系統調用入口點」。

現在該進程正在內核模式下運行。正在執行的指令位於內核內存中,並且可以讀取和寫入他們想要的任何內存。內核檢查進程剛剛做出的請求並決定如何處理它。

open例如,內核接收到對應於的int open(const char *filename, int flags[, int mode])參數2個或3個參數。第一個參數提供了內核空間何時需要訪問用戶空間的示例。你說open("foo", O_RDONLY)所以字符串"foo"是用戶空間中程序的一部分。系統調用機制只傳遞一個指針,而不是一個字符串,所以內核必須從用戶內存中讀取字符串。

要查找請求的文件,內核可以諮詢文件系統驅動程序(找出文件的位置)並阻止設備驅動程序(從磁盤加載必要的塊)或網絡設備驅動程序和協議(加載文件來自遠程源)。所有這些東西都是內核的一部分,即在內核空間中,而不管它們是內置還是作爲模塊加載。

如果請求不能立即滿足,內核可以將進程睡眠。這意味着該進程將從CPU中取出,直到從磁盤或網絡收到響應。另一個流程現在可能有機會運行。稍後,當響應進入時,您的進程再次開始運行(仍處於內核模式)。現在找到該文件,系統調用可以完成(檢查權限,創建文件描述符)並返回到用戶空間。

返回用戶空間是一件簡單的事情:將CPU置回非特權模式,並將寄存器恢復爲用戶 - >內核轉換之前的狀態,指令指針指向magic syscall指令之後的指令。

另外的系統調用,還有其他的東西,可以從用戶模式導致過渡到內核模式,包括:

  1. 頁面錯誤 - 如果您的進程訪問沒有物理地址的虛擬內存地址分配給它,CPU進入內核模式並跳轉到頁錯誤處理程序。然後內核決定虛擬地址是否有效,它會創建一個物理頁面並在其停止的用戶空間中恢復該進程,或者發送一個SIGSEGV。
  2. 中斷 - 一些硬件(網絡,硬盤,串行端口等)通知需要注意它的CPU。 CPU進入內核模式並跳轉到一個處理程序,內核對它作出響應,然後恢復中斷之前正在運行的用戶空間進程。

加載模塊是通過系統調用來完成的,該系統調用會要求內核將模塊的代碼和數據複製到內核空間並在內核模式下運行其初始化代碼。

這是很長,所以我停止。我希望以用戶內核轉換爲重點的演練已經提供了足夠的例子來鞏固這個想法。

2

有沒有內核空間區域在進程的虛擬內存映射中。虛擬內存映射包含:文本,bss,數據,堆,加載的程序和共享庫的堆棧。在Linux上,例如,您可以檢查任何用戶空間進程的/ proc/$ PID/maps。

當用戶空間進程通過系統調用訪問某些內核域代碼時,代表該進程在其堆棧中執行內核代碼。很明顯,從系統調用返回後,所有內核/驅動程序代碼都將不在堆棧中。爲了更清楚地說明,如果在某一時刻,某個部分的內核代碼沒有被任何進程使用,它將不會成爲任何進程的虛擬內存映射的一部分。

如果您使用Linux,我會推薦Robert Love的「Linux內核開發」一書。

相關問題