于PCI9656設(shè)備驅(qū)動(dòng)程序的Linu2.6內(nèi)核研究
時(shí)間:2022-11-17 09:45:00
導(dǎo)語(yǔ):于PCI9656設(shè)備驅(qū)動(dòng)程序的Linu2.6內(nèi)核研究一文來(lái)源于網(wǎng)友上傳,不代表本站觀點(diǎn),若需要原創(chuàng)文章可咨詢客服老師,歡迎參考。
摘要:本文以64位PCI總線接口芯片pci9656的設(shè)備驅(qū)動(dòng)程序為基礎(chǔ),比較了Linux2.6內(nèi)核與2.4內(nèi)核的區(qū)別,設(shè)計(jì)與開發(fā)了在Linux2.6內(nèi)核下PCI9656設(shè)備驅(qū)動(dòng)程序,進(jìn)而研究了2.6內(nèi)核的內(nèi)存和中斷管理機(jī)制。
關(guān)鍵字:Linux2.6;設(shè)備驅(qū)動(dòng)程序;PCI9656
1引言
Linux操作系統(tǒng)因?yàn)槠涓咝?、安全、可?dòng)態(tài)加載及源代碼開放等特點(diǎn),深受設(shè)備驅(qū)動(dòng)程序開發(fā)人員的喜愛。系統(tǒng)內(nèi)核大部分獨(dú)立于底層硬件運(yùn)行,用戶無(wú)需關(guān)心硬件問題,而用戶操作是通過(guò)一組標(biāo)準(zhǔn)化的調(diào)用來(lái)完成。設(shè)備驅(qū)動(dòng)程序的任務(wù)是將這些調(diào)用映射到作用于實(shí)際硬件設(shè)備的特定操作上,該編程接口能夠使得驅(qū)動(dòng)程序獨(dú)立于內(nèi)核的其他部分來(lái)搭建,在需要時(shí)才動(dòng)態(tài)加載到內(nèi)核。這種模塊化的特點(diǎn),使得Linux設(shè)備驅(qū)動(dòng)程序的編寫過(guò)程變得清晰簡(jiǎn)單。
目前,為滿足日益龐大的數(shù)據(jù)處理需要,基于64位PCI總線接口設(shè)備的研究開發(fā)顯得尤為重要。因而本文將基于PLX公司推出的PCI總線接口芯片PCI9656,設(shè)計(jì)開發(fā)在Linux2.6內(nèi)核下的設(shè)備驅(qū)動(dòng)程序,進(jìn)而對(duì)2.6內(nèi)核的內(nèi)存和中斷管理機(jī)制進(jìn)行分析研究。
2Linux2.6與2.4內(nèi)核的比較
2.1系統(tǒng)穩(wěn)定性
為了徹底防止對(duì)正在被使用的內(nèi)核模塊進(jìn)行錯(cuò)誤操作,2.6內(nèi)核在加載和導(dǎo)出內(nèi)核模塊方面都較2.4內(nèi)核進(jìn)行了改進(jìn),避免了用戶執(zhí)行將導(dǎo)致系統(tǒng)崩潰的操作,例如強(qiáng)制刪除模塊等。同時(shí),當(dāng)驅(qū)動(dòng)程序需要在多個(gè)文件中包含<linux/module.h>頭文件時(shí),不必定義宏__NO_VERSION__來(lái)檢查內(nèi)核的版本。
2.2統(tǒng)一設(shè)備模型
統(tǒng)一設(shè)備模型的創(chuàng)建是2.6內(nèi)核最重要的變化之一。它促進(jìn)了模塊接口的標(biāo)準(zhǔn)化,其目的是更好地控制和管理設(shè)備,主要包括:更準(zhǔn)確地確定系統(tǒng)設(shè)備,更高效的進(jìn)行電源管理以及改進(jìn)的系統(tǒng)總線結(jié)構(gòu)管理。
2.3內(nèi)核基礎(chǔ)設(shè)施
2.6內(nèi)核為了區(qū)別以.o為擴(kuò)展名的常規(guī)對(duì)象文件,將內(nèi)核模塊的擴(kuò)展名改為.ko。相對(duì)于2.4內(nèi)核下系統(tǒng)所支持的RAM為4GB而言,2.6內(nèi)核下系統(tǒng)支持更大數(shù)量的RAM,在分頁(yè)模式下最高可達(dá)64GB。同時(shí),2.6內(nèi)核優(yōu)化了I/O調(diào)度器,確保不會(huì)有進(jìn)程駐留在隊(duì)列中過(guò)長(zhǎng)時(shí)間等待輸入/輸出操作,使得I/O操作的響應(yīng)更為迅速。
2.4外部設(shè)備
在2.4內(nèi)核中有約束大型系統(tǒng)的限制,比如支持的每一類設(shè)備的最大數(shù)量為256。而2.6內(nèi)核則徹底地打破了這些限制,可以支持4095種主要的設(shè)備類型,每一個(gè)單獨(dú)的類型又可以支持超過(guò)一百萬(wàn)個(gè)的子設(shè)備。
3Linux2.6內(nèi)核下PCI設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)
3.1PCI設(shè)備驅(qū)動(dòng)程序中核心數(shù)據(jù)結(jié)構(gòu)
在2.6內(nèi)核下使用file_operations數(shù)據(jù)結(jié)構(gòu),來(lái)建立設(shè)備驅(qū)動(dòng)程序中的函數(shù)與主設(shè)備號(hào)(majornumber)之間的對(duì)應(yīng)關(guān)系。該數(shù)據(jù)結(jié)構(gòu)中包含了指向驅(qū)動(dòng)程序內(nèi)部大多數(shù)函數(shù)的指針,描述了虛擬文件系統(tǒng)如何操作一個(gè)打開的外圍設(shè)備。因而file_operations結(jié)構(gòu)是驅(qū)動(dòng)程序向內(nèi)核其他部分提供的一個(gè)統(tǒng)一的標(biāo)準(zhǔn)設(shè)備接口。
file結(jié)構(gòu)是設(shè)備驅(qū)動(dòng)程序使用的另一個(gè)重要的數(shù)據(jù)結(jié)構(gòu),指示當(dāng)前系統(tǒng)中已打開的文件。它在C語(yǔ)言庫(kù)中定義,在調(diào)用內(nèi)核open函數(shù)時(shí)創(chuàng)建,并傳遞給在該設(shè)備上進(jìn)行操作的所有函數(shù),直到最后的close函數(shù)。file結(jié)構(gòu)中還包含了指向它所擁有的file_operations結(jié)構(gòu)的指針。
inode結(jié)構(gòu)由內(nèi)核自動(dòng)生成,代表已打開文件的描述符,與每個(gè)打開的文件一一對(duì)應(yīng)。它包含了兩個(gè)重要的結(jié)構(gòu)成員:dev_t擴(kuò)展到32位,其中12位主設(shè)備號(hào),20位從設(shè)備號(hào),而cdev用于存儲(chǔ)一個(gè)指向字符設(shè)備文件的指針。
3.2驅(qū)動(dòng)程序與內(nèi)核和外部設(shè)備間的關(guān)系
(1)通過(guò)Linux提供的系統(tǒng)調(diào)用函數(shù)(例如init_module等)進(jìn)入內(nèi)核,這些函數(shù)在2.6內(nèi)核版本下總共有兩百多個(gè),提供了幾乎所有應(yīng)用程序進(jìn)入內(nèi)核所需要執(zhí)行的操作。
(2)系統(tǒng)的內(nèi)核函數(shù)都有“sys_”前綴(例如函數(shù)sys_init_module),應(yīng)用程序通過(guò)訪問設(shè)備文件系統(tǒng)來(lái)調(diào)用這些函數(shù)。這一層主要是“devfs”(devicefilesystem)文件管理機(jī)制,它是從普通文件和設(shè)備文件抽象出來(lái)的一個(gè)文件系統(tǒng)層,完成進(jìn)入具體的設(shè)備文件操作之前的準(zhǔn)備工作。
(3)由設(shè)備驅(qū)動(dòng)程序提供具體的函數(shù),來(lái)完成對(duì)硬件設(shè)備的各種操作。特別的對(duì)于PCI9656來(lái)說(shuō),就是通過(guò)PCI接口對(duì)設(shè)備的寄存器和存儲(chǔ)器進(jìn)行訪問操作,例如調(diào)用register_chrdev等函數(shù)來(lái)初始化芯片內(nèi)部的狀態(tài)寄存器和配置寄存器。
3.3PCI9656芯片的操作流程
PCI總線是目前最常用的外設(shè)總線之一,Linux的PCI內(nèi)核代碼為PCI設(shè)備驅(qū)動(dòng)程序的開發(fā)提供了強(qiáng)大的支持。PCI9656的驅(qū)動(dòng)程序主要包括以下幾個(gè)方面:設(shè)備初始化,為PCI芯片分配內(nèi)存資源,實(shí)現(xiàn)數(shù)據(jù)的讀寫功能,中斷處理,系統(tǒng)收回內(nèi)存資源,關(guān)閉設(shè)備等。
4.Linux2.6內(nèi)核下內(nèi)存和中斷管理的研究
2.6內(nèi)核應(yīng)用了許多新技術(shù)來(lái)實(shí)現(xiàn)對(duì)各類外部設(shè)備驅(qū)動(dòng)程序的更好支持。下面結(jié)合PCI9656驅(qū)動(dòng)程序中的內(nèi)存和中斷管理,進(jìn)一步分析和研究2.6內(nèi)核對(duì)內(nèi)存和中斷進(jìn)行的改進(jìn)和優(yōu)化。
4.1內(nèi)存管理
在Linux內(nèi)存管理器中,頁(yè)表保持對(duì)進(jìn)程使用的內(nèi)存物理頁(yè)的追蹤,它將虛擬頁(yè)映射到物理頁(yè)上。系統(tǒng)必須找到映射到該頁(yè)的每一個(gè)進(jìn)程,將使用較少的頁(yè)置換出去,這樣進(jìn)程中相應(yīng)頁(yè)的頁(yè)表?xiàng)l目才能被更新。隨著在系統(tǒng)中運(yùn)行的進(jìn)程數(shù)量的增加,將這些頁(yè)置換出去的工作量也會(huì)急劇增加。
為解決此問題,2.6內(nèi)核引入了反向映射機(jī)制(reversemapping),內(nèi)存管理器為每一個(gè)物理頁(yè)建立一個(gè)鏈表,包含指向當(dāng)前映射頁(yè)的每個(gè)進(jìn)程的頁(yè)表?xiàng)l目(page-tableentry)的指針。該鏈表叫PTE鏈,它極大地提高了找到那些映射某個(gè)頁(yè)的進(jìn)程的速度,如圖2所示。驅(qū)動(dòng)程序調(diào)用下列內(nèi)核函數(shù)來(lái)為PCI9656分配內(nèi)存空間。
get_free_page(GFP_NOIO,PGD_ORDER);
alloc_pages(gfp_mask,size);
//查找并為PCI9656分配空閑內(nèi)存物理頁(yè)
mempool_alloc(pool,gfp_mask);
request_mem_region(pdx->Pci9656);
remap_page_range(*mem_area,PCI9656,kernel_address,mem_size,prot);
//請(qǐng)求分配內(nèi)存空間,實(shí)現(xiàn)PCI9656物理地址到內(nèi)存地址的映射
mempool_free(*element,pool);//釋放內(nèi)存
2.6內(nèi)核中將頭文件malloc.h改為slab.h,分配標(biāo)志GFP_BUFFER改為GFP_NOIO和GFP_NOFS,并新增了文件mempool.h。這些變化一起促生了2.6內(nèi)核中的內(nèi)存管理器,其設(shè)計(jì)目標(biāo)是更高的性能、效率和穩(wěn)定性。
另一方面,使用反向映射獲得性能的提高也要付出代價(jià),即系統(tǒng)不得不占用一些低端內(nèi)存來(lái)保持對(duì)所有反向映射的追蹤,這勢(shì)必在32位硬件上成為內(nèi)存空間的瓶頸。因此2.6內(nèi)核引入了高端內(nèi)存頁(yè)表(HighmemPTE)機(jī)制,讓頁(yè)表?xiàng)l目存放在高端內(nèi)存中,釋放出更多的低端內(nèi)存區(qū)給必須放在這里的內(nèi)核數(shù)據(jù)結(jié)構(gòu)。同時(shí),較以前版本的內(nèi)核而言,2.6內(nèi)核重新構(gòu)建了一個(gè)更為簡(jiǎn)單的內(nèi)存管理器,提高了整個(gè)系統(tǒng)的穩(wěn)定性。
4.2中斷處理
Linux處理中斷的方式很大程度上與它在用戶空間處理信號(hào)的方式一樣,驅(qū)動(dòng)程序只需為設(shè)備所對(duì)應(yīng)的中斷注冊(cè)一個(gè)處理程序,并在中斷到達(dá)時(shí)進(jìn)行正確的處理。
在2.4內(nèi)核之前,Linux系統(tǒng)一直采用cli和sti函數(shù)來(lái)禁用和啟用中斷,然而對(duì)于任意某個(gè)例程,想要知道在它被調(diào)用時(shí)中斷是否被啟用,已變得越來(lái)越困難。因而2.6內(nèi)核定義了函數(shù)local_irq_enable和local_irq_disable,用來(lái)使能和無(wú)效處理器控制的所有中斷,定義函數(shù)local_irq_save來(lái)將當(dāng)前中斷的狀態(tài)存入flags變量,避免了查詢中斷的狀態(tài)信息。
中斷處理程序的作用就是將有關(guān)中斷接收的信息反饋給設(shè)備,并根據(jù)正在服務(wù)的中斷的不同含義對(duì)數(shù)據(jù)進(jìn)行相應(yīng)的讀或?qū)?。由于PC機(jī)只有0-15的中斷號(hào),設(shè)備都是以共享的形式申請(qǐng)中斷號(hào),2.6內(nèi)核改進(jìn)了PCI設(shè)備中斷請(qǐng)求隊(duì)列的組織方式,通過(guò)設(shè)置flags變量中的SA_SHIRQ標(biāo)志位,并保證內(nèi)核中所有中斷號(hào)(dev_id)的唯一性,來(lái)實(shí)現(xiàn)中斷的共享。
if(!(inb(card->iobase+CODEC_CMD_INT_STATUS)&0x80000000))return;//識(shí)別中斷類型
request_irq(irq,*handler,flags,PCI9656,*dev_id);//向系統(tǒng)注冊(cè)PCI9656的中斷
如果中斷注冊(cè)成功,則返回值IRQ_RETVAL為0,這時(shí)在/proc/interrupts文件中可以看申請(qǐng)成功的中斷。在2.6內(nèi)核下,request_irq和free_irq從sched.h改到了interrupt.h中定義。
synchronize_irq(irq);//中斷同步
if(wait_event_interruptible(waitqueue,condition)>0)return;//判斷中斷等待使能
outb(intstat&card->iobase+CODEC_CMD_INT_HLDCLR+2);//使能并行端口的中斷報(bào)告
//系統(tǒng)響應(yīng)PCI9656的中斷,執(zhí)行數(shù)據(jù)讀寫、寄存器訪問等操作
free_irq(irq,*dev_id);//釋放設(shè)備中斷、I/O資源和緩沖區(qū)
5實(shí)驗(yàn)與測(cè)試
我們?cè)O(shè)計(jì)了Makefile文件和一個(gè)簡(jiǎn)單的應(yīng)用程序,在動(dòng)態(tài)加載驅(qū)動(dòng)程序后,對(duì)PCI9656開發(fā)板進(jìn)行了大批量數(shù)據(jù)的讀寫實(shí)驗(yàn)?;?4位PCI總線和100MHz的時(shí)鐘頻率,我們對(duì)芯片的數(shù)據(jù)讀寫速率進(jìn)行了采集,實(shí)驗(yàn)結(jié)果統(tǒng)計(jì)如圖3所示。
從上圖可以看到,在2.6內(nèi)核下應(yīng)用PCI9656作為總線接口芯片,數(shù)據(jù)的讀寫傳輸速率隨著數(shù)據(jù)包的大小有大幅度的提高,這在工程應(yīng)用中有很大的現(xiàn)實(shí)意義。
6結(jié)束語(yǔ)
本文通過(guò)Linux2.6內(nèi)核所提供的一系列標(biāo)準(zhǔn)函數(shù)調(diào)用接口,用C++語(yǔ)言開發(fā)了PCI9656的設(shè)備驅(qū)動(dòng)程序,并在FedoraCore2平臺(tái)下調(diào)試通過(guò),能正確發(fā)送和接收各種大小的數(shù)據(jù)包。當(dāng)通信的數(shù)據(jù)包大小為64KB時(shí),DMA通道的讀寫速度最大可達(dá)1.8Gbps,能夠很好的滿足日益龐大的數(shù)據(jù)處理需要。同時(shí),Linux操作系統(tǒng)源代碼的開放性還能較好的保證數(shù)據(jù)存儲(chǔ)運(yùn)算和通信的安全性。
參考文獻(xiàn)
[1]AlessandroRubini&JonathanCorbet,LinuxDeviceDriver(3rdEdtion)[M],USA:O''''Reilly&AssociatesInc,2005