亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 2219 | 回復(fù): 0
打印 上一主題 下一主題

一起學(xué)習(xí)KLD(轉(zhuǎn)) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-08-15 15:57 |只看該作者 |倒序瀏覽

原文出處:http://bbs3.chinaunix.net/thread-763812-1-1.html
1.首先從hello world開始
[Copy to clipboard]

[ - ]
CODE:#include
#include
#include
#include
#include
#include
static int
hello_load(module_t md, int cmd, void* arg)
{
    int    err = 0;
    switch(cmd){
        case  MOD_LOAD:
                  printf("hello world!\n");
                  break;
        case  MOD_UNLOAD:
                  printf("bye world!\n");
                  break;
        default:
                  err = EINVAL;
                  break;
}
    return  err;
}
DEV_MODULE(helloworld, hello_load, NULL);
Makefile
[Copy to clipboard]

[ - ]
CODE:SRCS= hello_world.c
KMOD= hello_world
.include
現(xiàn)在實驗一下,首先編譯
[Copy to clipboard]

[ - ]
CODE:[prime@hello_world] $ make
Warning: Object directory not changed from original /usr/home/prime/mycode/kld/hello_world
@ -> /usr/src/sys
machine -> /usr/src/sys/i386/include
cc -O2 -fno-strict-aliasing -pipe  -Werror -D_KERNEL -DKLD_MODULE
-nostdinc -I-   -I. -I@ -I@/contrib/altq -I@/../include -I/usr/include
-finline-limit=8000 -fno-common  -mno-align-long-strings
-mpreferred-stack-boundary=2  -mno-mmx -mno-3dnow -mno-sse -mno-sse2
-ffreestanding -Wall -Wredundant-decls -Wnested-externs
-Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Winline
-Wcast-qual  -fformat-extensions -std=c99 -c hello_world.c
ld  -d -warn-common -r -d -o hello_world.kld hello_world.o
touch export_syms
awk -f /sys/conf/kmod_syms.awk hello_world.kld  export_syms | xargs -J% objcopy % hello_world.kld
ld -Bshareable  -d -warn-common -o hello_world.ko hello_world.kld
objcopy --strip-debug hello_world.ko
[prime@hello_world] $
然后加載
[Copy to clipboard]

[ - ]
CODE:[root@hello_world]#kldload ./hello_world.ko
現(xiàn)在dmesg看看
2.hello world干了什么
先看看DEV_MODULE,這個宏定義在/sys/sys/conf.h
[Copy to clipboard]

[ - ]
CODE:#define DEV_MODULE(name, evh, arg)                                      \
static moduledata_t name##_mod = {                                      \
    #name,                                                              \
    evh,                                                                \
    arg                                                                 \
};                                                                      \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
DECLARE_MODULE呢,定義在/sys/sys/module.h
[Copy to clipboard]

[ - ]
CODE:#define DECLARE_MODULE(name, data, sub, order)                          \
        MODULE_METADATA(_md_##name, MDT_MODULE, &data, #name);          \
        SYSINIT(name##module, sub, order, module_register_init, &data)  \
        struct __hack
那么我們的DEV_MODULE最終的展開結(jié)果是什么呢
[Copy to clipboard]

[ - ]
CODE:static moduledata_t helloworld_mod = {
    "helloworld",
    hello_load,
    NULL
};
static struct mod_metadata _mod_metadata_md_helloworld = {
    MDT_STRUCT_VERSION,
    MDT_MODULE,
    &helloworld_mod,
    "helloworld"
};
static void const* const
__set_modmetadata_set_sym__mod_metadata_md_helloworld
__section("set_modmetadata_set") __used =
&_mod_metadata_md_helloworld;
static struct sysinit helloworldmodule_sys_init = {
    SI_SUB_DRIVERS,
    SI_ORDER_MIDDLE,
    (sysinit_cfunc_t)(sysinit_nfunc_t)module_register_init,
    (void*)&helloworld_mod
};
static void const* const
__set_sysinit_set_sym_helloworldmodule_sys_init __section("set_sysinit_set") __used = &helloworldmodule_sys_init;
看上去很亂,讓我們捋一捋吧
我們通過kldload加載KLD,加載后內(nèi)核首先根據(jù)modmetadata_set找到一組指向struct
mod_metadata的指針,我們這里只有一個,
__set_modmetadata_set_sym__mod_metadata_md_helloworld指向
_mod_metadata_md_helloworld,
內(nèi)核使用這個指針指向的結(jié)構(gòu)中的數(shù)據(jù)為參數(shù)(/sys/kern/kern_linker.c中函數(shù)
linker_file_register_modules)調(diào)用module_register(/sys/kern/kern_module.c)對
模塊進(jìn)行注冊
然后,內(nèi)核根據(jù)sysinit_set找到一組指向struct
sysinit的指針,我們這里也是只有一個__set_sysinit_set_sym_helloworldmodule_sys_init指向
helloworldmodule_sys_init,內(nèi)核使用這個指針指向的結(jié)構(gòu)中的數(shù)據(jù)為參數(shù)(/sys/kern/kern_linker.c中函
數(shù)linker_file_sysinit)調(diào)用結(jié)構(gòu)中的函數(shù),我們這里就是以&helloworld_mod為參數(shù)調(diào)用
module_register_init
在module_register_init中,首先通過模塊名稱(helloworld_mod中的"helloworld")找到
module_register注冊的模塊,然后,通知該模塊MOD_LOAD,我們這里也就是調(diào)用hello_load其中cmd參數(shù)為
MOD_LOAD,mod參數(shù)為指向本模塊的指針,arg參數(shù)為helloworld_mod中的NULL,也就是我們的DEV_MODULE中的
NULL
3.復(fù)雜一點的hello world,在一個文件中實現(xiàn)多個模塊
其實并不復(fù)雜,代碼一樣簡單,Makefile就省略了
[Copy to clipboard]

[ - ]
CODE:#include
#include
#include
#include
#include
#define  NMODULE_SYSTEM  SI_SUB_DRIVERS
#define  NMODULE_ORDER   SI_ORDER_MIDDLE
static int
modload(module_t mod, int cmd, void* arg )
{
    int err = 0;
    char* me = (char*)arg;
    switch(cmd){
        case MOD_LOAD:
            printf("Module %s loaded\n",me);
            break;
        case MOD_UNLOAD:
            printf("Module %s unloaded\n",me);
            break;
        default:
            err = EINVAL;
            break;
    }
    return err;
}
static moduledata_t firstmodule = {
    "firstmodule",
    modload,
    "first one"
};
DECLARE_MODULE(firstmodule, firstmodule, NMODULE_SYSTEM, NMODULE_ORDER);
static moduledata_t secondmodule = {
    "secondmodule",
    modload,
    "second one"
};
DECLARE_MODULE(secondmodule, secondmodule, NMODULE_SYSTEM, (NMODULE_ORDER + 1));
static moduledata_t thirdmodule = {
    "thirdmodule",
    modload,
    "third one"
};
DECLARE_MODULE(thirdmodule, thirdmodule, NMODULE_SYSTEM, (NMODULE_ORDER + 2));
試試把secondmodule與thirdmodule的聲明順序顛倒一下,也就是先DECLARE_MODULE(thirdmodule.....)然后DECLARE_MODULE(secondmodule....),dmesg變了嗎?
4.定義模塊的版本與模塊間的依賴關(guān)系
MODULE_VERSION用來定義模塊的版本,在/sys/sys/module.h中定義,
[Copy to clipboard]

[ - ]
CODE:#define MODULE_VERSION(module, version)      \
static struct mod_version _##module##_version = {\
                version                      \
       };                                    \
MODULE_METADATA(_##module##_version, MDT_VERSION,\
&_##module##_version, #module)
其中module參數(shù)為模塊的名稱,version為版本號
MODULE_DEPEND定義模塊的依賴關(guān)系,在/sys/sys/module.h定義,
[Copy to clipboard]

[ - ]
CODE:#define MODULE_DEPEND(module, mdepend, vmin, vpref, vmax) \
static struct mod_depend _##module##_depend_on_##mdepend = {\
vmin,\
vpref,\
vmax\
};\
MODULE_METADATA(_md_##module##_on_##mdepend, MDT_DEPEND,\
&_##module##_depend_on_##mdepend, #mdepend)
定義的依賴關(guān)系為module依賴于mdepend,module可以接受的mdepend的版本號在vmin到vmax之間,最好為vpref
看看我們的實驗代碼,我們有四個模塊,包括1個版本的dephello,與版本號分別為1,2,3的三個版本的hello(茴字不過有四種寫法

),dephello依賴于hello,而且可以接受版本號的范圍是1--3,最接受的版本號為2
代碼的目錄結(jié)構(gòu)
[Copy to clipboard]

[ - ]
CODE:[prime@modverdep] $ ls
Makefile        dephello        hello2
common          hello1          hello3
[prime@modverdep] $
dephello目錄下有源文件dephello.c與前面的hello world差不多,就是多了一行
[Copy to clipboard]

[ - ]
CODE:MODULE_DEPEND(dephello, hello, 1, 3, 2);
hello*目錄下面的源文件為hello.c,比如hello1下的內(nèi)容為
[Copy to clipboard]

[ - ]
CODE:#define HELLO_VERSION 1
#include "../common/hello.c"
其他的依此類推
common目錄下的源文件如下
[Copy to clipboard]

[ - ]
CODE:#include
#include
#include
#include
#include
static int
hello_load(module_t mod, int cmd, void* arg)
{
    int err = 0;
    char* name = (char*)arg;
    switch(cmd){
        case MOD_LOAD:
            printf("version %d %s loading...\n", HELLO_VERSION, name);
            break;
        case MOD_UNLOAD:
            printf("version %d %s unloading...\n", HELLO_VERSION, name);
            break;
        default:
            err = EINVAL;
            break;
    }
    return err;
}
static moduledata_t hellomod = {
    "hello",
    hello_load,
    "hello"
};
DECLARE_MODULE(hello, hellomod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
MODULE_VERSION(hello, HELLO_VERSION);
上層目錄的Makefile
[Copy to clipboard]

[ - ]
CODE:SUBDIR= hello1 hello2 hello3 dephello
.include
首先make
然后換成超級用戶 make install(為什么要install,后面解釋);
[Copy to clipboard]

[ - ]
CODE:[prime@modverdep]$ make
[root@modverdep]#make install
現(xiàn)在
[Copy to clipboard]

[ - ]
CODE:[root@modverdep]# kldload dephello
[root@modverdep]# kldunload dephello
然后dmesg看看
如果我們只安裝版本號為1或者3的hello呢?如果我們不安裝hello呢?
MODULE_METADATA宏出現(xiàn)了很多次,詳細(xì)看看她吧,這個宏
定義了一個mod_metadata結(jié)構(gòu),并在modmetadata_set中保存一個指向這個結(jié)構(gòu)的指針,內(nèi)核在加載了KLD后根據(jù)這些指針找到所有
的這些結(jié)構(gòu)。mod_metadata有三種作用,MDT_DEPEND聲明模塊間的依賴關(guān)系,MDT_MODULE聲明模塊,MDT_VERSION聲
明模塊的版本。
[Copy to clipboard]

[ - ]
CODE:struct mod_metadata {
        int             md_version;
        int             md_type;
        void            *md_data;
        const char      *md_cval;
};
md_type指明了這個結(jié)構(gòu)的作用
md_type為MDT_DEPEND時,md_cval為所依賴的模塊名稱,而md_data則指向一個mod_depend結(jié)構(gòu);
md_type為MDT_MODULE時,md_cval為聲明的模塊名稱,而md_data則指向一個moduledata結(jié)構(gòu);
md_type為MDT_VERSION時,md_cval為模塊的名稱,而md_data則指向一個說明該模塊版本的mod_version結(jié)構(gòu)。
***為什么要make install?前面的例子我們都沒有安裝。
make install將模塊安裝到/boot/kernel下面,然后執(zhí)行kldxref
/boot/kernel。在加載dephello以前,內(nèi)核發(fā)現(xiàn)dephello依賴于hello,那么他將查找包含合適版本的模塊hello的KLD
文件并加載(/sys/kern/kern_linker.c中函數(shù)linker_load_dependencies),查找時需要所查找的目錄(內(nèi)核
查找的目錄包括/boot/kernel
/boot/modules)下的linker.hints文件,根據(jù)該文件的記錄,內(nèi)核決定應(yīng)該加載哪個KLD文件。kldxref的作用就是在
linker.hints文件中記錄哪些模塊的哪些版本包含在哪些KLD文件中(kldxref的詳細(xì)用法參看man kldxref)。
****這個實驗做完了,我不想在/boot/kernel下保存這些KLD,所以,我
#rm -i /boot/kernel/dephello.ko
#rm -i /boot/kernel/hello*
#kldxref /boot/kernel
5.在KLD中使用非全局變量
一直以為KLD是不能使用內(nèi)核中用static修飾定義的變量(Linux內(nèi)核中是這樣的,只能使用導(dǎo)出的有限的符號),但是今天實驗了一下,發(fā)現(xiàn)沒有這
個限制,在KLD中可以使用內(nèi)核中所有的變量,可以做個實驗,比如kld_mtx在kern/kern_linker.c中定義為static,但是,在
KLD中我們依然可以找出他的地址,只要使用以前聲明一下。
之所以要使用這種變量是因為內(nèi)核給我們封裝的功能有時侯無法滿足我們的需要,比如,我要直接操縱所有KLD的鏈表,所有module的鏈表,那么我需要首先鎖住kld_mtx。
6.內(nèi)核中KLD的實現(xiàn)簡介
內(nèi)核中每個KLD文件使用一個linker_file結(jié)構(gòu)來描述,這個結(jié)構(gòu)記錄了文件的名稱,引用計數(shù),唯一ID,文件之間的依賴關(guān)系以及特定文件格式相
關(guān)信息。所有的linker_file使用一個TAILQ連接起來(kern/kern_linker.c
linker_files),每個linker_file使用TAILQ記錄了文件中的所含有的所有module(TAILQ_HEAD(,
module) modules)。
對于模塊(module),內(nèi)核使用module結(jié)構(gòu)來描述。每個module結(jié)構(gòu)記錄了模塊名稱,引用計數(shù),唯一ID,包含模塊的
linker_file,事件(加載,卸載)處理函數(shù)等。所有加載的module通過TAILQ連接起來(kern/kern_module.c
modules),如前面所說,每個linker_file中的module也通過TAILQ連接起來。
另外,為了處理模塊的版本問題,內(nèi)核用一個TAILQ(kern/kern_linker.c found_modules)記錄所加載的模塊及其版本。
1>加載KLD模塊的任務(wù)主要由linker_load_module( kern/kern_linker.c )完成。
如果只是給定了module名,那么它首先根據(jù)module名來確定需要加載的KLD文件的路徑(這里會用到搜索目錄下的linker.hints文件,參看kern/kern_linker.c 中函數(shù) linker_search_module)
然后進(jìn)行模塊是否已經(jīng)加載等常規(guī)檢查
接下來調(diào)用格式相關(guān)的加載方法LINKER_LOAD_FILE來將KLD文件加載進(jìn)入內(nèi)存并進(jìn)行重定位等操作
然后注冊KLD文件中的module(使用前面提到的mod_metadata),把他們加入到相應(yīng)的TAILQ中,包括全局的TAILQ與KLD文件的TAILQ;注冊sysctl;使用SYSINIT框架初始化(使用前面提到的sysinit結(jié)構(gòu))
最后如果這個KLD文件是因為其他模塊需要而加載進(jìn)來的,那么在它的linker_file中記錄下這種依賴關(guān)系
對于格式相關(guān)的加載方法LINKER_LOAD_FILE的實現(xiàn),可以在kern/link_elf.c 與
kern/link_elf_obj.c中找到,他們在對KLD文件進(jìn)行重定位以前會調(diào)用linker_load_dependencies
(kern/kern_linker.c)來加載這個KLD文件所依賴的KLD文件。另外他們通過調(diào)用linker_make_file
(kern/kern_linker.c )來分配一個新的linker_file并將其連接到TAILQ中。
2>卸載KLD文件主要由linker_file_unload( kern/kern_linker.c )完成
首先減少linker_file的計數(shù)器,如果為0那么繼續(xù)
對linker_file包含的每個module通知卸載事件( MOD_UNLOAD )并減少他們的引用計數(shù),如果到0,釋放module
從found_modules TAILQ中去掉KLD文件中包含的module的版本信息
如果是正常卸載,那么通過SYSUNINIT框架執(zhí)行清理代碼,取消注冊的sysctl.
從全局TAILQ中刪除linker_file,釋放因為依賴而對其他KLD文件進(jìn)行的引用計數(shù)
使用LINKER_FILE_UNLOAD進(jìn)行格式相關(guān)的卸載操作
7.一個實際的KLD文件加載過程
我們使用前面 4 中的代碼來看一下實際的加載KLD加載過程.注意的是,我們已經(jīng)把dephello等等模塊安裝到了/boot/kernel下.
執(zhí)行加載命令
[Copy to clipboard]

[ - ]
CODE:[root@~]#kldload dephello
首先看看kldload(8 )的實現(xiàn),代碼在/usr/src/sbin/kldload,比較簡單直接使用了kldload(2),而kldload(2)的實現(xiàn)在kern/kern_linker.c kldload函數(shù).
首先系統(tǒng)調(diào)用后內(nèi)核進(jìn)入函數(shù)kldload(kern/kern_linker.c)
首先調(diào)用securelevel_gt與suser檢查權(quán)限,現(xiàn)在我們是root用戶而且安全等級是默認(rèn)的-1所以通過安全檢查
把字符串參數(shù)復(fù)制進(jìn)內(nèi)核 pathname指向新分配的內(nèi)存,把"dephello"復(fù)制到pathname中
確定它是KLD文件名還是模塊名,由于"dephello"中沒有`.'與`/'所以認(rèn)為它是模塊名,調(diào)用
linker_load_module,KLD文件名為NULL,模塊名為"dephello",我們不是以為其他KLD文件的依賴而加載,所以
parent參數(shù)為NULL,版本信息為NULL,并講結(jié)果保存到lf中
進(jìn)入linker_load_module(kern/kern_linker.c)函數(shù)
首先查找"dephello"是否已經(jīng)加載,調(diào)用modlist_lookup2,
在modlist_lookup2發(fā)現(xiàn)沒有版本信息所以直接使用modlist_lookup
在found_moudles指向的TAILQ上查找是否有名字為"dephello"的模塊,因為我們以前沒有加載dephello所以查找的結(jié)果是不
存在.所以可以繼續(xù)進(jìn)行加載過程
因為KLD文件名為NULL,所以調(diào)用linker_search_module來確定包含"dephello"的KLD文件
進(jìn)入linker_search_module(kern/kern_linker.c)
在linker_path中指定的所有目錄下使用linker_hints_lookup查找包含"dephello"的KLD文件
進(jìn)入linker_hints_lookup(kern/kern_linker.c)函數(shù)
首先打開參數(shù)path指定的目錄下的"linker.hints"文件并將其讀入內(nèi)存,然后在查找包含"dephello"的KLD文件,找到文件名
"dephello.ko"后,使用linker_lookup_file來確定"dephello.ko"是存在.最后返回結(jié)果
"/boot/kernel/dephello.ko"
linker_search_module返回結(jié)果"/boot/kernel/dephello.ko",回到linker_load_module
調(diào)用linker_find_file_by_name查找"dephello.ko"是否已經(jīng)加載,
linker_find_file_by_name遍歷linker_files指向的TAILQ查找"dephello,ko",沒有找到,繼續(xù)加載過

調(diào)用linker_load_file加載"/boot/kernel/dephello.ko"
linker_load_file首先調(diào)用linker_find_file_by_name查找"/boot/kernel/dephello.ko"是否加載,沒有找到,繼續(xù)加載過程
調(diào)用LINKER_LOAD_FILE來進(jìn)行格式相關(guān)的加載,經(jīng)過kobj處理,最終調(diào)用link_elf_load_file
(kern/link_elf.c)來加載"/boot/kernel/dephello.ko".首先進(jìn)行ELF格式的處理,然后調(diào)用
linker_make_file來產(chǎn)生新的linker_file,得到的新linker_file的名字為"dephello.ko",并連接進(jìn)
linker_files 所指向的TAILQ中
調(diào)用linker_load_dependencies來加載"dephello.ko"所依賴的KLD.進(jìn)入
linker_load_dependencies
(kern/kern_linker.c),因為所有的KLD都依賴于內(nèi)核,所以首先給"dephello.ko"注冊一個對"kernel"的依賴
(linker_file_add_dependency kern/kern_linker.c)
找到"dephello.ko"中modmetadata_set的開始,因為這其中包含了對其他KLD的依賴信息以及模塊的版本信息(一組指向mod_metadata結(jié)構(gòu)的指針)
首先檢查版本信息,確定"dephello.ko"中所有的模塊的相應(yīng)版本沒有加載,因為我們沒有在"dephello.ko"中聲明版本信息,所以,這一步不會執(zhí)行
檢查依賴信息,根據(jù)指針指向的mod_metadata結(jié)構(gòu)的內(nèi)容確定"dephello.ko"所依賴的模塊名,我們這里是
"hello",最接受版本2,接受版本1--3.首先確定"hello"不在"dephello.ko"中,然后調(diào)用modlist_lookup2來
查找版本在1--3間最好為2的"hello"是否加載,這里沒有加載
調(diào)用linker_load_module來加載需要版本的"hello"模塊,并且在參數(shù)中指出是因為"dephello.ko"依賴而加載
調(diào)用linker_addmodules將"dephello.ko"中的模塊的版本信息加入到found_modules指向的TAILQ中,由于"dephello.ko"中沒有版本信息,所以什么也不做
返回到link_elf_load_file(kern/link_elf.c)
link_elf_load_file進(jìn)行一系列的ELF處理后返回linker_load_file
完成了格式相關(guān)的加載,調(diào)用liner_file_register_modules注冊"dephello.ko"中的模塊.在
linker_file_register_modules中,首先找到modmetadata_set,根據(jù)他找到聲明模塊的mod_metadata
結(jié)構(gòu),根據(jù)結(jié)構(gòu)的內(nèi)容調(diào)用module_register來注冊"dephello.ko"中的模塊"dephello",包括將"dephello"模
塊連接到modules指向的TAILQ中,連接到"dephello.ko"的linker_file的TAILQ中.
調(diào)用linker_file_register_sysctls來注冊sysctl, "dephello.ko"中沒有sysctl,所以這一步略過
調(diào)用linker_file_sysinit來使用SYSINIT框架初始化"dephello.ko"這里,就是調(diào)用module_register_init
在module_register_init中簡單的根據(jù)模塊名("dephello" )找到加載的模塊,然后通知MOD_LOAD事件,我們這里也就是調(diào)用deph_load
從linker_load_file返回linker_load_module, linker_load_module檢查需要加載的模塊("dephello" )是否已經(jīng)加載
返回kldload,完成加載,把"dephello.ko"的ID返回給進(jìn)程
---------------
               
               
               

本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u3/91935/showart_2028749.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP