版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
模塊編程實(shí)驗(yàn)
模塊作為一種抽象數(shù)據(jù)類型,它具有一個(gè)可以通過靜態(tài)內(nèi)核中斷的接口。最小的模塊結(jié)構(gòu)必須包括兩個(gè)函數(shù):init_module()和cleanup_module(),它們?cè)谙到y(tǒng)加載模塊和卸載模塊時(shí)被調(diào)用。也可以編寫一個(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ù)雜的功能,故可以在模塊中加入很多新函數(shù)以實(shí)現(xiàn)所期望的功能。不過加入模塊的每個(gè)新函數(shù)都必須在該模塊加載到內(nèi)核中時(shí)進(jìn)行注冊(cè)。若該模塊是靜態(tài)加載的,則該模塊的所有函數(shù)都是在內(nèi)核啟動(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()中完成。
7.2.1模塊的組織結(jié)構(gòu)一般編譯模塊文件的命令格式如下:#gcc-O2–g-Wall-DMODULE-D__KERNEL__-c–f-I/usr/src/linux-2.4/include//為自己編寫的模塊程序源代碼文件
7.2.2模塊的編譯
7.2.3模塊的加載7.2.4模塊的卸載圖7-1模塊鏈接到內(nèi)核的示意圖7.2.5模塊鏈接到內(nèi)核的示意圖在內(nèi)核是用一個(gè)file結(jié)構(gòu)來識(shí)別模塊,而且內(nèi)核使用結(jié)構(gòu)來訪問模塊程序中的函數(shù)。結(jié)構(gòu)是一個(gè)定義在<linux/fs.h>中的函數(shù)指針表。管理模塊的文件操作,通常也稱為“方法”,它們都為struct提供函數(shù)指針。在struct中的操作一般按如下順序出現(xiàn),除非特別說明,一般它們返回0值時(shí)表示訪問成功;發(fā)生錯(cuò)誤時(shí)會(huì)返回一個(gè)負(fù)的錯(cuò)誤值(目前共有13個(gè)操作):int(*lseek)()、int(*read)()、int(*write)()int(*readdir)()、int(*select)()、int(*ioctl)()int(*mmap)()、int(*open)()、void(*release)()int(*fsync)()、int(*fasync)()int(*check_media_change)()int(*revalidate)()7.2.6模塊管理程序中的文件操作7.3實(shí)驗(yàn)內(nèi)容7.3.4
系統(tǒng)核心寄存器數(shù)值的獲取模塊的編寫#include<linux/kernel.h>//在內(nèi)核模塊中共享
#include<linux/module.h>//一個(gè)模塊
//處理CONFIG_MODVERSIONS#ifCONFIG_MODVERSIONS==1#defineMODVERSIONS#include<linux/modversions.h>#endifintinit_module()//初始化模塊
{printk(“Hello!Thisisatestingmodule!\n”);
return0;
}voidcleanup_module()//取消init_module()函數(shù)所做的打印功能操作
{printk(“Sorry!Thetestingmoduleisunloadingnow!\n”);
}
7.4實(shí)驗(yàn)指導(dǎo)7.4.1一個(gè)簡(jiǎn)單的內(nèi)核模塊模塊的編譯、加載和卸載的過程如下:[root@linux/]#gcc–O2–Wall–DMODULE–D__KERNEL__-ctestmodule.c[root@linux/]#ls–s//在當(dāng)前目錄下查看生成的目標(biāo)文件testmodule.o用下面命令將它加載到系統(tǒng)中:[root@linux/]#insmod–ftestmodule.o如果加載成功,則在/proc/modules文件中就可看到模塊testmodule,并可看到它的主設(shè)備號(hào)。同時(shí)在終端顯示:Hello!Thisisatestingmodule!如果要卸載,就用如下命令:[root@linux/]#rmmodtestmodule如果卸載成功,則在/proc/devices文件中就可看到模塊testmodule已經(jīng)不存在了。同時(shí)在終端顯示:Sorry!Thetestingmoduleisunloadingnow!對(duì)寄存器cr3的訪問,必須在內(nèi)核空間中完成,在用戶程序中被禁止。而采用加載模塊程序的方式就可以做到這一點(diǎn)。下面是程序源代碼:文件名GetCr3.c。此外最好先建立一個(gè)目錄。#include<linux/module.h>intinit_module(){intiValue;__asm____volatile__(“movl%%cr3,%0”:”=r”(iValue));printf(“cr3:%d”,iValue);
return0;}voidcleanup_module(void){printk(“uninstallgetcr3!\n”);}編寫Makefile文件如下:DFLAGS=-D_KERNEL_-DMODULECFLAGS=-O2–g–Wall–Wstrict-prototypes–pipe–l/user/include/linux/GetCr3.o:GetCr3.cgcc–cGetCr3.c$(DFLAGS)$(CFLAGS)–oGetCr3.oclean: rm–f*.o[root@linuxserverroot]#/sbin/insmodGetCr3.oCr3:234320012[root@linuxserverroot]#/sbin/rmmodGetCr3UninstallGetCr3!函數(shù)open()intopen(structinode*inode,structfile*filp){MOD_INC_USE_COUNT;
//增加該模塊的用戶數(shù)目
printk(“Thismoduleisinopen!\n”);
return0;
}函數(shù)release()
voidrelease(structinode*inode,structfile*filp){MOD_DEC_USE_COUNT;//該模塊的用戶數(shù)目減1printk(“Thismoduleisinrelease!\n”);
return0;
#ifdefDEBUGprintk(“release(%p,%p)\n”,inode,filp);
#endif}
7.4.3向模塊中添加新函數(shù)7.4.4模塊的測(cè)試在該模塊程序編譯加載后,再在/dev目錄下創(chuàng)建模塊設(shè)備文件moduledev,使用命令:#mknod/dev/moduledevcmajorminor其中“c”表示moduledev是字符設(shè)備,“major”是moduledev的主設(shè)備號(hào)。(該字符設(shè)備驅(qū)動(dòng)程序編譯加載后,可在/proc/modules文件中獲得主設(shè)備號(hào),或者使用命令:[root@linux/]#cat/proc/modules|awk”\\$2==\”moduledev\”{print\\$1}”獲得主設(shè)備號(hào))#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>main(){inti,testmoduledev;
charbuf[10];
testmoduledev=open(“/dev/moduledev”,O_RDWR);
if(testmoduledev==-1){printf(“Can’topenthefile!\n”);
exit(0);
}read(testmoduledev,buf,10);
for(i=0;i<10;i++)printf(“%d\n”,buf[i]);
close(testmoduledev);
return0;
}模塊程序設(shè)計(jì)思想
系統(tǒng)核心寄存器的數(shù)值在用戶態(tài)下,對(duì)于這些寄存器數(shù)值的訪問一般必須要在內(nèi)核空間中完成,在用戶程序中是被禁止的,因此將獲取寄存器數(shù)值的嵌入式匯編的語句寫入模塊函數(shù),這樣在加載模塊之后,用戶程序就可以從內(nèi)核空間中獲得這些寄存器的數(shù)值。
模塊程序由open_get()、release_get()、read_get()、write_get()、init_module()、cleanup_module()以及一個(gè)數(shù)據(jù)結(jié)構(gòu)Fops_Get七部分組成,各部分的具體功能可見源程序中的注釋。7.4.5系統(tǒng)核心寄存器數(shù)值的獲取實(shí)驗(yàn)結(jié)構(gòu)的定義當(dāng)一個(gè)進(jìn)程試圖對(duì)生成的設(shè)備進(jìn)行操作的時(shí)刻就利用下面這個(gè)數(shù)據(jù)結(jié)構(gòu),這個(gè)結(jié)構(gòu)就是提供給操作系統(tǒng)的接口,它的指針保存在設(shè)備表中,在init_module()中被傳遞給操作系統(tǒng)。structFops_Get={read:device_read,write:device_write,open:device_open,release:device_release,};頭文件及程序定義/*一些必要的頭文件*/#include<linux/kernel.h>#include<linux/module.h>
/*處理CONFIG_MODVERSIONS*/#ifCONFIG_MODVERSIONS==1#defineMODVERSIONS#include<linux/modversions.h>#endif
/*對(duì)于不同的版本需要做一些必要的事情*/#include<linux/fs.h>#include<linux/wrapper.h>
#ifndefKERNEL_VERSION#defineKERNEL_VERSION(a,b,c)((a)*65536+(b)*256+(c))#endif#ifLINUX_VERSION_CODE>KERNEL_VERSION(2,4,0)#include<asm/uaccess.h>/*為了使用__put_user這個(gè)函數(shù)*/#endif#defineSUCCESS0#defineDEVICE_NAME"get_dev"/*申明設(shè)備名,它會(huì)出現(xiàn)在/proc/devices*/#defineBUF_LEN100/*定義此設(shè)備消息緩沖的最大長(zhǎng)度*/
staticintOpen_Get=0;/*為了防止不同的進(jìn)程在同一時(shí)間使用此設(shè)備,
定義此靜態(tài)變量跟蹤其狀態(tài)*/staticcharMessage[BUF_LEN];/*當(dāng)提出請(qǐng)求的時(shí)候,設(shè)備將讀寫的內(nèi)容放在下面的數(shù)組*/staticchar*Message_Ptr;/*在進(jìn)程讀取設(shè)備內(nèi)容的時(shí)候,這個(gè)指針是指向讀取的位置*/staticintMajor;/*主設(shè)備號(hào)作為全局變量以便于這個(gè)設(shè)備在注冊(cè)和釋放的時(shí)候使用*/頭文件及程序定義/*初始化信息,注意不要使用讀寫內(nèi)容的長(zhǎng)度超過緩沖區(qū)的長(zhǎng)度,特別是運(yùn)行內(nèi)核模式時(shí),否則如果出現(xiàn)緩沖上溢則可能導(dǎo)致系統(tǒng)崩潰,因此在測(cè)試程序Test.c中只讀取了10個(gè)字符*/sprintf(Message,"IfItoldyouonce,Itoldyou%dtimes-%s",counter++,"Helo,world\n");Message_Ptr=Message;/*當(dāng)這個(gè)文件被打開的時(shí)候,必須確認(rèn)該模塊沒有被移走然后增加此模塊的用戶數(shù)目,與release()函數(shù)中的MOD_DEC_USE_COUNT;這條語句相對(duì)應(yīng)。在執(zhí)行cleanup_module()這個(gè)函數(shù)移去模塊時(shí),根據(jù)這個(gè)數(shù)字決定是否可移去,如果不是0則表明還有進(jìn)程在使用這個(gè)模塊,不能移走*/MOD_INC_USE_COUNT;returnSUCCESS;}open()函數(shù)release()函數(shù)release()函數(shù)用于進(jìn)程關(guān)閉該設(shè)備特殊文件。#ifLINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0)staticintrelease_get(structinode*inode,structfile*file)#elsestaticvoidrelease_get(structinode*inode,structfile*file)#endif{printk("Thismoduleisinrelease\n");#ifdefDEBUGprintk("release_get(%p,%p)\n",inode,file);#endif
Open_Get--;/*為下一個(gè)使用這個(gè)設(shè)備的進(jìn)程做準(zhǔn)備*/
/*減少這個(gè)模塊使用者的數(shù)目,否則將使得模塊使用者的數(shù)目永遠(yuǎn)不會(huì)為0,
就永遠(yuǎn)不能釋放這個(gè)模塊.與open()函數(shù)中的MOD_INC_USE_COUNT;
這條語句相對(duì)應(yīng)*/MOD_DEC_USE_COUNT;#ifLINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0)return0;#endif}read()函數(shù)當(dāng)打開此設(shè)備文件以后,read()函數(shù)用于讀取數(shù)據(jù),測(cè)試程序Test.c就是調(diào)用這個(gè)函數(shù)將10個(gè)字符讀入buf數(shù)組然后輸出。#ifLINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0)staticssize_tread_get(structfile*file,char*buffer,/*把讀出的數(shù)據(jù)放到這個(gè)緩沖區(qū),Test.c調(diào)用此函數(shù)時(shí)為數(shù)組buf[]*/size_tlength,/*緩沖區(qū)的長(zhǎng)度,Test.c調(diào)用此函數(shù)時(shí)賦值為10*/loff_t*offset)/*文件中的偏移*/#elsestaticintread_get(structinode*inode,structfile**buffer,intlength)#endif{inti,bytes_read=0;/*i用于后邊的循環(huán),bytes_read是實(shí)際讀出的字節(jié)數(shù)*//*驗(yàn)證buffer是否可用*/if(verify_area(VERIFY_WRITE,buffer,length)==-EFAULT)return-EFAULT;write()函數(shù)write()函數(shù)用于將數(shù)據(jù)寫入著這個(gè)設(shè)備文件。但這里的write()函數(shù)是個(gè)空操作,實(shí)際調(diào)用時(shí)什么也不做,僅僅為Fops結(jié)構(gòu)提供函數(shù)指針。#ifLINUX_VERSION_CODE>=KERNEL_VERSION(2,4,0)staticssize_twrite_get(structfile*char*buffer,size_tlength,loff_t*offset)#elsestaticintwrite_get(structinode*inode,structfile*char*bffer,intlength)#endif{returnlength;}init_module()函數(shù)init_module()這個(gè)函數(shù)用來初始化這個(gè)模塊---注冊(cè)該字符設(shè)備.init_module()函數(shù)調(diào)用nodule_register_chrdev,把設(shè)備驅(qū)動(dòng)程序添加到內(nèi)核的字符設(shè)備驅(qū)動(dòng)表中,它返回這個(gè)驅(qū)動(dòng)程序所使用的主設(shè)備號(hào)。intinit_module(){printk("\nHello!Thisismymodule---'Get'!\n");
/*注冊(cè)字符設(shè)備,注冊(cè)后在/proc/devices中可以看到這個(gè)字符設(shè)備的主設(shè)備號(hào)*/Major=register_chrdev(0,DEVICE_NAME,&Fops_Get);/*異常處理*/if(Major<0){printk("%sdevicefailedwith%d\n","Sorry,registeringthecharacter:(",Major);returnMajor;}init_module()函數(shù)/*一些提示信息,由于我在虛擬機(jī)中編程時(shí)無法使用中文,所以使用英文提示*/Printk("%sThemajordevicenumberis%d.\n\n\n","Registerationisasucces:)",Major);printk("Ifyouwanttotalktothedevicedriver,\n");printk("you'llhavetocreatadevicefile.\n");printk("Isuggestyouuse:\n");printk("mknod<name>c%d<minor>\n",Major);printk("Youcantrydifferentminornumbers%s","andsomethinginterestingwillhappen.\n\n\n");printk("Herearethevalueof23importantregistersinmysystem:\n");
/*定義了23個(gè)整型變量用以存放寄存器的數(shù)值,并在模塊加載時(shí)顯示在屏幕上*/intiValue01,iValue02,iValue03,iValue04,iValue05,iValue06,iValue07,iValue08,iValue09,iValue10,iValue11,iValue12,iValue13,iValue14,iValue15,iValue16,iValue17,iValue18,iValue19,iValue20,iValue21,iValue22,iValue23;__asm____volatile__("movl%%eax,%0":"=r"(iValue01));__asm____volatile__("movl%%ebx,%0":"=r"(iValue02));__asm____volatile__("movl%%ecx,%0":"=r"(iValue03));__asm____volatile__("movl%%edx,%0":"=r"(iValue04));__asm____volatile__("movl%%esp,%0":"=r"(iValue05));__asm____volatile__("movl%%ebp,%0":"=r"(iValue06));__asm____volatile__("movl%%esi,%0":"=r"(iValue07));__asm____volatile__("movl%%edi,%0":"=r"(iValue08));__asm____volatile__("movl%%cs,%0":"=r"(iValue09));__asm____volatile__("movl%%ds,%0":"=r"(iValue10));__asm____volatile__("movl%%ss,%0":"=r"(iValue11));__asm____volatile__("movl%%es,%0":"=r"(iValue12));__asm____volatile__("movl%%fs,%0":"=r"(iValue13));__asm____volatile__("movl%%gs,%0":"=r"(iValue14));__asm____volatile__("movl%%cr0,%0":"=r"(iValue15));__asm____volatile__("movl%%cr2,%0":"=r"(iValue16));__asm____volatile__("movl%%cr3,%0":"=r"(iValue17));__asm____volatile__("movl%%dr0,%0":"=r"(iValue18));__asm____volatile__("movl%%dr1,%0":"=r"(iValue19));__asm____volatile__("movl%%dr2,%0":"=r"(iValue20));__asm____volatile__("movl%%dr3,%0":"=r"(iValue21));__asm____volatile__("movl%%dr6,%0":"=r"(iValue22));__asm____volatile__("movl%%dr7,%0":"=r"(iValue23));printk("EAX:%0x",iValue01);printk("EBX:%0x",iValue02);printk("ECX:%0x",iValue03);printk("EDX:%0x",iValue04);printk("ESP:%0x",iValue05);printk("EBP:%0x\n",iValue06);printk("ESI:%0x",iValue07);printk("EDI:%0x",iValue08);printk("CS:%0x",iValue09);printk("DS:%0x",iValue10);printk("SS:%0x",iValue11);printk("ES:%0x\n",iValue12);printk("FS:%0x",iValue13);printk("GS:%0x",iValue14);printk("CR0:%0x",iValue15);printk("CR2:%0x",iValue16);printk("CR3:%0x",iValue17);printk("DR0:%0x\n",iValue18);printk("DR1:%0x",iValue19);printk
溫馨提示
- 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. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度環(huán)保設(shè)備研發(fā)與銷售服務(wù)合同3篇
- 2025年度大型水庫(kù)生態(tài)保護(hù)與恢復(fù)工程承包合同
- 2025年度個(gè)人汽車抵押貸款合同簽訂指南2篇
- 二零二五年度船舶消毒防疫合作協(xié)議3篇
- 二零二五年度車輛運(yùn)輸合同糾紛解決機(jī)制合同4篇
- 二零二五年度出租車智能調(diào)度系統(tǒng)服務(wù)合同2篇
- 二零二四年物業(yè)管理垃圾處理合同
- 二零二五年度攤位租賃與旅游推廣合同3篇
- 2025年個(gè)人房產(chǎn)抵押貸款合同(風(fēng)險(xiǎn)管理與法律合規(guī)版)2篇
- 二零二五年度商務(wù)公寓短期住宿合同模板3篇
- 幼兒平衡車訓(xùn)練課程設(shè)計(jì)
- 肩袖損傷的護(hù)理查房課件
- 2023屆北京市順義區(qū)高三二模數(shù)學(xué)試卷
- 公司差旅費(fèi)報(bào)銷單
- 我國(guó)全科醫(yī)生培訓(xùn)模式
- 2021年上海市楊浦區(qū)初三一模語文試卷及參考答案(精校word打印版)
- 八年級(jí)上冊(cè)英語完形填空、閱讀理解100題含參考答案
- 八年級(jí)物理下冊(cè)功率課件
- DBJ51-T 188-2022 預(yù)拌流態(tài)固化土工程應(yīng)用技術(shù)標(biāo)準(zhǔn)
- 《長(zhǎng)津湖》電影賞析PPT
- 銷售禮儀培訓(xùn)PPT
評(píng)論
0/150
提交評(píng)論