


版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、第五章 模塊編程實(shí)驗(yàn)【實(shí)驗(yàn)?zāi)康摹客ㄟ^學(xué)習(xí)核模塊的編寫和運(yùn)行,了解模塊是 Linux OS 的一種特有的機(jī)制,可根 據(jù)用戶的實(shí)際需要在不需要對(duì)核進(jìn)行重新編譯的情況下, 模塊能在核中被動(dòng)態(tài)地加載 和卸載。編寫一個(gè)模塊,將它作為 Linux OS 核空間的擴(kuò)展來執(zhí)行,并通過 insmod 命令來手工加載,通過命令rmmod來手工卸載?!緶?zhǔn)備知識(shí)】Linux 模塊是一些可以作為獨(dú)立程序來編譯的函數(shù)和數(shù)據(jù)類型的集合。在裝載這些模塊時(shí),將它的代碼到核中。 Linux 模塊有兩種裝載方式:靜態(tài)裝載(核啟動(dòng)時(shí)裝 載)和動(dòng)態(tài)裝載(在核運(yùn)行過程中裝載) 。若在模塊裝載之前就調(diào)用了動(dòng)態(tài)模塊的一 個(gè)函數(shù), 則此調(diào)用將
2、失??;若模塊已被裝載, 則核就可以使用系統(tǒng)調(diào)用, 并將其傳遞 到模塊中的相應(yīng)函數(shù)。 模塊通常用來實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)程序 (這要求模塊的 API 和設(shè)備驅(qū) 動(dòng)程序的 API 相一致)。模塊可用來實(shí)現(xiàn)所期望的任何功能。一模塊的組織結(jié)構(gòu)模塊一旦被裝載進(jìn)系統(tǒng), 就在核地址空間中管態(tài)下執(zhí)行。 它就像任何標(biāo)準(zhǔn)的核代 碼一樣成為核的一部分, 并擁有其它核代碼相同的權(quán)限和職責(zé) (當(dāng)然也會(huì)引起系統(tǒng)的 崩潰)。若模塊知道核數(shù)據(jù)結(jié)構(gòu)的地址,則它可以讀寫核數(shù)據(jù)結(jié)構(gòu)。但 Linux 是一個(gè) 整體式的核( monolithic kernel )結(jié)構(gòu),整個(gè)核是一個(gè)單獨(dú)的且非常大的程序,從 而存在一個(gè)普遍的問題:在一個(gè)文件中實(shí)現(xiàn)的
3、函數(shù)可能需要在其它文件中定義的數(shù) 據(jù)。在傳統(tǒng)的程序中, 這個(gè)問題是通過編輯器在生成可執(zhí)行對(duì)象文件時(shí), 使用編輯器 可以解析的外部 (全局) 變量來解決的。又因?yàn)槟K的設(shè)計(jì)和實(shí)現(xiàn)與核無關(guān),所以模 塊不能靠靜態(tài)通過變量名引用核數(shù)據(jù)結(jié)構(gòu)。 恰好相反, Linux 核采用了另外一種機(jī)制: 實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)的文件可以導(dǎo)出結(jié)構(gòu)的符號(hào)名(可以從文件/proc/ksyms 或文件/kernel/ksyms.c中以文本方式讀取這個(gè)公開符號(hào)表),這樣在運(yùn)行時(shí)就可以使用這個(gè)結(jié)構(gòu)了。不過在編寫模塊的過程中,編寫(修改)導(dǎo)出變量時(shí)要格外注意,因?yàn)?通過修改變量會(huì)修改核的狀態(tài), 其結(jié)果可能并不是核設(shè)計(jì)者所期望的。 在確信自己
4、了 解修改核變量的后果之前,應(yīng)該對(duì)這些變量只進(jìn)行讀操作。模塊作為一種抽象數(shù)據(jù)類型, 它具有一個(gè)可以通過靜態(tài)核中斷的接口。 最小的模 塊結(jié)構(gòu)必須包括兩個(gè)函數(shù),它們?cè)谙到y(tǒng)裝載模塊和卸載模塊時(shí)調(diào)用,分別是init_module() 和 cleanup_module() ??梢跃帉懸粋€(gè)只包括這兩個(gè)函數(shù)的模塊,這樣 該模塊中唯一會(huì)被調(diào)用的函數(shù)就是模塊被裝載時(shí)所調(diào)用的函數(shù) init_module() 和模 塊被卸載時(shí)所調(diào)用的函數(shù)cleanup_module() 。并且用函數(shù) init_module()來啟動(dòng)模塊裝載期間的操作,用函數(shù)cleanup_module() 來停止這些操作。由于模塊可以實(shí)現(xiàn)相當(dāng)復(fù)雜
5、的功能, 故可以在模塊中加入很多新函數(shù)以實(shí)現(xiàn)所要 期望的功能。 不過加入模塊的每個(gè)新函數(shù)都必須在該模塊裝載到核中時(shí)進(jìn)行注冊(cè)。 若 該模塊是靜態(tài)裝載的, 則該模塊的所有函數(shù)都是在核啟動(dòng)時(shí)進(jìn)行注冊(cè)的; 若該模塊是 動(dòng)態(tài)裝載的, 則這些新函數(shù)必須在裝載這個(gè)模塊時(shí)動(dòng)態(tài)注冊(cè)。當(dāng)然, 如果該模塊被動(dòng)態(tài)卸載了, 則該模塊的函數(shù)都必須從系統(tǒng)中注銷。 通過這種方式, 當(dāng)這個(gè)模塊不在系 統(tǒng)中時(shí),就不能調(diào)用該模塊的函數(shù)。 其中注冊(cè)工作通常是在函數(shù) init_module() 中完 成的,而注銷工作通常是在函數(shù) cleanup_module() 中完成的。由上述定義的模塊應(yīng)有如下的格式:#include <li
6、nux/kernel.h>#include <linux/module.h>/ 其它header信息int init_module( )/裝載時(shí),初始化模塊的編碼/期望該模塊所能實(shí)現(xiàn)的一些功能函數(shù),如open()、release。、write()、 / read() 、 ioctl() 等函數(shù)void cleanup_module( )/ 卸載時(shí),注銷模塊的編碼 °二模塊的編譯一旦設(shè)計(jì)并編寫好模塊, 必須將其編譯成一個(gè)適合核裝載的對(duì)象文件° 由于編寫 模塊是用 C 語言來完成的,故采用 gcc 編譯器來進(jìn)行編譯°若需要通知編譯程序把 這個(gè)模塊作為
7、核代碼而不是普通的用戶代碼來編譯,則就需向 gcc 編譯器傳遞參數(shù) “ -D_ _KERNEL_”;若需要通知編譯程序這個(gè)文件是一個(gè)模塊而不是一個(gè)普通文件,則就需向gcc編譯器傳遞參數(shù)“ -DMODUL”;若需要對(duì)模塊程序進(jìn)行優(yōu)化編譯、連接,則就需使用“ -O2 ”參數(shù);若還需要對(duì)裝載后的模塊進(jìn)行調(diào)試,則就需使用“-g ”參數(shù);同時(shí)需要使用“ -Wall ”參數(shù)來向裝載程序傳遞all,使用“ -c ”開關(guān)通知編譯程序在編譯完這個(gè)模塊文件后不調(diào)用程序。一般編譯模塊文件的命令格式如下:#gcc -O2 -g -Wall -DMODULE -D_ _KERNEL_ _ -c filename.c/
8、filename.c 為自己編寫的模塊程序源代碼文件執(zhí)行命令后就會(huì)得到文件 filename.o ,該文件就是一個(gè)可裝載的目標(biāo)代碼文件。三模塊的裝載核模塊的裝載方式有兩種。一種是使用 insmod 命令手工裝載模塊;另一種是請(qǐng) 求裝載 demand loading (在需要時(shí)裝載模塊) ,即當(dāng)有必要裝載某個(gè)模塊時(shí),若用戶 安裝了核心中不存在的文件系統(tǒng)時(shí), 核心將請(qǐng)求核守護(hù)進(jìn)程 kerneld 準(zhǔn)備裝載適當(dāng)?shù)?模塊。該核守護(hù)進(jìn)程是一個(gè)帶有超級(jí)用戶權(quán)限的普通用戶進(jìn)程。 此實(shí)驗(yàn)中我們主要采 用 insmod 命令手工裝載模塊。系統(tǒng)啟動(dòng)時(shí), kerneld 開始執(zhí)行,并為核打開一個(gè) IPC 通道,核通
9、過向 kerneld 發(fā)送消息請(qǐng)求執(zhí)行各種任務(wù)。 kerneld 的主要功能是裝載和卸載核模塊, kerneld 自 身并不執(zhí)行這些任務(wù), 它通過某些程序 (如 insmod )來完成。 Kerneld 只是核的代理, 只為核進(jìn)行調(diào)度。insmod 程序必須找到請(qǐng)求裝載的核模塊(該請(qǐng)求裝載的模塊一般被保存在 /lib/modules/kernel-version中)。這些模塊與系統(tǒng)中其它程序一樣是已連接的目標(biāo)文件, 但不同的是它們被連接成可重定位映象 (即映象沒有被連接到在特定的地址 上運(yùn)行,其文件格式是a.out或ELF)。亦就是說,模塊在用戶空間(使用適當(dāng)?shù)臉?biāo)志)進(jìn)行編譯, 結(jié)果產(chǎn)生一個(gè)可
10、執(zhí)行格式的文件。 在用 insmod 命令裝載一個(gè)模塊時(shí), 將會(huì)發(fā)生如下事件:( 1)新模塊(通過核函數(shù) create_module() )加入到核地址空間。( 2) insmod 執(zhí)行一個(gè)特權(quán)級(jí)系統(tǒng)調(diào)用 get_kernel_syms() 函數(shù)以找到核的輸出 符號(hào)(一個(gè)符號(hào)表示為符號(hào)名和符號(hào)值,如地址值) 。( 3) create_module() 為這個(gè)模塊分配存空間, 并將新模塊添加在核模塊鏈表的 尾部,然后將新模塊標(biāo)記為 UNINITIALIZED (模塊未初始化) 。( 4)通過 init_module() 系統(tǒng)調(diào)用裝載模塊。 (該模塊定義的符號(hào)在此時(shí)被導(dǎo)出, 供其它可能后來裝載的模
11、塊使用)( 5) insmod 為新裝載的模塊調(diào)用 init_module() 函數(shù),然后將新模塊標(biāo)志為 RUNNING模塊正在運(yùn)行)。在執(zhí)行完insmod命令后,就可在/proc/modules 文件中看到裝載的新模塊了。(為 證實(shí)其正確性,可在執(zhí)行insmod命令之前先查看/proc/modules 文件,執(zhí)行之后再 查看比較)四.模塊的卸載當(dāng)一個(gè)模塊不需要使用時(shí),可以使用rmmod命令卸載該模塊。由于無需連接,故 它的任務(wù)比加載模塊要簡單得多。但如果請(qǐng)求裝載模塊在其使用計(jì)數(shù)為0時(shí),kerneld將自動(dòng)從系統(tǒng)中卸載該模塊。卸載時(shí)調(diào)用模塊的cleanup_module()釋放分配給該模塊的核
12、資源,并將其標(biāo)志為 DELETER模塊被卸載);同時(shí)斷開核模塊鏈表中的連接, 修改它所依賴的其它模塊的引用,重新分配模塊所占的核存。五模塊連接到核的示意圖該圖比較明顯地展示了模塊連接到核所使用的命令和函數(shù),以及各個(gè)函數(shù)之間的調(diào)用關(guān)系。通過該圖,可以比較清晰地看出模塊連接到核的整個(gè)連接過程,這也有助于核模塊的編寫。模塊in smodini t_module()內(nèi)核核心register_capability()capabilities:printk()六模塊程序中管理模塊的幾個(gè)文件操作在核部用一個(gè) file 結(jié)構(gòu)來識(shí)別模塊, 而且核使用 file_operatuions 結(jié)構(gòu)來訪問 模塊程序中的函
13、數(shù)。 file_operatuions 結(jié)構(gòu)是一個(gè)定義在 <linux/fs.h> 中的函數(shù)指 針表。管理模塊的文件操作, 通常也稱為 “方法”,它們都為 struct file_operations 提供函數(shù)指針。在 struct file_operations 中的操作一般按如下順序出現(xiàn),除非說 明,它們返回 0 值時(shí)表示訪問成功;發(fā)生錯(cuò)誤時(shí)返回一個(gè)負(fù)的錯(cuò)誤值(目前共有 13 個(gè)操作):int (*lseek) ()、int (*read)()、int (*write)()、 int (*readdir)()、int(*select)() 、int (*ioctl)() 、in
14、t (*mmap)() 、int (*open)() 、void (*release)() 、 int (*fsync)() 、 int (*fasync)() 、 int (*check_media_change)() 、 int (*revalidate)()下面我們只簡單介紹其中的幾個(gè)操作,其它在以后涉及時(shí)再介紹 :1、方法 int (*read)(struct inode *,struct file *,char *, int)該方法用來從模塊中讀取數(shù)據(jù)。當(dāng)其為 NULL 指針時(shí)將引起 read 系統(tǒng)調(diào)用返回 -EINVAL (“非法參數(shù)”)。函數(shù)返回一個(gè)非負(fù)值表示成功地讀取了多少字節(jié)
15、。2、方法 int (*write)(struct inode *,struct file *,const char *, int)該方法用來向模塊發(fā)送數(shù)據(jù)。當(dāng)其為 NULL 指針時(shí)將引起 write 系統(tǒng)調(diào)用返回 -EINVALo如果函數(shù)返回一個(gè)非負(fù)值,則表示成功地寫入了多少字節(jié)。3、方法 int (*open)(struct inode *,struct file *)該方法是用來打開模塊的操作, 它是操作在模塊節(jié)點(diǎn)上的第一個(gè)操作, 即使這樣, 該方法還是可以為 NULL指針。如果為NULL指針,則表示該模塊的打開操作永遠(yuǎn)成功, 但系統(tǒng)不會(huì)通知你的模塊程序。4、方法 void (*rele
16、ase)(struct inode *,struct file *)該方法是用來關(guān)閉模塊的操作。當(dāng)節(jié)點(diǎn)被關(guān)閉時(shí)就調(diào)用這個(gè)操作。與open類似,release 也可以為 NULL指針。當(dāng)在你的模塊中需要上面這些方法時(shí),相應(yīng)的方法若沒有,則在structfile_operatio ns中相應(yīng)的地方將其令為 NULL指針。這樣我們需要的大概象下面這樣:struct file_operationsmodulename_fops =NULL,/ modulename_lseekmodulename_read, modulename_write, NULL,/ modulename_readdirNULL
17、,/ modulename_selectNULL,/ modulename_ioctlNULL,/ modulename_mmapmodulename_open, modulename_release, NULL,/ modulename_fsyncNULL,/ modulename_fasyncNULL,/ modulename_check_media_changeNULL/ modulename_revalidate【實(shí)驗(yàn)容】1、編寫一個(gè)簡單的核模塊, 該模塊至少需要有兩個(gè)函數(shù): 一個(gè)是 init_module() 函數(shù), 在把模塊裝載到核時(shí)被調(diào)用, 它為核的某些東西注冊(cè)一個(gè)處理程序, 或
18、是用自 身的代碼取代某個(gè)核函數(shù);另一個(gè)是 cleanup_module() 函數(shù), 在卸載模塊時(shí)被調(diào)用, 其任務(wù)是清除 init_module() 函數(shù)所做的一切操作。編寫完成后進(jìn)行該模塊的編譯、 裝載和卸載操作。2、 向上面模塊中再添加一些新函數(shù),如open() 、release() 、write() 和 read() 函數(shù),并編寫一個(gè)函數(shù)來測試你的模塊能否實(shí)現(xiàn)自己添加的函數(shù)的功能。其中 open() 、 release() 和 write() 函數(shù)都可以是空操作或較少的操作,它們僅僅為結(jié)構(gòu) file_operations 提供函數(shù)指針?!緦?shí)驗(yàn)指導(dǎo)】1 一個(gè)簡單的核模塊1. 1 必要的 he
19、ader 文件:除 了 前 面 講 到 的 頭 文 件 #include <linux/kernel.h> 和 #include <linux/module.h> 外,如果你的核打開了版本檢查,那么我們就還必須增加頭文件 #include <linux/modversions.h> ,否則就會(huì)出錯(cuò)。1.2 init_module() 函數(shù):由于題目的要求不高, 故可只在該函數(shù)里完成一個(gè)打印功能, 如 printk( “ Hello! This is a testing module!n”) ;等。為便于檢查模塊是否裝載成功,我們可以給一個(gè)返回值,如 retu
20、rn 0;若返回一個(gè)非 0 值,則表示 init_module() 失敗,從而不 能裝載模塊。1.3 cleanup_module() 函數(shù):只需用一條打印語句來取消 init_module() 函數(shù)所做的打印功能操作就可以了, 如 printk( “Sorry! The testing module is unloaded now!n” ) ;等。1.4 模塊的編寫:此處把該模塊文件取名為 testmodule.c#include <linux/kernel.h> /在核模塊中共享#include <linux/module.h> /一個(gè)模塊/ 處理 CONFIG_M
21、ODVERSIONS#if CONFIG_MODVERSIONS = 1#define MODVERSIONS#include <linux/modversions.h>#endifint init_module()/ 初始化模塊printk(“ Hello! This is a testing module! n” ) ;return 0void cleanup_module() / 取消 init_module() 函數(shù)所做的打印功能操作printk(“ Sorry! The testing module is unloading now! n” ) ;1.5 模塊的編譯、裝載
22、和卸載:rootlinux /# gcc- o2 - Wall - DMODUL D KERNEL -c testmodule.crootlinux /# ls- s / 在當(dāng)前目錄下查看生成的目標(biāo)文件testmodule.o現(xiàn)在,模塊 testmodule 已經(jīng)編譯好了。用下面命令將它裝載到系統(tǒng)中:rootli nux /# in smod f testmodule.o如果裝載成功, 則在 /proc/modules 文件中就可看到模塊 testmodule ,并可看到 它的主設(shè)備號(hào)。同時(shí)在終端顯示:Hello! This is a testing module! 如果要卸載,就用如下命令:
23、rootlinux /# rmmod testmodule如果卸載成功,則在 /proc/devices 文件中就可看到模塊 testmodule 已經(jīng)不存 在了。同時(shí)在終端顯示:Sorry! The testing module is unloading now!2 向 testmodule 模塊中添加新函數(shù) open() 、 release() 、 write() 和 read()2.1 函數(shù) open( )int open(struct inode *inode, struct file *filp) MOD_INC_USE_COUNT ; / 增加該模塊的用戶數(shù)目 printk(“Th
24、is module is in open!n”) ;return 0;2.2 函數(shù) release( )void release(struct inode *inode, struct file *filp) MOD_DEC_USE_COUNT ; / 該模塊的用戶數(shù)目減 1 printk( “This module is in release!n” ) ;return 0 ;#ifdef DEBUGprintk(release(%p,%p)n, inode , filp)#endif2.3 函數(shù) read()int read(struct inode *inode, struct file *filp,char *buf ,int count) int leave ; if(verify_area(VERIFY_WRITE,buf , count) = DEFAULT)return DEFAULT ;for
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 小企業(yè)勞動(dòng)用工合同
- 夏令營代理商合作協(xié)議新
- 買賣合作協(xié)議合同
- 產(chǎn)品銷售數(shù)據(jù)類表格
- 美甲店裝修施工方案模板
- TCSG 13-2024 高純工業(yè)品氟化鋰
- 《大數(shù)據(jù)技術(shù)導(dǎo)論》-課程標(biāo)準(zhǔn)
- 布簾施工方案
- 水利水電施工方案
- 預(yù)制樁鋼平臺(tái)基礎(chǔ)施工方案
- 金稅四期下的稅務(wù)風(fēng)險(xiǎn)與防范
- 把未來點(diǎn)亮歌詞打印版
- DB44T 887-2011住宅小區(qū)物業(yè)管理服務(wù)規(guī)范
- 國家中醫(yī)藥管理局第3批24個(gè)專業(yè)104個(gè)病種中醫(yī)診療方案
- 國際結(jié)算實(shí)驗(yàn)
- GB/T 8005.3-2008鋁及鋁合金術(shù)語第3部分:表面處理
- 2023年江西工業(yè)貿(mào)易職業(yè)技術(shù)學(xué)院高職單招(語文)試題庫含答案解析
- GB/T 25430-2019石油天然氣鉆采設(shè)備旋轉(zhuǎn)防噴器
- GB/T 19326-2003鋼制承插焊、螺紋和對(duì)焊支管座
- GB/T 1220-2007不銹鋼棒
- 普通話朗讀范文60篇(文本)
評(píng)論
0/150
提交評(píng)論