第二章 構造和運行模塊

  《1》 module_init ( xxx )  模塊在裝載到內核時調用,module_exit( xxx ) 模塊在被移除時調用。

  《2》 內核API中看到具有兩個下劃線的前綴(__)的函數名稱,具有這種名稱的函數通常是接口的底層組件,應謹慎使用。

  《3》 在構造內核模塊之前,應確保具備了正確版本的編譯器,模塊工具和其他必要的工具。內核文檔目錄中的Documentation/Changes文件列出了需要的工具版本。

  《4》 modprobe也用來將模塊裝入到內核中。它和insmod的區別在於,它會考慮要裝載是否引用了一些當前內核不存在的符號。如果有這類引用,modprobe會在當前模塊搜索路徑中查找定義了這些符號的其他模塊。如果modprobe找到了這些模塊(即要裝載的模塊所依賴的模塊),它會同時將這些模塊裝載到內核。在加載模塊失敗的時候,可以通過查看/var/log/messages或者系統配置使用的文件。

  《5》 針對內核版本的查看,在linux/version.h中相關的定義,這個頭文件自動包含於linux/module.h,並定義了下面的宏:


 UTS_RELEASE
           宏UTS_RELEASE擴展至爲一個描述內核版本的字符串,例如 “2.6.10”。

 LINUX_VERSION_CODE

           宏LINUX_VERSION_CODE擴展爲內核版本的二進制表示,版本發行號中的每一部分對應一個字節。例如,2.6.10對應的LINUX_VERSION_CODE是132618(即0x02060a)。使用這個宏,我們很容易確定正在使用的內核版本.

KERNEL_VERSION(major , minor , release)

           宏KERNEL_VERSION以組成版本號的三部分(三個整數)爲參數,創建整數的版本號。例如, KERNEL_VERSION(2 ,6 ,10)擴展爲132618.這個宏在我們需要將當前版本和一個已知的檢查點比較時非常有用。

   《6》 如果一個每模塊需要向其他模塊導出符號,則應該使用下面的宏。EXPORT_SYMBOL(name) ; EXPORT_SYMBOL_GPL(name) ; _GPL版本使得要導出的模塊只能被GPL許可證下的模塊使用。

   《7》 所有模塊代碼都需要包含這兩行代碼:

           #include <linux/module.h>  包含有可裝載模塊需要的大量符號和函數定義。

           #include <linux/init.h>          包含init.h的目的是指定初始化和清除函數。

           大部分模塊還包括moduleparam.h頭文件,這樣可以在裝載模塊時向模塊傳遞參數。

   《8》  雖然不是嚴格要求模塊代碼使用許可證,但還是需要考慮使用的,例如:MODULE_LECENSE(" GPL") ; 內核可以識別的許可證有“GPL”(任一版本的GNU通用公關許可證),“GPL v2”(GPL版本2), “GPL and additional rights ”(GPL及附加權利) “,” Dual BSD/GPL (GPL雙重許可證)“,”Dual MPL/GPL(MPL/GPL雙重許可證)“ 以及 ”Proprietary(專有)的“,沒有顯示標記爲上述可識別許可證,則會被假定是專有的,而內核轉載這種內核就會被"污染"。

   《9》 模塊中可以包含的其他描述性定義包括MODULE_AUTHOR(描述模塊作者),MODULE_DESCRIPTION(用來說明模塊用途的簡短描述),MODULE_VERSION(代碼修訂號;有關版本字符串的創建慣例,參考<linux/module.h>中的註釋),MODULE_ALIAS(模塊的別名)以及MODULE_DEVICE_TABLE(告訴用戶空間模塊所支持的設備)。

   《10》模塊初始化函數通常如下:

              /*__=2個_*/

               static int  __init initialization_function(void)   _ _ init 給內核暗示,在模塊被裝載之後,模塊裝載器就會將初始化函數扔掉,釋放內存。 

               {

                     /* 初始化代碼*/

               }

              module_init(initialization_function) ;

              static void  __exit   cleanup_function(void)

              {

                    /* 這裏是清除代碼*/

             }

             module_exit(cleanup_function);                          //幫助內核找到模塊的清除函數是必須的

            清除函數沒有返回值, _ _exit 修飾詞標記該代碼僅用於模塊卸載, 這樣的模塊只能在卸載或者關閉時被調用,其他的任何用法都是錯誤的。

           《11》當我們在內核中註冊設施時,要時刻銘記註冊可能會失敗,當註冊失敗的時候,我們要撤銷之前的任何註冊工作。

                       示例:

                    int  __init  my_init_function (void)

                     {

                          int err;

                           err = register_this(ptr1 , "skull");

                           if(err)   goto  fail_this;

                            err = register_that(ptr2 , "skull");

                           if(err)  goto fail_that;

                           err = register_those(ptr3 , "skull");

                          if(err)  goto fail_those;


                         return 0 ; /*success*/


                         fail_those: unregister_that(ptr2 , "skull");

                         fail_that :  unregister_this(ptr1 , "skull");

                         fail_this :  return err;

                    }

                    不支持goto的使用的人,就是記錄任何成功註冊的措施,然後再出錯的時候調用模塊清除函數。

                    顯然,清除函數需要撤銷初始化函數所註冊的所有設施,並且在習慣上(但不是必須的),以相反於註冊的順序撤銷設施:

                   void   __exit   my_cleanup_function(void)

                  {

                          unregister_those(ptr3 , “skull”);

                          unregister_that(ptr2 , “skull”);

                          unregister_this(ptr1, skull);

                          return ;

                 }

           《12》可以再insmod 或 modprobe 命令加載模塊的時候傳人蔘數,參數必須使用module_param宏來聲明,這個宏在moduleparam.h中定義。這個宏必須是放在任何函數之外, 通常是源文件的頭部。

                 主體的部分就是:  static char  *whom = “world” ;

                                                    static int  howmany = 1 ;

                                                    module_param (howmany , int , S_IRUGO) ;

                                                    module_param (whom , charp , S_IRUGO) ;

                   使用的命令比如: insmod  hellop  howmany=10  whom=“Mom” 

                    內核所能支持的模塊參數類型如下: 

                     bool 

                     invbool   /* 布爾值(取true 或 false ), 關聯的變量應該是 int 型。 invbool 類型反轉其值, 也就是說, true 值變成 false ,而false 變成 true 。*/

                     charp     /*字符指針值。內核會爲用戶提供的字符串分配內存, 並相應設置指針。*/

                     int   long   short   uint   ulong    ushort   具有不同長度的基本整數值。以u開頭的類型用於無符號值。

                     模塊裝載器也支持數組參數, 要聲明數組參數需要使用下面的宏:

                     module_param_array(name , type , num , perm);   /*name  數組名稱  type 數組類型  num 爲用戶提供的值得個數  perm 常見的訪問許可值。具體的細節請參閱moduleparam.h 文件*/  module_param 中最後一個參數是訪問許可值, 我們應使用<linux / stat . h> 中存在的定義。這個值用來控制誰能夠訪問sysfs中對模塊參數的表述。如果perm被設置成0 ,就不會有對應的sysfs入口項 ; 否則參數會在 /sys/module 中出現,並設置爲給定的訪問許可。如果對參數使用S_IRUGO , 則任何人均可讀取該參數, 但不能修改; S_IRUGO | S_IWUSR  允許root用戶修改該參數。 



發佈了28 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章