【操作系统实验】设备驱动(Linux环境下)
【實(shí)驗(yàn)?zāi)康摹?/strong>
實(shí)驗(yàn)?zāi)康?#xff1a;熟悉Linux下驅(qū)動(dòng)程序設(shè)計(jì)
?????編譯內(nèi)核
實(shí)驗(yàn)要求:在Linux系統(tǒng)下,編譯內(nèi)核,并在該內(nèi)核下完成實(shí)驗(yàn);
?????自主設(shè)計(jì)驅(qū)動(dòng)程序,完成驅(qū)動(dòng)程序的安裝
【實(shí)驗(yàn)內(nèi)容】
1.編譯內(nèi)核,構(gòu)造內(nèi)核源碼樹(shù)
2.ubantu14.04 32位下編寫(xiě)hello world程序以及加載驅(qū)動(dòng)
3.ubantu14.04第二個(gè)memory驅(qū)動(dòng)程序
4.ubantu14.04第三個(gè)使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng)
5.Linux設(shè)備驅(qū)動(dòng)中的阻塞與非阻塞I/O
【實(shí)驗(yàn)環(huán)境】(含主要設(shè)計(jì)設(shè)備、器材、軟件等)
Pc電腦一臺(tái)
【實(shí)驗(yàn)步驟、過(guò)程】(含原理圖、流程圖、關(guān)鍵代碼,或?qū)嶒?yàn)過(guò)程中的記錄、數(shù)據(jù)等)
1.編譯內(nèi)核,構(gòu)造內(nèi)核源碼樹(shù)(itc-centos)
(1)編譯指令
①指導(dǎo)書(shū)上的指令
②自己查閱的資料
??以一個(gè)不是root用戶的戶口,創(chuàng)建一個(gè)以~/rpmbuild為基礎(chǔ)的目錄樹(shù):
??以一個(gè)不是root用戶的普通戶口,執(zhí)行以下指令來(lái)安裝源代碼組件:
[user@host] $ rpm -i http://vault.centos.org/7.7.1908/updates/Source/SPackages /kernel-3.10.0-1062.9.1.e17.src.rpm 2>&1 | grep -v exist解壓及預(yù)備源代碼文件:
[user@host] $ cd ~/rpmbuild/SPECS [user@host SPECS] $ rpmbuild -bp --target = $(uname -m) kernel.spec??其中,$(uname -m)這條命令,可以將目標(biāo)結(jié)構(gòu)設(shè)置為你現(xiàn)有的內(nèi)核的結(jié)構(gòu),一般來(lái)說(shuō)這是可行的,因?yàn)槎鄶?shù)人需要以i686或x86_64為目標(biāo)。
(2)編譯過(guò)程截圖
????????????圖1 編譯內(nèi)核過(guò)程
(3)編譯過(guò)程注意事項(xiàng)
??如果這一步中沒(méi)有建立內(nèi)核源碼樹(shù),按下面步驟進(jìn)行,雖然能夠生成hello.ko,但執(zhí)行sudo insmod hello.ko后,執(zhí)行l(wèi)smod會(huì)沒(méi)反應(yīng),導(dǎo)致系統(tǒng)報(bào)告問(wèn)題,會(huì)導(dǎo)致下次開(kāi)機(jī)或重啟時(shí)有問(wèn)題,若啟動(dòng)不了,可以進(jìn)入recovery模式,執(zhí)行fsck,開(kāi)機(jī)時(shí)做嵌入式linux開(kāi)發(fā)一般在PC機(jī)上編譯好了,下到板子上去運(yùn)行,板子上的linux內(nèi)核和PC機(jī)上的linux版本很多時(shí)候都是不一樣的,比如pc機(jī)上的是linux2.6,板子上的是linux3.1,這個(gè)時(shí)候就要下linux3.1的內(nèi)核,用它編譯的驅(qū)動(dòng)模塊在板子上才能加載上,不然會(huì)出錯(cuò)。
??在執(zhí)行最后一條指令make modules和make modules_install時(shí),執(zhí)行結(jié)束之后,會(huì)在/lib/modules下生成新的目錄/lib/modules/3.13.0-32-generic/,但若由于主機(jī)本身內(nèi)核版本就為3.13.0-32-generic,所以/lib/modules/3.13.0-32-generic/本身就存在,此時(shí)這兩條指令make modules和make modules_install就不需要執(zhí)行了。
2.ubantu14.04 32位下編寫(xiě)hello world程序以及加載驅(qū)動(dòng)
(1)實(shí)驗(yàn)步驟
①編寫(xiě)hello. c程序并寫(xiě)Makefile文件;
②之后通過(guò)make指令,生成hello.ko等其他文件;
③執(zhí)行sudo insmod hello.ko,在lsmod即可驗(yàn)證模塊是否已裝載,最后rmmod移出模塊;
④通過(guò)cat /var/log/syslog | grep world來(lái)觀察其輸出。
(2)實(shí)驗(yàn)過(guò)程截圖
??????????圖2 hello.c代碼
??????????圖3 對(duì)于Makefile內(nèi)容
??????????圖4 執(zhí)行make指令
??????????圖5 執(zhí)行l(wèi)smod指令
??????????圖6 運(yùn)行結(jié)果
(3)實(shí)驗(yàn)過(guò)程注意事項(xiàng)
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules??這句是Makefile的規(guī)則:這里的$(MAKE)就相當(dāng)于make,-C 選項(xiàng)的作用是指將當(dāng)前工作目錄轉(zhuǎn)移到你所指定的位置。“M=”選項(xiàng)的作用是,當(dāng)用戶需要以某個(gè)內(nèi)核為基礎(chǔ)編譯一個(gè)外部模塊的話,需要在make modules 命令中加入“M=dir”,程序會(huì)自動(dòng)到你所指定的dir目錄中查找模塊源碼,將其編譯,生成ko文件。
??一定要實(shí)現(xiàn)查看電腦Linux的內(nèi)核版本,機(jī)房不同電腦的內(nèi)核版本可能不一樣,要事先查好之后并且在Makefile文件中版本號(hào)要改。
??用printk,內(nèi)核會(huì)根據(jù)日志級(jí)別,可能把消息打印到當(dāng)前控制臺(tái)上,這個(gè)控制臺(tái)通常是一個(gè)字符模式的終端、一個(gè)串口打印機(jī)或是一個(gè)并口打印機(jī)。這些消息正常輸出的前提是──日志輸出級(jí)別小于console_loglevel(在內(nèi)核中數(shù)字越小優(yōu)先級(jí)越高)。
3.ubantu14.04第二個(gè)memory驅(qū)動(dòng)程序
(1)實(shí)驗(yàn)步驟
①編寫(xiě)c程序并寫(xiě)Makefile文件;
②根據(jù)設(shè)備號(hào),從內(nèi)核空間將數(shù)據(jù)取出,寫(xiě)入相應(yīng)的設(shè)備空間內(nèi);
③通過(guò)程序創(chuàng)建主從設(shè)備,將數(shù)據(jù)寫(xiě)入;
④再通過(guò)模塊功能讀出,觀察其輸出。
(2)實(shí)驗(yàn)過(guò)程截圖
①到包含Makefile和mydm1.c的目錄下執(zhí)行make,生成mydm1.ko;
②執(zhí)行sudo insmod mydm1.ko;
③驗(yàn)證:lsmod | grep mydm1
④需要?jiǎng)?chuàng)建一個(gè)文件(該設(shè)備文件用于和設(shè)備驅(qū)動(dòng)操作)
mknod /dev/fgj c 224 0 c代表字符設(shè)備 224為主設(shè)備號(hào),0為從設(shè)備號(hào)
⑤ gcc test.c
主要代碼如下:
1.mydm1.c:
2.Makefile:
obj-m := mydm1.o #KERNELDIR := /lib/modules/3.16.61-32-generic/build KERNELDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install clean:rm *.o *.ko *.mod.c *.order *.symvers3.test.c:
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h>void main(void) {int fd;int i;char data[256];int retval;fd = open("/dev/fgj",O_RDWR);if(fd==-1){perror("erroropen\n");exit(-1);}printf("open/dev/fgjsuccessfully\n");//寫(xiě)數(shù)據(jù)retval = write(fd,"fgj",3);if(retval==-1){perror("writeerror\n");exit(-1);}printf("write successfully\n");//讀數(shù)據(jù)retval=read(fd,data,3);if(retval==-1){perror("readerror\n");exit(-1);}data[retval]=0;printf("readsuccessfully:%s\n",data);//關(guān)閉設(shè)備close(fd); }運(yùn)行結(jié)果如下:
?? ?? ?? ?? ??圖7 執(zhí)行make命令
?? ?? ?? ?? ??圖8 執(zhí)行結(jié)果
(3)實(shí)驗(yàn)過(guò)程注意事項(xiàng)
①保證/dev/fgj有讀寫(xiě)權(quán)限 chmod 666 /dev/fgj;
②printk打印的消息若滅有在控制臺(tái)上顯示,可以同構(gòu)dmesg命令或查看系統(tǒng)的日志文件cat /var/log/syslog命令看到;
③驅(qū)動(dòng)編譯:gcc必須用系統(tǒng)自帶的版本,gcc -v查看當(dāng)前版本, 否則insmod后,lsmod會(huì)沒(méi)反應(yīng),系統(tǒng)直接卡死,注銷也不行,只能重啟;
4.ubantu14.04第三個(gè)使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng)
(1)實(shí)驗(yàn)步驟
①編寫(xiě)c程序并寫(xiě)Makefile文件;
②執(zhí)行:make ,然后sudo insmod globalmem.ko;
③驗(yàn)證:lsmod 可以看到該模塊,mknod /dev/globalmem c 354 0, echo ‘good nihao’ > /dev/globalmem, cat /dev/globalmem可以看到輸出good nihao;
(2)實(shí)驗(yàn)過(guò)程截圖
代碼如下:
2.Makefile:
KERNELDIR := /lib/modules/$(shell uname -r)/build obj-m := globalmem.o modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules modules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean:make -C $(KERNELDIR) M=`pwd` modules clean rm -rf modules.order??????????圖9 執(zhí)行make指令
??????????圖10 執(zhí)行l(wèi)smod指令
??????????圖11 驗(yàn)證結(jié)果
5.Linux設(shè)備驅(qū)動(dòng)中的阻塞與非阻塞I/O
(1)實(shí)驗(yàn)內(nèi)容
??阻塞和非阻塞I/O是設(shè)備訪問(wèn)的兩種不同模式,驅(qū)動(dòng)程序可以靈活的支持用戶空間對(duì)設(shè)備的這兩種訪問(wèn)方式。本例子講述了這兩者的區(qū)別并實(shí)現(xiàn)I/O的等待隊(duì)列機(jī)制,并進(jìn)行了用戶空間的驗(yàn)證。
基本概念:
1> 阻塞操作是指在執(zhí)行設(shè)備操作時(shí),若不能獲得資源,則掛起進(jìn)程直到滿足操作條件后再進(jìn)行操作。被掛起的進(jìn) 程進(jìn)入休眠,被從調(diào)度器移走,直到條件滿足。
2> 非阻塞操作在不能進(jìn)行設(shè)備操作時(shí),并不掛起,它或者放棄,或者不停地查詢,直到可以進(jìn)行操作。非阻塞應(yīng)用程序通常使用select系統(tǒng)調(diào)用查詢是否可以對(duì)設(shè)備進(jìn)行無(wú)阻塞的訪問(wèn)最終會(huì)引發(fā)設(shè)備驅(qū)動(dòng)中poll函數(shù)執(zhí)行。
(2)實(shí)驗(yàn)過(guò)程截圖
主要代碼如下;
????????????圖12 運(yùn)行結(jié)果1
????????????圖13 運(yùn)行結(jié)果2
【實(shí)驗(yàn)結(jié)果或總結(jié)】(對(duì)實(shí)驗(yàn)結(jié)果進(jìn)行相應(yīng)分析,或總結(jié)實(shí)驗(yàn)的心得體會(huì),并提出實(shí)驗(yàn)的改進(jìn)意見(jiàn))
1.在編寫(xiě) hello world 程序以及加載驅(qū)動(dòng)的時(shí)候,module_init(hello_init); module_exit(hello_exit); 這兩個(gè)是函數(shù)的入口地址和出口地址。同時(shí)Makefile文件記得更改KERNELDIR := /lib/modules/3.16.61-32-generic/build的版本號(hào),包括32也需要改成自己電腦相匹配的。
2.$(MAKE) -C (KERNELDIR)M=(KERNELDIR) M=(KERNELDIR)M=(PWD) modules 這句是 Makefile 的規(guī)則:這里的$(MAKE)就相當(dāng)于 make,-C 選項(xiàng)的作用是指將當(dāng)前,工作目錄轉(zhuǎn)移到你所指定的位置。“M=”選項(xiàng)的作用是,當(dāng)用戶需要以某個(gè)內(nèi)核為基礎(chǔ)。
3.通過(guò)查閱相關(guān)資料,我明白了Makefile文件的作用,它相當(dāng)于是覆寫(xiě)了make指令,讓make指令的指向目標(biāo)變?yōu)楫?dāng)前目錄下的文件了。而sudo的作用在于,普通用戶在安裝時(shí),是沒(méi)有權(quán)限的,因此要通過(guò)sudo來(lái)獲取超級(jí)用戶權(quán)限。
4.在第二個(gè)memory驅(qū)動(dòng)程序中 ret=register_chrdev( devMajor,“mydm1”,&simple_fops); register_chrdev 函數(shù)用于在內(nèi)核空間,把驅(qū)動(dòng) 和/dev 下設(shè)備文件鏈接在一起,mydm1.c :read()函數(shù),將內(nèi)核空間中的數(shù)據(jù)復(fù)制到用戶空間中,從而讀取出數(shù)據(jù)。在驗(yàn)證過(guò)程中,首先是在內(nèi)核的設(shè)備區(qū)創(chuàng)建了對(duì)應(yīng)程序的設(shè)備區(qū),再通過(guò)測(cè)試程序往里面寫(xiě)入數(shù)據(jù),最后再在用戶空間中讀出來(lái)。Write()函數(shù)則相反。
5.Makefile 里的KERNELDIR := /lib/modules/$(shell uname -r)/build 則是用腳本的方法獲取 uname -r 即可不用對(duì)代碼進(jìn)行修改,動(dòng)態(tài)獲取內(nèi)核的版本信息。
6.使用文件私有數(shù)據(jù)的globalmem的設(shè)備驅(qū)動(dòng) :用到了內(nèi)核區(qū)的字符設(shè)備,將輸入的字符存儲(chǔ)到全局內(nèi)存區(qū)域,再?gòu)挠脩艨臻g中訪問(wèn)這個(gè)區(qū)域,獲取到其中的數(shù)據(jù)。struct globalmem_dev { struct cdev cdev; //cdev 結(jié)構(gòu)體 unsigned char mem[GLOBALMEM_SIZE]; //全局內(nèi)存 }; globalmem 的設(shè)備結(jié)構(gòu)體:包含了對(duì)應(yīng)于 globalmem 字符設(shè)備的 cdev 和 使用內(nèi)存 mem[GLOBALMEM_SIZE],其他與上一個(gè)實(shí)驗(yàn)類似。增加了一個(gè)ioctl函數(shù):ioctl()函數(shù)接受的 MEM_CLEAR 命令,這個(gè)命令將全局內(nèi)存的有效數(shù)據(jù)長(zhǎng)度 清零,對(duì)于設(shè)備不支持的命令,ioctl()函數(shù)應(yīng)該返回-EINVAL。,mknod /dev/globalmem c 354 0, echo ‘good nihao’ > /dev/globalmem, cat /dev/globalmem 即可驗(yàn)證輸出 ,cat是讀出,echo是寫(xiě)入。
??最后感謝倪福川老師以及各位同學(xué)給我的幫助,通過(guò)一學(xué)期對(duì)于操作系統(tǒng)理論和實(shí)驗(yàn)的學(xué)習(xí),讓我對(duì)操作系統(tǒng)加深了理解,在自己原有知識(shí)的基礎(chǔ)上得到了更深層次的感悟,我也會(huì)把在操作系統(tǒng)課程之中學(xué)到的知識(shí)應(yīng)用到今后的學(xué)習(xí)生活中去,思考問(wèn)題也要更細(xì)致,要學(xué)會(huì)從底層去思考問(wèn)題的起源,并學(xué)會(huì)從底層去解決問(wèn)題。最后再一次感謝倪福川老師這一學(xué)期以來(lái)的諄諄教誨,我定當(dāng)銘記于心,認(rèn)真完成后續(xù)課程的學(xué)習(xí)。
總結(jié)
以上是生活随笔為你收集整理的【操作系统实验】设备驱动(Linux环境下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Mysql存储结构B树与B+树与索引
- 下一篇: linux字体使用教程,Ubuntu 字