Linux內核設計與實現---模塊

模塊

  • 1 構建模塊
    • 放在內核源代碼樹中
    • 放在內核代碼外
  • 2 安裝模塊
  • 3 產生模塊依賴性
  • 4 載入模塊
  • 5 管理配置選項
  • 6 模塊參數
  • 7 導出符號表

Linux內核是模塊化組成的,它允許內核在運行時動態地向其中插入或從中刪除代碼。

與開發的內核核心子系統不同,模塊開發更接近編寫新的應用程序,因為至少要在模塊文件中具有入口點和出口點。

下面是hello_world內核模塊

#include  <linux/init.h>
#include  <linux/module.h>
#include <linux/kernel.h>static int hello_init(void)
{printk(KERN_ALERT "I bear a charmed life.\n");return 0;
}static void hello_exit(void)
{printk(KERN_ALERT "Out,out,brief candle !\n");
}module_init(hello_init);
module_exit(hello_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Shakespeare");

hello_init()函數是模塊的入口點,它通過module_init()注冊到系統中,在模塊裝載時被調用。調用module_init()實際上不是真正的函數調用,而是一個宏調用,它唯一的參數便是模塊的初始化函數。模塊的所有初始化函數必須符合下面的形式:

int my_init(void);

因為init函數通常不會被外部函數直接調用,所以不必導出該函數,故它可被標記為static類型。init函數會返回一個int型數據,如果初始化順利完成,那么它的返回值為0,失敗的話,返回一個非0值。

hello_exit()函數是模塊的出口函數,它由module_exit()注冊到系統,在模塊從內存卸載時,內核便會調用hello_exit()。在退出函數返回后,模塊就被卸載了。

退出函數必須符號以下形式:

void my_exit(void);

MODULE_LICENSE()宏用于指定模塊的版權,如果載入非GPL模塊到系統內存,則會在內核中設置被污染標志。MODULE_AUTHOR()宏指定代碼作者,完全是用作信息記錄目的。

1 構建模塊

在2.6內核中,由于采用了新的kbuild構建系統,現在構建模塊相比從前更加容易,構建過程中的第一步是決定在哪里管理模塊代碼,你可以把模塊源碼加入到內核源代碼樹中,也可以在內核源碼樹外維護構建模塊源碼。

放在內核源代碼樹中

最理想的情況莫過于模塊正式成為Linux內核的一部分,這樣就會被存放在內核源代碼樹中。

首先你要清楚你的模塊應該在內核源代碼樹中何處。設備驅動程序存放在內核源碼樹根目錄drivers/的子目錄下,在drivers內部,設備驅動文件被進一步細分。如字符設備存在于drivers/char/目錄下,而塊設備存放在drivers/block/目錄下,USB設備則存放在drivers/usb/目錄下。

假設你有一個字符設備,而且希望放在drivers/char/目錄下,那么你要注意,在該目錄下同時會存在大量的C源代碼文件和其他目錄。所以對于僅僅只有一兩個源文件的設備驅動程序,可以直接存放在該目錄下。如果驅動程序包含許多源文件和其他輔助文件,那么可以創建一個新子目錄。

假設你想創建自己代碼的子目錄,你的驅動程序是一個釣魚桿和計算機的接口,名為Fish Master XL 2000 Titanium,那么你應在drivers/char/目錄下建立一個名為fishing的子目錄。現在你需要項drivers/char/下的Makefile文件中添加一行。編輯drivers/char/Makefile加入:

obj-m += fishing/

這行編譯指令告訴模塊構建系統在編譯模塊時需要進入fishing/子目錄中。更可能發生的情況是,你的驅動程序的編譯取決于一個特殊配置選項,比如,可能的CONFIG_FISHING_POLE。如果這樣,你需要用下面的指針替代剛才那條指令:

obj-$(CONFIG_FISHING_POLE) += fishing/

最后,在drivers/char/fishing/下,需要添加一個新的Makefile文件,其中需要有下面這樣:

obj-m += fishing.o

此刻構建系統運行就將會進入fishing/目錄下,并且將fishing.c編譯為fishing.ko模塊,雖然拓展名是.o,但是模塊被編譯后的拓展名是.ko。
要是你的釣魚桿驅動程序編譯時有編譯選項,那么你可能需要這么來做:

obj-$(CONFIG_FISHING_POLE) += fishing.o

如果喜歡把源文件置于drivers/char/目錄下,并且不建立新目錄。那么你要做的便是將前面提到的行(也就是原來處于drivers/char/fishing/下你自己的Makefile中的)都加入到drivers/char/Makefile中。

開始編譯吧,運行內核構建過程,如果模塊編譯取決于配置選項,比如有CONFIG_FISHING_POLE約束,那么在編譯前首先要確保選項被允許。

放在內核代碼外

如果你喜歡脫離內核源代碼樹來維護和構建你的模塊,那么你要做的就是在你自己的源代碼樹目錄建立一個Makefile文件,它只需要一行指令:

obj-m := fishing.o

就可以把fishing.c編譯成fishing.ko。

模塊在內核內或內核外構建的最大區別 在于構建過程。當你的模塊在內核源代碼樹外時,你必須告訴make如何找到內核源代碼文件和基礎的Makefile文件。

make -C /kernel/sourece/location SUBDIRS=$PWD modules

/kernel/source/location是你以配置的內核源碼樹。

2 安裝模塊

編譯后的模塊將被裝入到目錄/lib/modules/version/kernel/下。比如,如果使用的是2.6.10內核,而且你將你的模塊源代碼直接放在drivers/char/下,那么編譯后的釣魚桿驅動程序的存放路徑是:/lib/modules/2.6.10/kernel/drivers/char/fishing.ko

下面的構建命令用來安裝編譯的模塊到合適的目錄下:

make modules_install

3 產生模塊依賴性

Linux模塊之間存在依賴性,也就是說釣魚模塊依賴魚餌模塊,那么當載入釣魚模塊時,魚餌模塊會被自動載入,這里需要的依賴信息必須事先生成。若想產生內核依賴關系的信息,root用戶可運行命令:

depmod

為了執行更快的更新操作,可以只為新模塊生成依賴信息,而不是生成所有的依賴關系,這時root用戶可運行命令:

depmod -A

模塊依賴關系信息存放在/lib/modules/version/modules.dep文件中

4 載入模塊

載入模塊最簡單的方法是通過insmod命令,這是個功能很有限的命令,它的作用就是請求內核載入你指定的模塊。insmod程序不執行任何依賴性分析或進一步的錯誤檢查,它用法簡單,以root運行命令:

insmod module

需要載入的模塊名稱由參數module指定,比如裝載釣魚桿模塊,那你就執行命令:

insmod fishing

卸載一個模塊,你可使用rmmod命令,同樣用root身份執行:

rmmod module

比如,rmmod fishing將卸載釣魚桿模塊。

系統為我們提供了一個更先進的工具modprobe,它提供了模塊依賴性分析,錯誤智能檢查,錯誤報告以及許多其他功能和選項,推薦用這個命令:

modprobe module [module parameters]

module指定需要載入的模塊名稱,后面的參數將在模塊加載時傳入內核。modprobe命令不但會加載指定的模塊,而且會自動加載任何它所依賴的有關模塊。所以說它是加載模塊的最佳技術。

modprobe命令也可用來從內核中卸載模塊,當然這也需要root身份運行。

modprobe -r modules

參數modules指定一個或多個需要卸載的模塊,與rmmod命令不同,modprobe也會卸載給定模塊所依賴的相關模塊,前提是這些相關模塊沒有被使用。

5 管理配置選項

2.6內核中新引入了kbuid系統,加入一個新配置選項是很容易的。你所需做的全部就是向Kconfig文件中添加一項,用于對應內核源碼樹。對驅動程序而言,Kconfig通常和源碼處于同一目錄。如果釣魚桿驅動程序子drivers/char/下,那么你便會發現drivers/char/Konfig同時存在。
如果你建立了一個新子目錄,而且也希望Kconfig文件存在于該目錄中的話,那么必須在一個已存在的Kconfig文件中將它引入

source "drivers/char/fishing/Kconfig"

可以很方便地在Kconfig文件中加入一個配置選項,請看釣魚桿模塊的選項如下所示:
在這里插入圖片描述
配置選項第一行定義了該選項所代表的配置文件,注意CONFIG_前綴不需要寫上。這個就是構建模塊時,在Makefile里加入的特殊配置選項CONFIG_FISHING_POLE。
第二行聲明選項類型為tristate,也就是說被編譯進內核(Y),也可作為模塊編譯(M),或干脆不編譯它(N),選Y,CONFIG_FISHING_POLE的值就是Y,依次類推。如果編譯選項代表的是一個系統功能,而不是一個模塊,那么編譯選項將用bool代替tristate,這說明它不允許被編譯成模塊。處于指令之后的引號內文件為該選項指定了名稱。
第三行指定了該選項的默認選擇,這里默認操作是不編譯它。

help指令是為該選項提供幫助文檔。

除了上述選項外,還存在其他選項。

6 模塊參數

Linux允許驅動程序聲明參數,從而用戶可以在系統啟動或者模塊裝載時再指定參數值,這些參數對于你的驅動程序屬于全局變量,模塊參數同時也將出現在sysfs文件系統中。
定義一個模塊參數可通過宏module_param()完成:

module_param(name,type,perm);

參數name既是用戶可見的參數名,也是模塊中存放模塊參數的變量名。參數type則存放參數的類型,最后一個參數perm指定了模塊在sysfs文件系統下對應文件的權限,該值可以是八進制格式,比如0666,或是S_Ifoo的定義形式,比如S_IRUGO|S_IWUSR,如果該值為0,則表示禁止所有的sysfs項。

上面的宏并沒有定義變量,你必須在使用該宏前進行變量定義。通常使用類似下面的語句完成定義。

static int allow_live_bait = 1;
module_param(allow_live_bait,bool,0666);

有可能模塊的外部參數名稱不同于它對應的內部變量名稱,這是就該使用宏module_param_named()定義了:

module_param_named(name,variable,type,perm);

參數name是外部可見的參數名稱,參數variable是參數對應的內部全局變量名稱。比如:

static unsigned int max_text = DEFAULT_MAX_LINE_TEST;
module_param_named(maximum_line_test,max_test,int ,0)

其他宏:

module_param_string(name,string,len,name);	/* 拷貝字符串到指定的字符數組 */
module_param_array(name,type,nump,perm);	/* 接受逗號分割的參數序列 */
module_param_array_named(name,array,type,nump,perm);	/* 將內部參數數組命名區別于外部參數 */

上述所有宏被定義在linux/moduleparam.h文件中。

7 導出符號表

模塊被載入后,就會動態連接到內核。注意,它與用戶空間中的動態連接庫類型,只有當被顯式導出后的外部函數,才可以被動態庫調用。在內核中,導出內核內核函數需要使用特殊的指令:
EXPORT_SYMBOL()和EXPORT_SYMBOL_GPL()。

導出的內核函數可以被模塊調用,而未導出的函數模塊則無法使用。導出的內核符號表被看做是導出的內核接口,甚至稱為內核API。

導出符號相當簡單,在聲明函數后緊跟上EXPORT_SYMBOL()指令就搞定了,比如:

int get_priate_beard_color(void)
{return pirate->beard->color;
}
EXPORT_SYMBOL(get_priate_beard_color);

假定get_priate_beard_color同時也定義在一個可訪問的文件中,那么任何模塊現在都可以訪問它。

有一些開發者希望自己的接口僅僅對GPL兼容的模塊可見,內核連接器使用MODULE_LICENSE()宏可滿足這個要求,如果你希望先前的函數僅僅對標記為GPL協議的模塊可見,那么你就需要用:

EXPORT_SYMBOL_GPL(get_priate_beard_color);

如果你的代碼被設置為模塊,那么就必須確保它被編譯為模塊時所用的全部接口已被導出,否則就會產生連接錯誤(而且模塊不能成功編譯)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379607.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379607.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379607.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JSTL技術

1&#xff0e;JSTL概述 JSTL&#xff08;JSP Standard Tag Library)&#xff0c;JSP標準標簽庫&#xff0c;可以嵌入在jsp頁面中使用標簽的形式完成業務邏輯等功能。jstl出現的目的同el一樣也是要代替jsp頁面中的腳本代碼。JSTL標準標準標簽庫有5個子庫&#xff0c;但隨著發展…

asinh函數_JavaScript中帶有示例的Math.asinh()方法

asinh函數JavaScript | Math.asinh()方法 (JavaScript | Math.asinh() Method) Math.asinh() is a function in math library of JavaScript that is used to find the value of hyperbolic arc-sine of a number. Math.asinh()是JavaScript數學庫中的函數&#xff0c;用于查找…

使用PHP創建一個REST API(Create a REST API with PHP)

譯者前言&#xff1a; 首先這是一篇國外的英文文章&#xff0c;非常系統、詳盡的介紹了如何使用PHP創建REST API&#xff0c;國內這方面的資料非常非常的有限&#xff0c;而且基本沒有可操作性。這篇文章寫的非常好&#xff0c;只要對PHP稍有了解的程序員&#xff0c;看完本文基…

old-

大數問題:求用一段C或C程序寫求 f(x)100! 的完整程序大數問題&#xff0c; 我用數組作的&#xff0c;輸出格式應該是是222,222,222 #include "stdafx.h" #include<stdio.h> #include<stdlib.h> int a[1000]{0}; in…

javaEE的開發模式

1&#xff0e;什么是模式 模式在開發過程中總結出的“套路”&#xff0c;總結出的一套約定俗成的設計模式 2&#xff0e;javaEE經歷的模式 model1模式&#xff1a; 技術組成&#xff1a;jspjavaBean model1的弊端&#xff1a;隨著業務復雜性 導致jsp頁面比較混亂 model2模式…

Linux內核設計與實現---kobject sysfs

kobject sysfs1 kobject2 ktype3 kset4 subsystem5 別混淆了這些結構體6 管理和操作kobject7 引用計數kref8 sysfssysfs中添加和刪除kobject向sysfs添加文件9 內核事件層2.6內核增加了一個引人注目的新特性—同一設備模型。設備模型提供了獨立的機制專門表示設備&#xff0c;并…

開發Windows Mobile今日插件 -- 內存電量,桌面便箋,桌面記單詞

本篇文章講解的是開發 Windows Mobile 上的今日插件。關于是今日插件&#xff0c;在 PPC 或者 SP SDK 的幫助文檔中有相關的章節介紹&#xff0c;在網絡上也有一些帖子和資源講解。在這里簡要回顧一下。今日插件就是在windows mobile的桌面上顯示的條目&#xff0c;例如系統提供…

c語言中將函數指針作為形參_在C中將有效指針作為NULL指針

c語言中將函數指針作為形參Prerequisite: An Example of Null pointer in C 先決條件&#xff1a; C中的空指針示例 Any pointer that contains a valid memory address can be made as a NULL pointer by assigning 0. 通過分配0&#xff0c;可以將包含有效內存地址的任何指…

[轉]一個清華計算機博士生的退學申請

偶然間在網上看到這篇帖子&#xff0c;回想起自己的求學經歷&#xff0c;思索良久。。。 本想找到原帖及作者&#xff0c;但是幾經搜索&#xff0c;發現原帖出自科學網&#xff0c;已被刪除。對此&#xff0c;我還能說啥&#xff1f;&#xff01; http://www.sciencenet.cn/m/u…

算法---遞歸

遞歸結題三部曲 何為遞歸&#xff1f;程序反復調用自身即是遞歸。 我自己在剛開始解決遞歸問題的時候&#xff0c;總是會去糾結這一層函數做了什么&#xff0c;它調用自身后的下一層函數又做了什么…然后就會覺得實現一個遞歸解法十分復雜&#xff0c;根本就無從下手。 相信…

給定條件找最小值c語言程序_根據給定條件最小化n的最小步驟

給定條件找最小值c語言程序Problem statement: 問題陳述&#xff1a; Given a number n, count minimum steps to minimize it to 1 performing the following operations: 給定數字n &#xff0c;執行以下操作&#xff0c;計算最少的步驟以將其最小化為1&#xff1a; Operat…

提高C#編程水平不可不讀的50個要訣

提高C#編程水平的50個要點 1.總是用屬性 (Property) 來代替可訪問的數據成員 2.在 readonly 和 const 之間&#xff0c;優先使用 readonly 3.在 as 和 強制類型轉換之間&#xff0c;優先使用 as 操作符 4.使用條件屬性 (Conditional Attributes) 來代替條件編譯語句 #if 5.總是…

那個年代的蘇聯歌曲

小時候&#xff0c;不時聽父親提起電影《這里的黎明靜悄悄》&#xff0c;怎么也想不到如此美麗的名字為什么要和戰爭聯系起來。后來在大學看了這部電影之后&#xff0c;開始認為這名字是合適的&#xff0c;因為電影講的是女性——戰場中的女性&#xff0c;各自都懷揣著愛情去保…

linux系統編程---進程總結

進程控制總結1 進程創建的三種方式forkvfrokclone2 進程終止進程正常退出returnexit_exit進程異常退出進程收到某個信號&#xff0c;而該信號使進程終止abort3 進程等待進程等待的方法waitwaitpid4 進程替換替換原理替換函數制作一個簡單的shell1 進程創建的三種方式 參考文章…

銀行賬務轉賬系統(事務處理)

流程如下&#xff1a; 創建項目工程如下&#xff1a; transfer包下的代碼如下&#xff1a; package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils;pu…

【msdn wpf forum翻譯】TextBox中文本 中對齊 的方法

原文鏈接&#xff1a;http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/49864e35-1dbf-4292-a361-93f1a8400558問題&#xff1a;TextBox中文本中對齊&#xff0c;使用 TextBox.HorizontalContentAlignment"Center"行不通&#xff08;TextBox.VerticalConte…

wifi操作及實例

1.什么事WIFI 利用無線路由器上網的協議2.獲取WIFI網卡的狀態 WIFI網卡的狀態是由一系列的整形常量來表示的 有狀態&#xff1a; 網卡不可用WIFI_STATE_DISABLED 對應值為1 網卡正在關閉WIFI_STATE_DISABLING 對應值為0 網卡可用WIFI_STATE_ENABLED 對應的值為3 …

c語言 函數的參數傳遞示例_C語言中帶有示例的remove()函數

c語言 函數的參數傳遞示例C語言中的remove()函數 (remove() function in C) The remove() function is defined in the <stdio.h> header file. remove()函數在<stdio.h>頭文件中定義。 Prototype: 原型&#xff1a; int remove(const char* filename);Parameter…

使用ThreadLocal綁定連接資源(事務)

dao層代碼如下&#xff1a; package beyond.transfer.dao;import java.sql.Connection; import java.sql.SQLException;import org.apache.commons.dbutils.QueryRunner;import beyond.utils.DataSourceUtils; import beyond.utils.MyDataSourceUtils;public class TransferDa…

算法---棧和隊列

棧和隊列1 棧棧的順序存儲棧的鏈式存儲2 隊列隊列的順序存儲隊列的鏈式存儲3 棧和隊列的應用用棧實現隊列用隊列實現棧最小棧1 棧 參考文章&#xff1a; https://zhuanlan.zhihu.com/p/346164833 https://zhuanlan.zhihu.com/p/120965372#:~:text%E6%A0%88%E6%98%AF%E4%B8%80%…