WINCE驅(qū)動(dòng)分析以及MapPtrToProcess 用法 3
出處:互聯(lián)網(wǎng) 發(fā)布于:2011-09-04 17:35:40
對(duì)于wince 驅(qū)動(dòng)或者linux驅(qū)動(dòng),或者其他操作系統(tǒng)驅(qū)動(dòng)。基本上就是兩個(gè)部分,1,訪問(wèn)硬件寄存器。2,編寫(xiě)操作系統(tǒng)接口。從訪問(wèn)硬件上來(lái)說(shuō),可以有總線驅(qū)動(dòng),一般的I/O驅(qū)動(dòng)等。從操作系統(tǒng)來(lái)說(shuō),就wince而言,可以分為,built-driver和stream driver,也可以從另外的一個(gè)角度,分為 Layered Device Driver 和 Monolithic driver。總之,驅(qū)動(dòng)的叫法和種類(lèi)很多,一般都要根據(jù)具體開(kāi)發(fā)的驅(qū)動(dòng)再仔細(xì)研究。其實(shí)大多數(shù)工作都是要看E文的datasheet,了解硬件的工作原理,對(duì)CPU工作方式有一定的理解,問(wèn)題就不大了。這里簡(jiǎn)單介紹一下如何編寫(xiě)wince下的stream driver。
首先講一下框架,很簡(jiǎn)單,按照wince的聯(lián)機(jī)幫助文檔,完成下面的接口函數(shù)就好了。
XXX_Close (Device Manager)
XXX_Deinit (Device Manager)
XXX_Init (Device Manager)
XXX_IOControl (Device Manager)
XXX_Open (Device Manager)
……
無(wú)非就是一些讀寫(xiě),IOCTL,POWER管理的接口而已。
通過(guò)前面的學(xué)習(xí)我們已經(jīng)對(duì)MapPtrToProcess 用法 WINCE驅(qū)動(dòng)分析有了初步了解,接下來(lái)我們要使用下面的應(yīng)用程序代碼測(cè)試這個(gè)driver,我們將使用evc編譯。
#include <windows.h>
#include<Windev.h>
#include <stdio.h>
#include "objbase.h"
#include "initguid.h"
#include "foo.h"
//char data1[10];
int WinMain(void)
{
HANDLE hnd;
COPY_STRUCT cs[1];
int i;
//static char data1[10];
auto char data1[10];
auto char data2[10];
static char* p1,*p2;
//cs.pBuffer1 = (char *)malloc(10);
//cs.pBuffer2 = (char*)malloc(10);
//cs.nLen = 10;
p1 = (char *)LocalAlloc(LPTR,10);
p2 = (char *)malloc(10);
//cs[0].pBuffer1 = (char *)malloc(10);
//cs[0].pBuffer2 = (char*)malloc(10);
cs[0].pBuffer1 = &data1[0];
cs[0].pBuffer2 = &data2[0];
cs[0].nLen = 10;
memset(cs[0].pBuffer1,'a',10);
hnd = CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);
if(hnd==NULL)
{
printf("Open device fALIed!\n");
return;
}
DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);
//for(i=0;i<9;i++)
//{
//printf(" %c",*(cs.pBuffer2++));
//}
printf("\n");
CloseHandle(hnd);
// free(cs[0].pBuffer1);
// free(cs[0].pBuffer2);
}
我們可以通過(guò)evc的單步調(diào)試看結(jié)果。等到一切都完成了,我們就來(lái)看看系統(tǒng)是怎么工作的吧,從應(yīng)用程序開(kāi)始,
CreateFile(FOO_DEV_NAME,GENERIC_READ|GENERIC_WRITE,0,NULL,0,0,NULL);
會(huì)調(diào)用到
FOO_Open(DWORD dwContext, DWORD AccessCode, DWORD ShareMode)
而FOO_DEV_NAME名字定義在foo.h里面。
#define FOO_DEV_NAME L"Foo1:"
注意后面是 1 ,這個(gè)是和注冊(cè)表的這一項(xiàng)匹配的,去注冊(cè)表確認(rèn)下以保證萬(wàn)無(wú)一失。
"Index"=dword:1
當(dāng)調(diào)用CreateFile發(fā)生了什么呢?slot之間的轉(zhuǎn)換,一系列系統(tǒng)操作后,調(diào)用到我們自己的driver函數(shù)FOO_Open,在這個(gè)函數(shù)里我們返回了一個(gè)句柄,它可以用來(lái)存儲(chǔ)我們的自己driver的信息。在其它I/O操作中可以使用。
Driver什么時(shí)候加載的?在注冊(cè)表里,device manager會(huì)一個(gè)個(gè)的加載,會(huì)調(diào)用到FOO_Init函數(shù)。這個(gè)函數(shù)返回一個(gè)指針,在調(diào)用FOO_Open又傳回來(lái)了,這樣我們就可以實(shí)現(xiàn)初始化一些自己driver的東西。
接著我們來(lái)說(shuō)一個(gè)重要的函數(shù),
DeviceIoControl(hnd,IOCTL_FOO_XER,&cs[0],sizeof(COPY_STRUCT),NULL,0,NULL,NULL);
調(diào)用到
FOO_IOControl
走到這里
case IOCTL_FOO_XER:
if((pInBuf==NULL))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
pcs = (COPY_STRUCT*)pInBuf;
__try{
pMap1 = MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());
pMap2 = MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());
DEBUG_OUT(1, (TEXT("+FOO_IOControl(0x%x,0x%x)\r\n"),pcs->pBuffer1,pcs->pBuffer2));
memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);
bResult = TRUE;
}
__except(EXCEPTION_EXECUTE_HANDLER){
DEBUG_OUT(1,(TEXT("Exception:FOO_IOCTL\r\n")));
break;
}
break;
default:
break;
這里又很多東西要研究,這里我就不做詳細(xì)解說(shuō)了。
從應(yīng)用程序傳來(lái)的參數(shù)有, control code,IOCTL_FOO_XER和一個(gè)重要的輸入?yún)?shù)&cs[0],它是一個(gè)指針。cs 是一個(gè)結(jié)構(gòu)體,定義在FOO.H
typedef struct {
char* pBuffer1;
char* pBuffer2;
int nLen;
}COPY_STRUCT;
而且這個(gè)結(jié)構(gòu)體里有兩個(gè)指針。
DeviceIoControl 傳過(guò)來(lái)的指針可以用嗎?它包含的兩個(gè)指針可以直接用嗎?
按照PB連接幫助文檔看,
The operating system (OS ) manages pointers passed directly as parameters. Drivers must map all pointers contained in structures. DeviceIoControl buffers are often structures that contain data, some of which might be pointers.
You can map a pointer contained in a structure by calling MapPtrToProcess, setting the first parameter to the pointer, and then setting the second parameter to GetCallerProcess.
cs指針已經(jīng)映射好了,但是它指向的結(jié)構(gòu)里的指針我們需要自己使用MapPtrToProcess函數(shù)映射。
這也就是:
pMap1 = MapPtrToProcess(pcs->pBuffer1,GetCallerProcess());
pMap2 = MapPtrToProcess(pcs->pBuffer2,GetCallerProcess());
的由來(lái),可是后面的代碼沒(méi)有使用pMap1,pMap2。而是直接使用:
memcpy(pcs->pBuffer2,pcs->pBuffer1,pcs->nLen);
而且它還工作了,沒(méi)有出現(xiàn)exception。很奇怪。我次在一個(gè)家伙的代碼里看見(jiàn)這種情況,很吃驚,但是它工作的很好,是文檔出錯(cuò)了?還是別的地方出錯(cuò)了呢?
那么我們就來(lái)分析一下吧。首先我們看看應(yīng)用程序的代碼:
COPY_STRUCT cs[1];
auto char data1[10];
auto char data2[10];
cs結(jié)構(gòu)和data1,data2數(shù)組都是自動(dòng)變量,存放在堆棧里。假設(shè)這個(gè)應(yīng)用程序被加載到0x18000000位置的slot里,那么他們的地址都是0x18XXXXXX。不熟悉wince memory architecture的可以看看資料,了解一下slot。當(dāng)調(diào)用了。
DeviceIoControl,按照文檔的說(shuō)法,cs指針得到了轉(zhuǎn)換,因?yàn)閺膽?yīng)用程序的進(jìn)程轉(zhuǎn)到了device.exe進(jìn)程,而device進(jìn)程又是當(dāng)前的運(yùn)行的進(jìn)程,被映射到了slot0,系統(tǒng)負(fù)責(zé)轉(zhuǎn)換cs指針。而cs包含的pBuffer1和pBuffer2是沒(méi)有映射不能直接用的。
事實(shí)上,我們傳過(guò)來(lái)的指針根本就是不需要映射,因?yàn)樗麄兌际?x18xxxxxx,在應(yīng)用程序的slot里,所以只要device.exe有訪問(wèn)應(yīng)用程序的權(quán)限,就可以了。而這個(gè)權(quán)限,系統(tǒng)已經(jīng)幫我們?cè)O(shè)置好了。
那什么情況下要自己映射呢?
如果應(yīng)用程序在定義 data1和data2使用static關(guān)鍵字,或者使用LocalAlloc,HeapAlloc的時(shí)候,一定要自己映射cs里的指針。
在應(yīng)用程序里這樣寫(xiě):
cs.pBuffer1 = (char *)malloc(10);
cs.pBuffer2 = (char*)malloc(10);
cs.nLen = 10;
如果不使用MapPtrToProcess完成映射,那就出現(xiàn)data abort exception.這是為什么呢?
因?yàn)檫@些變量都是在堆里分配的,而當(dāng)應(yīng)用程序運(yùn)行時(shí),被映射到slot0,堆的地址也就是處于slot的范圍內(nèi),傳遞到device.exe后,device.exe被映射到了slot0,這個(gè)時(shí)候必須要將應(yīng)用程序的指針映射回應(yīng)用程序所在的slot。否則訪問(wèn)的是device.exe的空間,會(huì)發(fā)生不可知道的結(jié)果。
現(xiàn)在我們來(lái)驗(yàn)證一下上面說(shuō)的地址分配問(wèn)題。
我們這樣定義:
COPY_STRUCT cs[1];
static char data1[10]; 堆里
auto char data2[10]; 棧里
這樣賦值:
cs[0].pBuffer1 = &data1[0];
cs[0].pBuffer2 = &data2[0];
cs[0].nLen = 10;
調(diào)試信息:
cs[0].pBuffer1 = &data1[0];
180112D0 ldr r2, [pc, #0xD0]
180112D4 str r2, [sp, #0x10]
讀取&data1[0]使用的是PC作為基址,而此時(shí)的應(yīng)用程序處于運(yùn)行階段映射到slot0,那么pc也就在0~01ffffff范圍,我的調(diào)試結(jié)果是在0x000112D0+8,使用的是arm,流水線機(jī)制,當(dāng)前指令地址+8才是pc值。
143: cs[0].pBuffer2 = &data2[0];
180112D8 add r0, sp, #0x20
180112DC str r0, [sp, #0x14]
讀取&data2[0]采用的是sp作為基址,sp在應(yīng)用程序加載到slot的時(shí)候就確定了的。所以保持了在應(yīng)用程序slot的值,處于0x18xxxxxx范圍。
我們看到因?yàn)閣ince的slot機(jī)制,我們有時(shí)候需要映射,有時(shí)候不需要。所以wince文檔說(shuō)結(jié)構(gòu)里的指針要映射。畢竟你不知道應(yīng)用程序怎么寫(xiě)。
當(dāng)然,你可以根本不映射,只要把那個(gè)結(jié)構(gòu)屏蔽調(diào),寫(xiě)一個(gè)STATIC LIBRARY給用戶(hù)使用,自己保證使用正確的地址分配就可以了。上面我說(shuō)的那個(gè)家伙就是這么干的。
好了,接著調(diào)用:
CloseHandle(hnd);
程序就這么結(jié)束了,完成了我們進(jìn)行簡(jiǎn)單的拷貝就OK了。
這個(gè)框架完成了,driver的基本接口設(shè)計(jì),強(qiáng)調(diào)了內(nèi)存指針的使用問(wèn)題。但是相對(duì)于一個(gè)真正的driver,還缺少點(diǎn)東西,就是訪問(wèn)硬件的方法。不過(guò)我們還是先了解下驅(qū)動(dòng)程序和應(yīng)用程序之間傳遞數(shù)據(jù)時(shí)何時(shí)調(diào)用MapPtrToProcess?
因?yàn)樵O(shè)備管理器負(fù)責(zé)加載驅(qū)動(dòng)程序DLL,這意味著當(dāng)應(yīng)用程序調(diào)用驅(qū)動(dòng)程序接口函數(shù)的時(shí)候,WINCE內(nèi)核會(huì)將調(diào)用驅(qū)動(dòng)程序接口函數(shù)的線程轉(zhuǎn)移到設(shè)備管理器的進(jìn)程空間然后執(zhí)行具體的驅(qū)動(dòng)程序代碼,應(yīng)用程序和設(shè)備管理器處于兩個(gè)進(jìn)程空間,這就造成設(shè)備管理器無(wú)法訪問(wèn)應(yīng)用程序傳遞的指針(虛擬地址),所以當(dāng)我們?cè)趹?yīng)用程序中傳遞指針給流驅(qū)動(dòng)程序接口函數(shù)時(shí),WINCE內(nèi)核從中作了一個(gè)地址映射,例如ReadFile、WriteFile、DeviceIoControl函數(shù)的參數(shù)凡是指針都經(jīng)過(guò)了映射才傳遞給驅(qū)動(dòng)程序,所以很多驅(qū)動(dòng)程序開(kāi)發(fā)者并不了解其中的奧秘就可以編程了。但是如果參數(shù)是一個(gè)指向一個(gè)結(jié)構(gòu)體的指針,而結(jié)構(gòu)體里包括一個(gè)或多個(gè)指針,那么WINCE內(nèi)核并不負(fù)責(zé)映射,所以就需要開(kāi)發(fā)者在驅(qū)動(dòng)程序接口函數(shù)中調(diào)用API函數(shù)MapPtrToProcess來(lái)映射地址。例如:pPointer_retval = MapPtrToProcess(pPointer, GetCallerProcess());
關(guān)于MapPtrToProcess 用法 WINCE驅(qū)動(dòng)分析的學(xué)習(xí)又要告一段落了。我們使用evc編譯應(yīng)用程序代碼測(cè)試driver。希望大家在學(xué)習(xí)中舉一反三學(xué)到更多的東西。當(dāng)然也許本文還不夠完善,在接下來(lái)的學(xué)習(xí)中我們會(huì)更加深入地學(xué)習(xí)MapPtrToProcess 用法 WINCE驅(qū)動(dòng)分析。如果大家有更好的例子可以發(fā)出來(lái)。學(xué)無(wú)止境,我的并不一定是的,我只希望對(duì)需要這方面知識(shí)的人有所幫助,我就滿(mǎn)足了。接下來(lái)我們要說(shuō)的就是對(duì)一個(gè)真正的driver還缺少的東西——訪問(wèn)硬件的方法。希望感興趣的人多多關(guān)注。
版權(quán)與免責(zé)聲明
凡本網(wǎng)注明“出處:維庫(kù)電子市場(chǎng)網(wǎng)”的所有作品,版權(quán)均屬于維庫(kù)電子市場(chǎng)網(wǎng),轉(zhuǎn)載請(qǐng)必須注明維庫(kù)電子市場(chǎng)網(wǎng),http://hbjingang.com,違反者本網(wǎng)將追究相關(guān)法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明自其它出處的作品,目的在于傳遞更多信息,并不代表本網(wǎng)贊同其觀點(diǎn)或證實(shí)其內(nèi)容的真實(shí)性,不承擔(dān)此類(lèi)作品侵權(quán)行為的直接責(zé)任及連帶責(zé)任。其他媒體、網(wǎng)站或個(gè)人從本網(wǎng)轉(zhuǎn)載時(shí),必須保留本網(wǎng)注明的作品出處,并自負(fù)版權(quán)等法律責(zé)任。
如涉及作品內(nèi)容、版權(quán)等問(wèn)題,請(qǐng)?jiān)谧髌钒l(fā)表之日起一周內(nèi)與本網(wǎng)聯(lián)系,否則視為放棄相關(guān)權(quán)利。
- ARM技術(shù)架構(gòu)與應(yīng)用開(kāi)發(fā)實(shí)踐指南2026/1/6 10:40:19
- 嵌入式實(shí)時(shí)操作系統(tǒng)(RTOS)選型與移植技術(shù)指南2025/12/31 10:42:31
- 工業(yè)嵌入式系統(tǒng):通信接口技術(shù)選型與抗干擾設(shè)計(jì)實(shí)踐2025/12/15 14:36:53
- 深入解析嵌入式 OPENAMP 框架:開(kāi)啟異核通信新時(shí)代2025/7/22 16:27:29
- 一文快速了解OPENWRT基礎(chǔ)知識(shí)2025/7/14 16:59:04
- 編碼器的工作原理及作用1
- 超強(qiáng)整理!PCB設(shè)計(jì)之電流與線寬的關(guān)系2
- 三星(SAMSUNG)貼片電容規(guī)格對(duì)照表3
- 電腦藍(lán)屏代碼大全4
- 國(guó)標(biāo)委發(fā)布《電動(dòng)汽車(chē)安全要求第3部分:人員觸電防護(hù)》第1號(hào)修改單5
- 通俗易懂談上拉電阻與下拉電阻6
- 繼電器的工作原理以及驅(qū)動(dòng)電路7
- 電容單位8
- 跟我學(xué)51單片機(jī)(三):?jiǎn)纹瑱C(jī)串口通信實(shí)例9
- 一種三極管開(kāi)關(guān)電路設(shè)計(jì)10
- 高速PCB阻抗控制核心實(shí)操規(guī)范
- 高速數(shù)字系統(tǒng)(如DDR、SerDes)中的信號(hào)完整性濾波
- MOSFET在UPS電源中的應(yīng)用解析
- 電源管理IC在物聯(lián)網(wǎng)設(shè)備中的應(yīng)用
- SMT連接器焊接缺陷分析
- MOSFET在汽車(chē)電子中的應(yīng)用要求
- 通信設(shè)備電源管理IC應(yīng)用解析
- 通信設(shè)備連接器選型與設(shè)計(jì)
- PCB電磁兼容性(EMC)設(shè)計(jì)核心實(shí)操規(guī)范
- 物聯(lián)網(wǎng)節(jié)點(diǎn)低功耗設(shè)計(jì):信號(hào)鏈中的濾波與功耗管理









