Kernel Module實戰指南(二):內核模塊和應用程序的區別

原文地址:Kernel Module實戰指南(二):內核模塊和應用程序的區別算法

Introduction

你已經寫出了第一個內核模塊Hello World!有沒有發現內核模塊和應用程序寫法的不一樣?
下面我將從概念和原理上進行介紹,內核模塊和應用程序爲何不一樣。緩存

內核模塊和應用程序的區別

出入口

應用程序的入口始終是main()函數,而出口是main()函數的return。
內核模塊的入口是init_module(),而出口是cleanup_module()。架構

函數庫

應用程序能夠調用不少C標準庫中的函數,如printf()。這些函數都編譯到libc中,只有當你的代碼在編譯的連接階段時,纔會和libc中實際的函數地址綁定。
內核模塊則不一樣,內核中不存在標準庫,天然沒有相似printf()之類的函數。不過內核中提供了一些函數/符號,你能夠經過下面的命令查看:函數

$ cat /proc/kallsyms | grep printk
...
0000000000000000 T printk
0000000000000000 T printk_emit
...

全部內核中能夠用的函數/符號都在/proc/kallsyms,換句話說,你不能使用這裏以外的函數/符號。code

CPU執行模式

在Intel x86架構上中,有四種模式,也叫ring 0 - ring 3,模式之間的權限不一樣,這裏的權限指的是對硬件設備的操做,如讀寫內存,讀寫硬盤等。
Linux使用其中兩種模式,即內核模式/特權模式/supervisor mode/ring 0,以及用戶模式/非特權模式/user mode/ring 3。
應用程序跑的代碼,包括所調用的C標準庫,都是跑在用戶模式中。而內核模塊跑的代碼,都是跑在內核模式中。用戶模式想要進入內核模式,入口之一即是系統調用函數。內存

用戶態和內核態之間的交互

用戶態和內核態進行交互的方式之一,是上面咱們提到過系統調用函數。什麼是系統調用函數?你能夠簡單認爲,libc調用的下層函數,就是系統調用函數,如libc中open()的實現,最終須要調用系統調用函數__NR_open(),進入內核,在內核態中訪問硬盤,打開文件。
另外一種方式是設備驅動程序,Linux的設備驅動都存放在/dev下面,當用戶態程序和設備驅動交互時,設備驅動在內核態執行代碼邏輯,而後將結果返回給用戶態。get

設備驅動

查看硬盤驅動:it

$ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Jan 26 23:00 /dev/sda
brw-rw---- 1 root disk 8, 1 Jan 26 23:00 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jan 26 23:00 /dev/sda2
brw-rw---- 1 root disk 8, 3 Jan 26 23:00 /dev/sda3

若是你找不到sda,那麼你能夠查詢ls -l /dev/hda*。
這裏須要簡單介紹一下,列的含義。第一列的b,是block的意思,代碼這個設備是塊設備(對應的是c, char字符設備)。io

塊設備:存儲單位通常是固定大小的塊,支持隨機讀寫。對於讀寫請求有緩存,能夠選擇最佳的位置存儲。(有沒有想到硬盤的尋址算法?)
字符設備:存儲大小不定,存儲流式數據,通常不支持隨機讀寫,只支持順序讀寫。編譯

8的意思是,驅動的主版本號是8,這個主版本號是給內核看的。
後面的0-3的意思是,副版本號是0-3,這個副版本號是給設備驅動程序看的,內核不關心。
這裏只是拋磚迎玉,後面咱們再詳細介紹設備驅動。

Summary

咱們進一步深刻了內核模塊,介紹了內核模塊和應用程序的區別。雖然概念性內容偏多,但這倒是理解內核模塊的必經之路。

相關文章
相關標籤/搜索