付笑宇 張線媚
摘 要:WinIo 3.0軟件包只提供了在C#使用WinIo的用例,且沒有提供WinIo.lib文件,使得VC 2010下無法直接使用WinIo。在VC 2010下對WinIo 3.0的源碼重新進(jìn)行編譯生成WinIo.lib,修改WinIo.h文件后VC 2010下即可直接使用WinIo。給出了一個(gè)應(yīng)用樣例,實(shí)驗(yàn)結(jié)果表明該方法安全、簡潔、高效。
關(guān)鍵詞:內(nèi)核態(tài) WDF 驅(qū)動(dòng)程序 I/O端口
中圖分類號:TP311 文獻(xiàn)標(biāo)志碼:A 文章編號:1672-3791(2015)05(a)-0020-02
在電網(wǎng)實(shí)時(shí)測控系統(tǒng)研發(fā)過程中,需要使用in和out指令對測控單元的端口直接進(jìn)行讀寫,但X86CPU的硬件保護(hù)機(jī)制將I/O指令指定為特權(quán)指令,禁止用戶態(tài)的應(yīng)用程序訪問I/O端口。用戶態(tài)的應(yīng)用程序只能通過運(yùn)行于核心態(tài)的設(shè)備驅(qū)動(dòng)程序提供的API間接地訪問I/O端口,實(shí)時(shí)性較差。
Windows操作系統(tǒng)為用戶提供了WDM (Windows Driver Model)[1]架構(gòu),用于編寫設(shè)備驅(qū)動(dòng)程序。WDM架構(gòu)異常復(fù)雜,要求開發(fā)人員對Windows系統(tǒng)內(nèi)部的管理機(jī)制非常熟悉,有豐富的系統(tǒng)級應(yīng)用開發(fā)的經(jīng)驗(yàn),驅(qū)動(dòng)程序的調(diào)試相對困難,其安全性與效率無法保障。
Yariv Kaplan在2010年發(fā)布開源軟件WinIo 3.0[2],它采用了非文檔化的Windows API(native API)和其它一些底層編程技巧繞過Windows安全保護(hù)機(jī)制,Windows下的應(yīng)用程序程序可直接對I/O端口進(jìn)行操作、
1 WinIo 3.0簡介
WinIo 3.0支持32位和64位版的Windows 7/8,它提供了10個(gè)庫函數(shù),用于對I/O端口和內(nèi)存物理存儲(chǔ)單元的直接讀寫。WinIo軟件包由WinIo.sys、winio_nt.h、Winio.h、WinIo.dll、WinIo.lib(未提供,需要用戶在VC2010下生成)等5個(gè)核心文件組成。與I/O端口操作相關(guān)的4個(gè)函數(shù)如下:
(1)WinIo庫函數(shù)初始化。
WINIO_API bool -stdcall InitializeWinIo();
(2)卸載WinIo庫函數(shù)。
WINIO_API void -stdcall ShutdownWinIo();
(3)I/O端口讀操作函數(shù)。
WINIO_API bool _stdcall GetPortVal(WORD wPortAddr,PDWORD pdwPortVal,BYTE bSize);
參數(shù)wPortAddr為端口地址,16位整型變量或常量;參數(shù)pdwPortVal為指向一存放讀取端口內(nèi)容的32位整型變量指針;參數(shù)bSize為實(shí)際讀取的字節(jié)數(shù),8位整型變量或常量,取值范圍為1、2或4,表示讀操作的對象為8位、16位或32位端口。
(4)I/O端口寫操作函數(shù)。
WINIO_API bool _stdcall SetPortVal(WORD wPortAddr,DWORD dwPortVal, BYTE bSize);
參數(shù)wPortAddr為端口地址,16位位整型變量或常量;參數(shù)dwPortVal為要寫入端口的32位整型變量或常量;參數(shù)bSize為實(shí)際寫出的字節(jié)數(shù),取值范圍為1、2或4,表示寫操作的對象為8位、16位或32位端口。
2 VC 2010下WinIo 3.0的應(yīng)用
2.1 VC 2010下WinIo.lib的生成
WinIo 3.0軟件包的Source文件夾下包含了WinIo的源文件及其所需的資源,其下的DLL文件夾為VC 2010的WinIo項(xiàng)目文件夾。生成WinIo.lib文件的步驟如下。
(1)雙擊“WinIo.sln”啟動(dòng)WinIo項(xiàng)目。
(2)在VC 2010 IDE下打開“生成”菜單,單擊“生成WinIo”。
生成的WinIo.lib文件它存放于“.\Suorce\DLL\Debug”文件夾。注意:VC 2010學(xué)習(xí)版不能生成WinIo.lib文件。
2.2 VC 2010下WinIo應(yīng)用環(huán)境配置
(1)創(chuàng)建一個(gè)Win32控制臺(tái)應(yīng)用項(xiàng)目。
啟動(dòng)VC 2010,創(chuàng)建一個(gè)“Win32控制臺(tái)應(yīng)用程序”的WinIoDemo項(xiàng)目,在VC2010 IDE下打開“生成”菜單,單擊“生成WinIoDemo”。
(2)復(fù)制WinIo核心文件到制定的文件夾。
將WinIo 3.0軟件包的Source文件夾下的winio_nt.h、Winio.h與WinIo.lib復(fù)制到WinIoDemo項(xiàng)目文件夾下,WinIo.sys與WinIo.dll復(fù)制到WinIoDemo項(xiàng)目文件夾下的Debug文件夾。
(3)修改Winio.h文件。
將Winio.h中的“#include"..\drv\winio_nt.h"”,修改為“#include "winio_nt.h"”;
(4)配置鏈接器附加依賴項(xiàng)。
在VC 2010 IDE下打開“項(xiàng)目”菜單,單擊“屬性”,打開項(xiàng)目屬性頁對話框,打開“配置屬性”目錄樹,選擇“鏈接器”下的“輸入”子項(xiàng),在“附加依賴項(xiàng)”中添加“WinIo.lib”,如圖1所示。WinIo應(yīng)用環(huán)境配置完成,用戶可以編寫自己的源代碼進(jìn)行調(diào)試。
2.3 CMOS RAM讀寫實(shí)例
PC機(jī)的主板上集成有CMOS實(shí)時(shí)時(shí)鐘,為操作系統(tǒng)提供時(shí)間信息:年、月、日與時(shí)、分、秒。它附有128或256個(gè)字節(jié)的RAM,用于存放時(shí)間與硬盤、內(nèi)存、顯示卡等最基本的硬件配置信息。操作系統(tǒng)啟動(dòng)時(shí),從CMOS實(shí)時(shí)時(shí)鐘中讀取時(shí)間信息作為系統(tǒng)的基準(zhǔn)時(shí)間。系統(tǒng)斷電后由后備的鋰電池供電,以保障信息不丟失。
PC機(jī)為CMOS實(shí)時(shí)時(shí)鐘分配了70H和71H兩個(gè)8端口,用于訪問CMOS RAM,在進(jìn)行讀寫操作時(shí),需要先向70H端口寫入CMOS RAM單元的地址,然后通過71H端口進(jìn)行讀寫操作。
CMOS RAM的0、2、4單元分別存放秒、分、小時(shí)信息,7、8、9單元依次存放日、月、年信息,這些數(shù)據(jù)均采用壓縮的BCD碼表示。下面的代碼是一個(gè)完整的利用WinIo實(shí)現(xiàn)對I/O端口直接進(jìn)行讀寫操作的樣例,它先讀取CMOS RAM的9號單元的年份信息并顯示,然后再向9號單元寫入新的年份信息。重新啟動(dòng)PC后,Windows系統(tǒng)則采用新的年份。該樣例源代碼在32位版的Windows 7/8操作系統(tǒng)平臺(tái)上,使用VC 2010調(diào)試通過。
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
#include
#include "winio.h"
int _tmain(int argc, _TCHAR* argv[])
{
DWORD dwPortVal;
bool bResult;
bResult = InitializeWinIo();
if (bResult)
{
// write CMOS ram addr=9
SetPortVal(0x70, 9, 1);
// read CMOS ram addr=9,year,BCD code
GetPortVal(0x71, &dwPortVal, 1);
printf("Current Year:%4x\n",dwPortVal);
printf("Enter new year:");
scanf("%x",&dwPortVal);
SetPortVal(0x70, 9, 1);
SetPortVal(0x71,dwPortVal , 1); //write new year
SetPortVal(0x70, 9, 1);
GetPortVal(0x71, &dwPortVal, 1); //read new year
printf(" new Year:%4x\n",dwPortVal);
// When you're done using WinIo, call ShutdownWinIo
ShutdownWinIo();
}
else
{
printf("Error during initialization of WinIo.\n");
exit(1);
}
printf("\nPress anyke to continue …");
_getch();
return 0;
}
3 結(jié)語
該文給出了一種在VC 2010下使用WinIo 3.0的簡潔方法,已有的采用使用WinIo 2.0開發(fā)的應(yīng)用系統(tǒng),無需修改源代碼,在VC 2010下重新編譯后即可遷移到安全性更好的WinIo 3.0平臺(tái)。在實(shí)時(shí)測控系統(tǒng)的開發(fā)中,使用WinIo 3.0,省去了設(shè)備驅(qū)動(dòng)程序的開發(fā)環(huán)節(jié),可以極大的縮短系統(tǒng)的開發(fā)周期,降低開發(fā)成本,系統(tǒng)的安全性和可靠性也得到了保障。
參考文獻(xiàn)
[1] 邰銘 ,武安河,于洪濤.Windows 2000/XP WDM設(shè)備驅(qū)動(dòng)程序開發(fā)[M].北京:電子工業(yè)出版社,2003.
[2] Yariv Kaplan.WinIo[DB/OL].http://www.internals.com,2014-11-02.
[3] 孫穎.隨機(jī)波浪數(shù)據(jù)采集與處理技術(shù)的研究[D].天津:天津理工大學(xué),2014.
[4] 萬振凱,郭建民.大型自動(dòng)化三維編織復(fù)合材料編織機(jī)的開發(fā)[J].紡織導(dǎo)報(bào),2013(9):64-66,68.
[5] 袁軍,譚永東,任俊.利用WinIo實(shí)現(xiàn)并口數(shù)據(jù)通信[J].計(jì)算機(jī)與現(xiàn)代化,2009(8):49-53.
[6] 馮曉偉,李正生,吳寧.XP系統(tǒng)下CB對ISA總線的讀寫方法及應(yīng)用研究[J].自動(dòng)化與儀器儀表,2011(5):17-19.
[7] 王元強(qiáng),朱為.一種通過PCI總線配置FPGA的設(shè)計(jì)方法[J].現(xiàn)代電子技術(shù),2010(2):90-92,95.