張小磊,孟李林,崔晨琪
(西安郵電大學(xué) 電子工程學(xué)院,陜西 西安 710061)
設(shè)備驅(qū)動(dòng)是計(jì)算機(jī)系統(tǒng)里軟硬件交互的接口,是計(jì)算機(jī)操縱硬件的基礎(chǔ),它的性能在很大程度上影響著整個(gè)系統(tǒng)的性能。KMDF是微軟推出的下一代驅(qū)動(dòng)模型WDF中的內(nèi)核模式驅(qū)動(dòng)程序框架,意在取代從WINDOWS2000就開始使用的WDM模型。其旨在為開發(fā)者提供一個(gè)面向?qū)ο蟮氖录?qū)動(dòng)開發(fā)框架,并封裝了驅(qū)動(dòng)與操作系統(tǒng)的接口使開發(fā)者可以更關(guān)注驅(qū)動(dòng)需要操控的硬件,以改變長久以來驅(qū)動(dòng)程序作為硬件和操作系統(tǒng)的連接,既要處理硬件行為,又要與操作系統(tǒng)內(nèi)核交互而導(dǎo)致的開發(fā)難度大,開發(fā)門檻高等問題。KMDF是WINDOWS 7/8首先的驅(qū)動(dòng)模型。
PCI Express是一種應(yīng)用于各種計(jì)算與通信平臺(tái)的高性能、通用、串行 I/O 互連協(xié)議。它采用包交換技術(shù)、Ack/Nak協(xié)議以及流量控制技術(shù),實(shí)現(xiàn)報(bào)文的高速高可靠傳輸。此外,PCI Express協(xié)議保持與現(xiàn)有 PCI 設(shè)備的軟件兼容性,而且可以用較低的開銷提升現(xiàn)有 PCI 系統(tǒng)的性能,在 PC 機(jī)及嵌入式系統(tǒng)中得到了廣泛的應(yīng)用。因此研究基于KMDF驅(qū)動(dòng)框架的PCI Express驅(qū)動(dòng)設(shè)計(jì)具有現(xiàn)實(shí)意義。
本文介紹KMDF的對(duì)象模型和I/O模型,并介紹一種基于KMDF的PCI Express設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)。
KMDF是內(nèi)核模式驅(qū)動(dòng)開發(fā)的框架,它定義了基于對(duì)象的編程模型,可以通過一系列層次化組織的對(duì)象以及與對(duì)象相關(guān)聯(lián)的方法和屬性來表示設(shè)備、驅(qū)動(dòng)、隊(duì)列等信息。KMDF對(duì)象模型中定義的主要的對(duì)象以及其層次如圖1所示:
圖1 KMDF中的主要對(duì)象及其層次
圖1中KMDF框架定義的主要對(duì)象有:
(1)WDFDRIVER:WDF驅(qū)動(dòng)對(duì)象,所有對(duì)象的根對(duì)象,描述一個(gè)驅(qū)動(dòng)程序在內(nèi)存的實(shí)例,維護(hù)驅(qū)動(dòng)程序的相關(guān)信息,如驅(qū)動(dòng)的入口點(diǎn),加載位置,可以管理的設(shè)備等。每一個(gè)驅(qū)動(dòng)程序在內(nèi)存中有且僅有一個(gè)WDFDRIVER對(duì)象。
(2)WDFDEVICE:WDF設(shè)備對(duì)象,系統(tǒng)中具體硬件的抽象,代表驅(qū)動(dòng)程序可以控制的硬件設(shè)備,用戶程序可以通過定義的設(shè)備接口訪問設(shè)備。WDFDEVICE也可以是虛擬設(shè)備。
(3)WDFQUEUE:WDF隊(duì)列對(duì)象,一個(gè)特殊的I/O請(qǐng)求隊(duì)列,它定義了一系列回調(diào)函數(shù),當(dāng)I/O請(qǐng)求進(jìn)入隊(duì)列時(shí),框架將自動(dòng)調(diào)用對(duì)應(yīng)的回調(diào)函數(shù)處理。
(4)WDFINTERRUPT:WDF中斷對(duì)象,定義了設(shè)備中斷使能,禁止回調(diào)函數(shù)和設(shè)備中斷的服務(wù)程序和DPC例程。
KMDF建立了自己的I/O模型,可以截獲發(fā)送給本設(shè)備驅(qū)動(dòng)程序的所有IRP。當(dāng)IRP到達(dá)時(shí),分發(fā)器根據(jù)IRP的主功能碼把IRP分發(fā)到I/O請(qǐng)求隊(duì)列或者電源管理隊(duì)列,框架會(huì)在適當(dāng)?shù)臅r(shí)間自動(dòng)的調(diào)用已經(jīng)注冊(cè)的回調(diào)函數(shù)。I/O流程如圖2所示:
圖2 I/O通過KMDF庫和驅(qū)動(dòng)程序流程
KMDF的I/O隊(duì)列管理那些針對(duì)驅(qū)動(dòng)程序的請(qǐng)求。驅(qū)動(dòng)程序通常創(chuàng)建一個(gè)或多個(gè)隊(duì)列,每個(gè)隊(duì)列可以接受一種或多種類型的請(qǐng)求。調(diào)度方法決定給定時(shí)間內(nèi)驅(qū)動(dòng)程序可服務(wù)的請(qǐng)求數(shù)量。
PCI Express作為高速串行I/O技術(shù)已經(jīng)在現(xiàn)行的計(jì)算機(jī)系統(tǒng)得到了廣泛應(yīng)用,本文涉及的PCI Express板卡是自行研發(fā)的基于Altera公司PCI Express硬核設(shè)計(jì)的高速數(shù)據(jù)處理系統(tǒng)。該系統(tǒng)的框架圖如圖3所示:
系統(tǒng)采用Altera 公司的Cyclone IV GX 系列FPGA芯片作為核心,使用FPGA中的硬件電路完成對(duì)下發(fā)數(shù)據(jù)的處理。FPGA主要模塊功能介紹:
圖3 系統(tǒng)框架圖
PCI-E IP硬核:實(shí)現(xiàn)PCI Express 1.1版本協(xié)議,完成PC機(jī)地址域與設(shè)備內(nèi)部地址域轉(zhuǎn)換,DMA通過IP硬核接口與PC機(jī)通信。IP硬核是完成計(jì)算機(jī)系統(tǒng)和數(shù)據(jù)處理卡系統(tǒng)通信的橋梁。
CPU:采用Altera公司NIOS II軟核實(shí)現(xiàn),作為PCI Expess設(shè)備的主控模塊,根據(jù)RAM緩沖區(qū)的數(shù)據(jù)包頭,啟動(dòng)相應(yīng)的算法模塊;或者根據(jù)算法模塊的結(jié)束信號(hào)啟動(dòng)一次DMA傳輸。
DMA以及RAM:DMA實(shí)現(xiàn)數(shù)據(jù)的高速傳輸,提高系統(tǒng)的效率;RAM數(shù)據(jù)的緩沖區(qū),在每次運(yùn)算過程緩存帶運(yùn)算數(shù)據(jù)以及運(yùn)算結(jié)果。
數(shù)據(jù)處理:系統(tǒng)的功能模塊,實(shí)現(xiàn)具體的數(shù)據(jù)處理算法,由CPU調(diào)度。
PCI Express是與PCI軟件兼容的系統(tǒng)總線,PCI Express具有與PCI總線相同的軟件訪問接口,因此可以使用與PCI相同的軟件流程。
本文介紹的PCI Express高速處理卡的驅(qū)動(dòng)流程如圖4所示。
KMDF設(shè)備驅(qū)動(dòng)程序初始化與WDM初始化入口相同,均為NTSTATSU DriverEntry(INPDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)函數(shù)[7],但是函數(shù)主要完成的功能并不相同,在WDM中主要完成驅(qū)動(dòng)的回調(diào)函數(shù)設(shè)置,而在KMDF中則主要完成驅(qū)動(dòng)對(duì)象的創(chuàng)建,即WDFDRIVER對(duì)象的創(chuàng)建,WDFDRIVER對(duì)象是對(duì)WDM中DRIVER_OBJECT對(duì)象的封裝,創(chuàng)建WDFDRIVER對(duì)象時(shí)需要提供創(chuàng)建WDFDEVICE對(duì)象的回調(diào)函數(shù)和驅(qū)動(dòng)的卸載例程的回調(diào)函數(shù),以及屬于驅(qū)動(dòng)對(duì)象的屬性。在KMDF中并不允許直接對(duì)框架創(chuàng)建的對(duì)象賦值,需要由專門的對(duì)象配置來實(shí)現(xiàn)。
圖4 驅(qū)動(dòng)流程圖
對(duì)于KMDF中涉及的所有內(nèi)核對(duì)象都可以在創(chuàng)建時(shí)指定一個(gè)屬于對(duì)象的環(huán)境變量結(jié)構(gòu),和獲得環(huán)境變量的方法名字,該環(huán)境變量的信息存儲(chǔ)在對(duì)象屬性結(jié)構(gòu)里,由框架在對(duì)象創(chuàng)建時(shí)使用。主要代碼如下:
WDF_DRIVER_CONFIG_INIT
(&config,UsbDataTransAdd);
//配置參數(shù)初始化,主要用來設(shè)置添加設(shè)備函數(shù)UsbDataTransAdd,此函數(shù)由框架在每次枚舉屬于驅(qū)動(dòng)程序的設(shè)備時(shí)調(diào)用。
status = WdfDriverCreate(DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
WDF_NO_HANDLE);
//創(chuàng)建驅(qū)動(dòng)對(duì)象,其中DriverObject由框架傳遞來的WDM驅(qū)動(dòng)對(duì)象,RegistryPath是注冊(cè)表中的服務(wù)鍵路徑,config為已經(jīng)初始化的對(duì)象配置。
在驅(qū)動(dòng)初始化以后,或者設(shè)備被首次枚舉,系統(tǒng)都會(huì)調(diào)用驅(qū)動(dòng)對(duì)象中設(shè)置的添加設(shè)備程序,設(shè)備添加例程主要的職責(zé)是:創(chuàng)建設(shè)備對(duì)象、一個(gè)或多個(gè)I/O隊(duì)列和設(shè)備GUID接口,設(shè)置各種事件回調(diào)函數(shù),以及創(chuàng)建中斷對(duì)象。主要函數(shù)如下:
WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);
//初始化即插即用和電源管理例程配置結(jié)構(gòu),該結(jié)構(gòu)只有在初始化后才在可以使用,并且該結(jié)構(gòu)的初始化必須在設(shè)備對(duì)象創(chuàng)建之前完成。
WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
//創(chuàng)建設(shè)備對(duì)象。
WDF_INTERRUPT_CONFIG_INIT(
&interruptConfig,
PCISample_EvtInterruptIsr,
PCISample_EvtInterruptDpc);
//設(shè)置中斷例程和延時(shí)過程函數(shù)
WdfInterruptCreate(
device,
&interruptConfig,
WDF_NO_OBJECT_ATTRIBUTES,
&pDeviceContext->Interrupt);
//創(chuàng)建中斷對(duì)象。
WdfDeviceCreateDeviceInterface(
device, (LPGUID)&PCI_DEVINTERFACE_GUID, NULL);
//設(shè)置內(nèi)核驅(qū)動(dòng)與應(yīng)用態(tài)的接口其中PCI_DEVINTERFACE_GUID是應(yīng)用程序?qū)ふ因?qū)動(dòng)的標(biāo)識(shí)碼,可使用Visual Studio中自帶的GUID生成器生成。
KMDF設(shè)備驅(qū)動(dòng)模型為分層模型,最底層為PCI Express總線驅(qū)動(dòng)由操作系統(tǒng)提供,總線驅(qū)動(dòng)上層才是我們提供的特定設(shè)備的設(shè)備驅(qū)動(dòng)。在PCI Express設(shè)備驅(qū)動(dòng)初始化時(shí),由總線驅(qū)動(dòng)通過IO端口CONFIG_ADDRESS(地址0CF8~0CFB),CONFIG_DATA(地址0CFC~0CFF)獲取配置空間設(shè)備資源信息[8],將資源信息記錄到設(shè)備對(duì)象的設(shè)備環(huán)境中,并且映射PCI Express配置空間BAR寄存器里描述的PCI Express內(nèi)存到PC機(jī)內(nèi)存空間,以使得驅(qū)動(dòng)程序可以使用簡單的內(nèi)存訪問函數(shù)直接訪問設(shè)備空間。
在創(chuàng)建設(shè)備對(duì)象時(shí)注冊(cè)的例程PcieDevicePrepareHardware會(huì)在設(shè)備進(jìn)入工作狀態(tài)之前由框架調(diào)用完成對(duì)硬件資源的獲取,并且會(huì)在即將進(jìn)入D0時(shí)對(duì)硬件進(jìn)行一些配置,相關(guān)的主要代碼:
case CmResourceTypeMemory:
{
momeryflag = TRUE;
pDevicecontext->MemBaseAdd=
MmMapIoSpace(
escriptor->u.Memory.Start,
descriptor->u.Memory.Length,
MmNonCached);
pDevicecontext->MemLength =
descriptor->u.Memory.Length;
pDevicecontext->PhysicalAdd=
descriptor->u.Memory.Start;
break;
}
//獲取PCI Express設(shè)備在PC內(nèi)存空間的地址并使用MmMapIoSpace函數(shù)將其轉(zhuǎn)換成可被直接訪問的內(nèi)核態(tài)虛擬地址。
case CmResourceTypeInterrupt:
{ASSERT(descriptor->Flags!=
CM_RESOURCE_INTERRUPT_MESSAGE)break;}
在本設(shè)計(jì)中主要獲取兩種資源:
(1)CmResourceTypeMemory內(nèi)存映射地址空間:PCI Express協(xié)議通過BAR映射FPGA電路控制寄存器到計(jì)算機(jī)系統(tǒng)的硬件地址空間,使得我們可以使用內(nèi)存訪問的方式直接訪問FPGA硬件。
(2)中斷資源:在WDM模型中,我們?cè)诒仨毇@得分配給此設(shè)備的中斷號(hào)以及此設(shè)備支持的中斷方式等中斷資源,以此為信息注冊(cè)本設(shè)備的中斷。但是在KMDF中這些已經(jīng)被框架所實(shí)現(xiàn),所以中斷資源變得可有可無。
訪問內(nèi)存映射地址空間時(shí)可以用KMDF提供的專用函數(shù)WRITE_RESISTER_xx、READ_RESISTER_xx系列函數(shù)讀寫該空間對(duì)應(yīng)的虛擬地址或者使用一般的內(nèi)存訪問函數(shù)直接訪問該空間對(duì)應(yīng)的虛擬地址。
本系統(tǒng)對(duì)數(shù)據(jù)的傳輸主要采用DMA實(shí)現(xiàn),通過兩個(gè)DMA實(shí)現(xiàn)數(shù)據(jù)的上行和下行,在本系統(tǒng)主要要求傳輸速度的前提下,本設(shè)計(jì)采用了把DMA控制和緩沖區(qū)映射到應(yīng)用層,由應(yīng)用程序直接控制DMA傳輸過程,以減少程序在狀態(tài)切換上的開銷。涉及的主要代碼如下:
pDevicecontext->mdlcard=IoAllocateMdl(
pDevicecontext->UserMemBase1, pDevicecontext->UserMemLength1,
FALSE, FALSE, NULL);
MmBuildMdlForNonPagedPool(dx->mdlcard);//分配MDL結(jié)構(gòu),其中dx->UserMemBase1為在PcieDevicePrepareHardware例程得到的硬件資源。
pDevicecontext->usercard= MmMapLockedPagesSpecifyCache
(pDevicecontext->MemBaseAdd,
UserMode,
MmNonCached,
NULL, FALSE,
NormalPagePriority);
//映射硬件資源到應(yīng)用態(tài)空間,pDevicecontext->MemBaseAdd存儲(chǔ)DMA控制寄存器空間基地址;pDevicecontext->usercard為得到的用戶空間地址,在合適的時(shí)機(jī)傳回應(yīng)用態(tài)。
pDevicecontext->mdldma=
IoAllocateMdl(pDevicecontext->vaCom
monBuffer,
SJY0601_MAXTRANSFER,
FALSE,FALSE, NULL);
MmProbeAndLockPages
(pDevicecontext->mdldma,
KernelMode,
IoModifyAccess);
pDevicecontext->userdma= MmMapLockedPagesSpecifyCache
(pDevicecontext->mdldma,
UserMode,
MmNonCached,
NULL,FALSE,
NormalPagePriority);
//其中pDevicecontext->mdldma為DMA緩沖區(qū)基地址,由應(yīng)用程序直接讀寫。
經(jīng)測(cè)試,本文所述的基于KMDF模型的PCI Express 數(shù)據(jù)處理系統(tǒng)驅(qū)動(dòng)在DMA 傳輸模式下處理數(shù)據(jù)速度可達(dá) 3024 Mbits/s(包括下發(fā)數(shù)據(jù),數(shù)據(jù)簡單處理,數(shù)據(jù)上發(fā)),且在壓力測(cè)試的100小時(shí)里程序能穩(wěn)定、可靠地工作。
本文所述的PCI Express設(shè)備驅(qū)動(dòng)程序,使用了KMDF模型,該模型提供了面向?qū)ο?、事件?qū)動(dòng)的驅(qū)動(dòng)程序開發(fā)框架,由框架負(fù)責(zé)管理與操作系統(tǒng)內(nèi)核相關(guān)的功能,不但使得驅(qū)動(dòng)程序的編寫簡單方便而且可靠性和穩(wěn)定性提高。同時(shí)本文所述的驅(qū)動(dòng)使用了內(nèi)核態(tài)到應(yīng)用態(tài)地址映射的技術(shù),所有數(shù)據(jù)均由應(yīng)用程序直接寫入設(shè)備,大幅度減少CPU狀態(tài)轉(zhuǎn)換帶來的開銷,提高系統(tǒng)的整體速度。綜上所述這樣的設(shè)計(jì)具有較傳統(tǒng)設(shè)計(jì)更優(yōu)的性能。
[1] 李正平,徐超,陳軍寧,等.WDF驅(qū)動(dòng)程序的設(shè)計(jì)與實(shí)現(xiàn)[J].計(jì)算機(jī)技術(shù)與發(fā)展,2007(5):227-230.
[2] 馬晨,陳彥萍.基于PCI Express總線 1394b 網(wǎng)絡(luò)傳輸系統(tǒng)WDM驅(qū)動(dòng)設(shè)計(jì)[J].測(cè)控技術(shù),2012,32(3):93-97.
[3] 武安河.Windows設(shè)備驅(qū)動(dòng)程序WDF開發(fā)[M].北京:電子工業(yè)出版社,2009:3-11.
[4] 王祥.基于FPGA的PCI-E數(shù)據(jù)采集系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)[D].成都:電子科技大學(xué),2012:1-5.
[5] 季喬龍.基于WDF的加密卡驅(qū)動(dòng)程序開發(fā)及密鑰管理[D].成都:電子科技大學(xué),2012:10-11.
[6] Ronald D Reeves.Windows 7設(shè)備驅(qū)動(dòng)程序開發(fā)[M].張猛,紀(jì)小玲,周姝嫣,譯.北京:人民郵電出版社,2012:95-95.
[7] 黎紹秀,衛(wèi)紅,蘭春嘉. PCI- E 圖像采集系統(tǒng)的 WDF 驅(qū)動(dòng)程序設(shè)計(jì)[J].科學(xué)技術(shù)與工程, 2011,11(16):3824-3827.
[8] 王齊.PCI Express體系結(jié)構(gòu)導(dǎo)讀[M].北京:機(jī)械工業(yè)出版社,2011:123-123.