①設定一套核心原始碼樹,比如/usr/src/linux-2.6.x,參考
eg:uname -r --->2.6.32-27-generic
wget
pub/linux/kernel/v2.6/linux-2.6.32.27.tar.gz
②直接用發行版的核心原始碼包,比如
/lib/modules/$(shell uname -r),包含核心目標鏈結檔案。 #
include
#include
module_license(
"dual bsd/gpl");
static
int hello_init(
void
)static
void hello_exit(
void
)module_init(hello_init)
;module_exit(hello_exit)
;makefile檔案
#如果已定義
ifneq (
$(kernelrelease),)
obj-m :
= hello.o
#否則,是直接從命令列呼叫的,這是要呼叫核心構造系統
else
kerneldir ?
=/lib/modules/
$(shell uname -r)
/build
pwd :
= $(shell pwd)
default
:$(make)
-c $(kerneldir) m=
$(pwd) modules
endif
make編譯,然後用insmod安裝,用dmesg可以在終端看到輸出資訊,或者輸出到某個日誌檔案裡比如/var/log/messages.
linux的模組並不複雜,
②核心函式不支援浮點運算。
③unix使用兩個級別,核心態和使用者態。當處理器有多個級別時,使用最高端別和最低級別。
④每當應用程式執行系統呼叫或者被硬體中斷掛起時,unix從使用者空間切換到核心空間。
⑤系統呼叫的**執行在程序上下文,可以訪問程序所有資料。而處理硬體中斷的核心**和程序是非同步的,與任乙個特定程序無關。
⑥乙個驅動程式要執行兩類任務:模組中的某些函式作為系統呼叫的一部分執行(實現使用者api),而其他函式則負責中斷處理。
⑦核心具有非常小的棧,可能只有4k大小頁。我們自己的函式必須和整個核心空間呼叫鏈一同共享這個棧,如果需要大的結構,應該在呼叫時動態分配。
linux2.6中核心**已經是可搶占的。
①編寫核心**時,時刻銘記:同一時刻,可能會有許多事情正在發生。
②linux核心**(包括驅動**)必須是可重入的。
核心**可通過訪問全域性項current來獲得當前程序,current在
中定義,是乙個指向struct task_struct的指標。
在2.6中,current不再是乙個全域性變數,指向task_stuct結構的指標隱藏在核心棧中,current是乙個可以獲得這個結構的巨集,包含
即可引用。 #
include
printk(kern_info"the process is \"%s\" (pid %i)\n"
,current-
>comm,current-
>pid);
對hello world模組,makefile只要一行就可以了:obj-m := hello.o
如果要構造的模組名module.ko由兩個原始檔生成,file1.c,file2.c,則:
obj-m :
= module.o
module.o-objs :
= file1.o file2.o
裝載:sudo insmod hello.ko
檢視:lsmod
解除安裝:sudo rmmod hello
公共核心符號表中包含了所有的全域性核心項(函式和變數)的位址,模組被裝載後,它所匯出的任何符號都會變成核心符號表的一部分。
模組層疊技術在複雜專案中非常有用,modprobe是處理層疊技術的乙個使用工具,功能類似insmod.通過層疊技術,可以將模組劃分為多個層,通過簡化每個層,可縮短開發時間。8
#include
//
#include
//
//所有模組**中都包含這兩行
module_license(
"dual bsd/gpl"
);//制定許可證,一般用"gpl"或者
static
int __init hello_init(
void
) //__init表示初始化函式執行完之後就釋放記憶體
static
void __exit hello_exit(
void
) //__exit表示在解除安裝是執行,編譯器把這類函式放在特殊的elf段中
module_init(hello_init)
;module_exit(hello_exit)
;//如果註冊設施時遇到任何錯誤,首先判斷模組是否可以繼續初始化,通常,在某個註冊失敗後可以通過降低功能來繼續執行。因此,只要可能,模組應該繼續向前並盡可能提供功能。
若發生的特定型別錯誤之後無法繼續裝載模組,則出錯之前的任何註冊工作都要撤銷(未撤銷,核心可能不穩定)。
void
)void
)struct something * item2;
void my_cleanup(
void
)int __init my_init(
void)
static
char
*whom =
"world"
;static
int howmany = 10;
module_param(howmany,
int,s_irugo)
;module_param(whom,charp,s_irugo)
;module_param(name,type,num,perm)
;name-
-陣列名字
type-
-陣列元素型別
num-
-陣列個數
perm-
-訪問許可值
insmod hello.ko whom=yuyunbo howmany=5
本章新符號總結(函式,變數,巨集等)
insmod,modprobe,rmmod,lsmod,dmesg
用來裝載模組到正執行的核心和移除模組的使用者空間工具
#include
module_init(init_function);
module_exit(cleanup_function);
用於指定模組的初始化和清除函式的巨集。
__init,__initdata,__exit,__exitdata
僅用於模組初始化或清除階段的函式(__init和_exit)和資料(__initdta和__exitdata)標記。
#include
最重要的標頭檔案之一,該檔案包含驅動程式使用的大部分核心api的定義,包括睡眠函式以及各種變數宣告。
struct task_struct *current;
當前程序
current->pid
current->com
當前程序的程序id和命令名。
obj-m
由核心構造系統使用的makefile的符號,用來確定當前目錄中應構造那些模組
/sys/module是sysfs目錄層次結構中包含當前已裝載模組資訊的目錄
/proc/modules是早期的用法,在單個檔案中包含模組名稱,每個模組記憶體總量以及引用計數等。
vermagic.o核心源**目錄中的乙個目標檔案,描述了模組的構造環境。
#include
必須的標頭檔案,它必須包含在模組源**中。
#include
包含說構造核心版本資訊的標頭檔案。
linux_version_code整數巨集,用在處理版本以來的預處理條件語句中。
export_symbol (symbol);
匯出單個符號到核心的巨集
export_symbol_gpl(symbol);僅用於gpl許可證下的模組
module_author(author);
module_description(desctiption);
module_version(version_string);
module_device_table(table_info);
module_alias(alternate_name);
在目標檔案中新增關於模組的文件資訊。
module_init(init_function);
module_exit(exit_function);
宣告模組初始化和清除函式的巨集
#include
module_param(variable,type,perm);
用來建立函式模組的巨集,在裝載模組時調整引數
#include
int printk(const char * fmt,...);
函式printf的核心**
0
給主人留下些什麼吧!~~
LDD3學習筆記 模組的編譯
新手上路,ldd3學習之旅開始,以下內容純屬筆記,若有錯誤,望見諒!1.什麼是 模組 可以在系統執行時加入到核心中的 故 模組包括但不限於裝置驅動程式。2.如何寫乙個模組?1 c檔案 2 實現module init,module exit3.ldd3中makefile編寫規則 照搬 ifneq ke...
ldd3第二章 建立核心原始碼樹,編譯模組
ubuntu編譯核心樹 首先我實驗的hello和scull模組都不需要建立核心原始碼樹,只需系統自帶的標頭檔案就可。ubuntu 10.04 確認你當前使用ubuntu系統的核心版本 當模組 要鏈結至不同版本的核心時,必須要做的就是對這個模組 重新進行編譯。這是因為模組對某一版本核心中定義的一些資料...
第二章 構造和執行模組(筆記)
如果讀者正在編寫乙個只適用於某特定發行版的驅動程式,則應該針對相關核心建立和測試自己的驅動程式。2.6.x核心構造模組,必須在自己的系統中配置並構造好核心樹 因為2.6核心的模組要和核心源 樹中的目標檔案連線 先前的核心只需要一套核心標頭檔案就夠了。module license用來告訴核心,該模組採...