歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> linux內核空間與用戶空間信息交互方法

linux內核空間與用戶空間信息交互方法

日期:2017/3/2 10:06:52   编辑:Linux內核

摘要:在進行設備驅動程序,內核功能模塊等系統級開發時,通常需要在內核和用戶程序之間交換信息。Linux提供了多種方法可以用來完成這些任務。本文總結了各種常用的信息交換方法,並用簡單的例子演示這些方法各自的特點及用法。其中有大家非常熟悉的方法,也有特殊條件下方可使用的手段。通過對比明確這些方法,可以加深我們對Linux內核的認識,更重要的是,可以讓我們更熟練駕御linux內核級的應用開發技術。

內核空間(kernel-space) VS 用戶空間(user-space)
作為一個Linux開發者,首先應該清楚內核空間和用戶空間的區別。關於這個話題,已經有很多相關資料,我們在這裡簡單描述如下:

現代的計算機體系結構中存儲管理通常都包含保護機制。提供保護的目的,是要避免系統中的一個任務訪問屬於另外的或屬於操作系統的存儲區域。如在IntelX86體系中,就提供了特權級這種保護機制,通過特權級別的區別來限制對存儲區域的訪問。 基於這種構架,Linux操作系統對自身進行了劃分:一部分核心軟件獨立於普通應用程序,運行在較高的特權級別上,(Linux使用Intel體系的特權級3來運行內核。)它們駐留在被保護的內存空間上,擁有訪問硬件設備的所有權限,Linux將此稱為內核空間。

相對的,其它部分被作為應用程序在用戶空間執行。它們只能看到允許它們使用的部分系統資源,並且不能使用某些特定的系統功能,不能直接訪問硬件,不能直接訪問內核空間,當然還有其他一些具體的使用限制。(Linux使用Intel體系的特權級0來運行用戶程序。)

從安全角度講將用戶空間和內核空間置於這種非對稱訪問機制下是很有效的,它能抵御惡意用戶的窺探,也能防止質量低劣的用戶程序的侵害,從而使系統運行得更穩定可靠。但是,如果像這樣完全不允許用戶程序訪問和使用內核空間的資源,那麼我們的系統就無法提供任何有意義的功能了。為了方便用戶程序使用在內核空間才能完全控制的資源,而又不違反上述的特權規定,從硬件體系結構本身到操作系統,都定義了標准的訪問界面。關於X86系統的細節,請查閱參考資料1

一般的硬件體系機構都提供一種“門”機制。“門”的含義是指在發生了特定事件的時候低特權的應用程序可以通過這些“門”進入高特權的內核空間。對於IntelX86體系來說,Linux操作系統正是利用了“系統門”這個硬件界面(通過調用int $0x80機器指令),構造了形形色色的系統調用作為軟件界面,為應用程序從用戶態陷入到內核態提供了通道。通過“系統調用”使用“系統門”並不需要特別的權限,但陷入到內核的具體位置卻不是隨意的,這個位置由“系統調用”來指定,有這樣的限制才能保證內核安全無虞。我們可以形象地描述這種機制:作為一個游客,你可以買票要求進入野生動物園,但你必須老老實實的坐在觀光車上,按照規定的路線觀光游覽。當然,不准下車,因為那樣太危險,不是讓你丟掉小命,就是讓你嚇壞了野生動物。

出於效率和代碼大小的考慮,內核程序不能使用標准庫函數(當然還有其它的顧慮,詳細原因請查閱參考資料2)因此內核開發不如用戶程序開發那麼方便。而且由於目前(linux2.6還沒正式發布)的內核是“非搶占”的,因此正在內核空間運行的進程是不會被其他進程取代的(除非該進程主動放棄CPU的控制,比如調用sleep(),schedule()等),所以無論是在進程上下文中(比如正在運行read系統調用),還是在中斷上下文(正在中斷服務程序中),內核程序都不能長時間占用CPU,否則其它程序將無法執行,只能等待。

內核空間和用戶空間的相互作用
現在,越來越多的應用程序需要編寫內核級和用戶級的程序來一起完成具體的任務,通常采用以下模式:首先,編寫內核服務程序利用內核空間提供的權限和服務來接收、處理和緩存數據;然後編寫用戶程序來和先前完成的內核服務程序交互,具體來說,可以利用用戶程序來配置內核服務程序的參數,提取內核服務程序提供的數據,當然,也可以向內核服務程序輸入待處理數據。

比較典型的應用包括: Netfilter(內核服務程序:防火牆)VS Iptable(用戶級程序:規則設置程序);IPSEC(內核服務程序:VPN協議部分)VS IKE(用戶級程序:vpn密鑰協商處理);當然還包括大量的設備驅動程序及相應的應用軟件。這些應用都是由內核級和用戶級程序通過相互交換信息來一起完成特定任務的。

信息交互方法
用戶程序和內核的信息交換是雙向的,也就是說既可以主動從用戶空間向內核空間發送信息,也可以從內核空間向用戶空間提交數據。當然,用戶程序也可以主動地從內核提取數據。下面我們就針對內核和用戶交互數據的方法做一總結、歸納。

信息交互按信息傳輸發起方可以分為用戶向內核傳送/提取數據和內核向用戶空間提交請求兩大類,先來說說:
由用戶級程序主動發起的信息交互。

用戶級程序主動發起的信息交互
A編寫自己的系統調用
從前文可以看出,系統調用是用戶級程序訪問內核最基本的方法。目前linux大致提供了二百多個標准的系統調用(參見內核代碼樹中的include/ asm-i386/unistd.h和arch/i386/kernel/entry.S文件),並且允許我們添加自己的系統調用來實現和內核的信息交換。比如我們希望建立一個系統調用日志系統,將所有的系統調用動作記錄下來,以便進行入侵檢測。此時,我們可以編寫一個內核服務程序。該程序負責收集所有的系統調用請求,並將這些調用信息記錄到在內核中自建的緩沖裡。我們無法在內核裡實現復雜的入侵檢測程序,因此必須將該緩沖裡的記錄提取到用戶空間。最直截了當的方法是自己編寫一個新系統調用實現這種提取緩沖數據的功能。當內核服務程序和新系統調用都實現後,我們就可以在用戶空間裡編寫用戶程序進行入侵檢測任務了,入侵檢測程序可以定時、輪訓或在需要的時候調用新系統調用從內核提取數據,然後進行入侵檢測了。

B編寫驅動程序
Linux/UNIX的一個特點就是把所有的東西都看作是文件(every thing is a file)。系統定義了簡潔完善的驅動程序界面,客戶程序可以用統一的方法透過這個界面和內核驅動程序交互。而大部分系統的使用者和開發者已經非常熟悉這種界面以及相應的開發流程了。

驅動程序運行於內核空間,用戶空間的應用程序通過文件系統中/dev/目錄下的一個文件來和它交互。這就是我們熟悉的那個文件操作流程:open() —— read() —— write() —— ioctl() —— close()。(需要注意的是也不是所有的內核驅動程序都是這個界面,網絡驅動程序和各種協議棧的使用就不大一致,比如說套接口編程雖然也有open()close()等概念,但它的內核實現以及外部使用方式都和普通驅動程序有很大差異。)關於這部分的編程細節,請查閱參考資料3、4。

Copyright © Linux教程網 All Rights Reserved