Camus1981
驱动牛犊
驱动牛犊
  • 注册日期2004-08-09
  • 最后登录2006-04-13
  • 粉丝0
  • 关注0
  • 积分100分
  • 威望10点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
阅读:1519回复:2

斑竹,高手们,帮帮小弟阿~~~~~一个问题,弄了好几天了~~~~~~

楼主#
更多 发布于:2004-08-19 22:06
小弟偶第一次做驱动,重启蓝屏无数次了,装系统也有N次了。要不是实在没办法(身边的参考资料几乎只从网上下,我们学校的图书馆放假了,书店也放假了),偶是不会随便来bbs哭的:)。
各位高手,你们先不要骂我,等调通了偶竖着耳朵让你们骂,OK??

是这样的,偶在一个NDIS中间层驱动下面想要访问磁盘文件,这里就是想从磁盘文件里面读数据,该文件名是c:\\passthru.txt,里面的数据是一些字符,偶随便写了些,比如,gggggghhhhh。

我是这样来编码的:

在DriverEntry里面:

...
MyDriverCreateFile(NULL,&m_ghFileHandle,m_gFileName);
...
这是个自定义函数,用于打开一个文件,参数m_ghFileHandle是个全局变量,m_gFileName是"\\\\??\\\\c:\\\\passthru.txt",这个函数返回的文件句柄是176,偶把它输出来看了的。

在PtReiceive里面:(这个函数工作在IRQL=DISPATCH_LEVEL)

...
char readbuffer[50];//这个是用来存放读出数据的缓冲区
char * piChar;
...
MyDriverReadFile(readbuffer,20,m_ghFileHandle);//自定义函数
//这个函数就是读取数据的函数,其中m_ghFileHandle的值,经察看是176,
//readbuffer即用于存放数据的缓冲区,20表示读取20字节。

piChar=readbuffer; //指向缓冲区的头部
for(i=0;i<=19;i++) //用于输出缓冲区的数据,显示为乱码,不是文件中的数据gggggghhhhh.
{
DbgPrint("%c",*piChar);//输出到DbgView
piChar++;
}
...
下面是偶的自定义函数,主要是3个函数:一个用于打开文件,两个用于读取文件数据。

1.MyDriverCreateFile();//打开文件

这个函数用于打开文件,当然,也是在workitem里面打开了。其中对IRQL进行判断,若在IRQL=DISPATCH则用workitem来创建一个系统进程,再在workitem里面打开文件,这个函数返回值正确,就不列出细节,只给出最主要的ZwCreateFile部分。而且偶用它返回的文件句柄来写文件是正确的,就是说可以用这个文件句柄来写,就是读不出来,缓冲区始终为原来的值,不是读出的文件数据。

...
ntStatus=NT::ZwCreateFile( &FileHandle,
SYNCHRONIZE | GENERIC_READ,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
...

2.MyDriverReadFile();

这个是用来读文件数据的函数:

VOID MyDriverReadFile(
IN PVOID Buffer, //存放数据的缓冲区
IN ULONG Length, //读出的字节数
IN OUT HANDLE FileHandle) //文件句柄
{
NTSTATUS ntStatus;
NT::OBJECT_ATTRIBUTES ObjectAttributes;//NT是个namespace,里面包含了ntddk.h,ntdef.h,及自定义的struct_FILE_WORK_ITEM结构

NT::IO_STATUS_BLOCK IoStatusBlock;
NT::UNICODE_STRING UniFileName;
NT::PFILE_WORK_ITEM workitem; //FILE_WORK_ITEM结构是在NT这个namespace里面定义的
NT::LARGE_INTEGER ByteOffset;

if(NT::KeGetCurrentIrql() < DISPATCH_LEVEL)
//若IRQL==PASSIVE_LEVEL
{
ntStatus=NT::ZwReadFile(FileHandle,
0,
0,
0,
&IoStatusBlock,
Buffer,
Length,
NULL,
NULL);
if(NT_SUCCESS(ntStatus) && FileHandle != NULL)
{
}
}

else //经输出调试,发现IRQL不在
//PASSIVE_LEVEL,因此,执行的是这个分支
{
ntStatus = STATUS_PENDING;
workitem = (NT::PFILE_WORK_ITEM)NT::ExAllocatePool(NT::NonPagedPool,sizeof(NT::FILE_WORK_ITEM));
if (workitem) {

ExInitializeWorkItem(&workitem->WorkItem,
MyDriverReadFileWorkItem,//自定义的系统线程,用于读文件
workitem);

workitem->FileContext = Buffer;
workitem->FileHandle = FileHandle;
workitem->Length = Length;

NT::ExQueueWorkItem(&workitem->WorkItem,NT::DelayedWorkQueue);

}
else
{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}

}
return;
}

3.MyDriverReadFileWorkItem();

这个是自定义的读数据的系统进程函数,把其中的"Read"换成"Write"就是写文件的函数,而且经使用,写是可以正确写的(这时ZwCreateFile函数的参数要相应改为GENERIC_WRITE)。

VOID MyDriverReadFileWorkItem(
PVOID Context)
{
HANDLE FileHandle;
NTSTATUS ntStatus;
NT::IO_STATUS_BLOCK IoStatusBlock;
NT::LARGE_INTEGER ByteOffset;
PVOID Buffer;
ULONG Length;

NT::PFILE_WORK_ITEM workitem = (NT::PFILE_WORK_ITEM) Context;

FileHandle = workitem->FileHandle;
Buffer = workitem->FileContext;
Length = workitem->Length;

ntStatus=NT::ZwReadFile(FileHandle,
0,
0,
0,
&IoStatusBlock,
Buffer,
Length,
NULL,
NULL);
if(NT_SUCCESS(ntStatus) && FileHandle != NULL)
{
}
NT::ExFreePool(workitem);
return;
}

就是这3个函数了,打开文件,然后读文件数据到缓冲区。
再强调一下几个数据:
文件句柄:m_ghFileandle是个全局变量
缓冲区:char readbuffer[50]是在PtReceive里面定义的
用这个句柄和缓冲区是可以正确的写文件到数据的,已经实现过了,可就是不能正确的读文件数据。

偶第一次做驱动,重启蓝屏无数次了,装系统也有N次了。要不是实在没办法(身边的参考资料几乎只从

网上下,我们学校的图书馆放假了,书店也放假了),偶也不会来这哭了:)。
各位高手,就这些了,你们先不要骂我,等调通了偶竖着耳朵让你们骂,OK??
Thank you for all your help~~~!

[编辑 -  8/19/04 by  Camus1981]
tooflat
论坛版主
论坛版主
  • 注册日期2002-07-08
  • 最后登录2014-03-11
  • 粉丝2
  • 关注0
  • 积分1007分
  • 威望551点
  • 贡献值3点
  • 好评度476点
  • 原创分0分
  • 专家分0分
沙发#
发布于:2004-08-26 12:19
读文件和写文件的代码应该差不多,写没有问题,读应该也不会有问题,你确定是在读文件的时候蓝屏的吗??读和写操作的代码是否基本一致??
还有如果irql != PASSIVE_LEVEL,你的MyDriverReadFile将是异步的,你在该函数返回后立即读取缓冲区中的内容,当然可能是乱码,因为那时候系统还没有往里面写数据,另外因为MyDriverReadFile可能是异步工作,所以,你如果过早释放了缓冲区,还有可能导致蓝屏,不知道你的蓝屏是不是这个原因???
right_wind
驱动中牛
驱动中牛
  • 注册日期2001-10-12
  • 最后登录2018-05-29
  • 粉丝1
  • 关注0
  • 积分60分
  • 威望66点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
  • 社区居民
板凳#
发布于:2004-08-26 14:42
看看这段文字对你有没有帮助。

访问文件
有时,WDM驱动程序需要读写常规的磁盘文件。你可能需要向硬件下载一大段微代码,或者创建自己的全面的硬件操作记录。有一组ZwXxx函数可以做这些事情。

访问磁盘文件的第一步是调用ZwCreateFile打开一个文件句柄。DDK中详细地描述了该函数。我在这里仅描述该函数的两个方面,即读/写一个已知名的文件。

打开已存在文件然后读
下面例子打开一个已存在的文件然后读该文件:

NTSTATUS status;
OBJECT_ATTRIBUTES oa;
IO_STATUS_BLOCK iostatus;
HANDLE hfile;              //  the output from this process
PUNICODE_STRING pathname;  //  you've been given this

InitializeObjectAttributes(&oa, pathname, OBJ_CASE_INSENSITIVE, NULL, NULL);
status = ZwCreateFile(&hfile,
     GENERIC_READ,
     &oa,
     &iostatus,
     NULL,
     0,
     FILE_SHARE_READ,
     FILE_OPEN,
     FILE_SYNCHRONOUS_IO_NONALERT,
     NULL,
     0);
 

创建或重写文件
为了创建一个新文件,或打开一个已存在文件并截为0长度,用下面方式调用ZwCreateFile函数:

status = ZwCreateFile(&hfile,
     GENERIC_WRITE,
     &oa,
     &iostatus,
     NULL,
     FILE_ATTRIBUTE_NORMAL,
     0,
     FILE_OVERWRITE_IF,
     FILE_SYNCHRONOUS_IO_NONALERT,
     NULL,
     0);
 

在上面这些例子中,我们建立了一个OBJECT_ATTRIBUTES结构,其目的是用它指向被打开文件的完整路径。我们指定了OBJ_CASE_INSENSITIVE属性,因为Win32文件系统模型对路径名的大小写不区分。然后我们调用ZwCreateFile打开文件句柄。

第一个参数(&hfile),是HANDLE类型变量的地址,ZwCreateFile将向该地址返回它创建的句柄。
第二个参数(GENERIC_READ或GENERIC_WRITE),指定文件访问方式,读或写。
第三个参数(&oa),是OBJECT_ATTRIBUTES结构的地址,该结构包含要打开的文件名。
第四个参数(&iostatus),指向一个IO_STATUS_BLOCK结构,该结构接收ZwCreateFile操作的结果状态。
第五个参数(NULL),是一个指针,指向一个64位整数,该数指定文件的初始分配大小。该参数仅关系到创建或重写文件操作,如果忽略它(如我在这里所做的),那么文件长度将从0开始,并随着写入而增长。
第六个参数(0或FILE_ATTRIBUTE_NORMAL),指定新创建文件的属性。
第七个参数(FILE_SHARE_READ或0),指定文件的共享方式。如果仅为读数据而打开文件,则可以与其它线程同时读取该文件。如果为写数据而打开文件,你可能不希望其它线程访问该文件。
第八个参数(FILE_OPEN或FILE_OVERWRITE_IF),表明当指定文件存在或不存在时应如何处理。在只读情况中,我指定FILE_OPEN,因为我希望打开一个已存在的文件,当文件不存在时返回错误。在只写情况中,我指定FILE_OVERWRITE_IF,因为我希望改写任何已存在的文件或创建一个新文件。
第九个参数(FILE_SYNCHRONOUS_IO_NONALERT),指定控制打开操作和句柄使用的附加标志位。在这里,我指明要做同步I/O操作(即我希望读写函数在I/O操作完成后才返回,此时调用者处于等待状态)。
第十个参数(NULL),一个指针,指向可选的扩展属性区。
第十一个参数(0),扩展属性区的长度。
我们希望ZwCreateFile返回STATUS_SUCCESS状态并设置句柄变量。然后我们用ZwReadFile和ZwWriteFile函数执行读写操作,最后调用ZwClose函数关闭文件句柄。

ZwClose(hfile);
 

你可以执行同步或异步读写操作,这取决于你在ZwCreateFile中指定的标志。我在上面例子中指定了同步操作,读写函数在完成后才返回。如下例:

PVOID buffer;
ULONG bufsize;
status = ZwReadFile(hfile, NULL, NULL, NULL, &iostatus, buffer, bufsize, NULL, NULL);

            -or-

status = ZwWriteFile(hfile, NULL, NULL, NULL, &iostatus, buffer, bufsize, NULL, NULL);
 

这些调用与用户模式中的非重叠ReadFile或WriteFile调用类似。当这些函数返回时,你可能对iostatus.Information域感兴趣,该域携带了操作所传输的字节数量。

如果你想把整个文件读入内存缓冲区,应该先调用ZwQueryInformationFile获得文件的总长度:

FILE_STANDARD_INFORMATION si;
ZwQueryInformationFile(hfile, &iostatus, &si, sizeof(si), FileStandardInformation);
ULONG length = si.EndOfFile.LowPart;
 

文件操作的时间选择
当驱动程序为响应IRP_MN_START_DEVICE请求而初始化设备时,可能需要读磁盘文件。由于设备初始化可能出现在系统初始化各种设备的不同阶段,所以使用普通的路径名如\??\C:\dir\file.ext有时不能访问到文件。为了安全起见,你应该把数据文件放到系统根目录下的某个目录中,如\SystemRoot\dir\file.ext,而名称空间中的SystemRoot分支总是可访问的,因为操作系统在启动时也需要读磁盘文件。

浮点运算
有时候整数运算并不能满足要求,我们需要浮点运算。在Intel处理器上,浮点协处理器还可以执行MMX指令。在历史上,驱动程序在执行浮点运算上有两个问题。对于没有浮点协处理器的计算机,操作系统将用软件仿真一个,但是仿真的浮点协处理器会消耗很大的CPU处理能力,并且需要一个处理器异常来捕捉浮点指令。在内核模式中处理异常,尤其是在提升的IRQL级上,是困难的。另外,在有浮点协处理器的计算机上,由于CPU结构上的原因,当线程上下文切换时,需要一个耗时的操作来保存和恢复浮点协处理器的状态。所以,通常的做法是禁止在内核模式驱动程序中使用浮点运算。

Windows 2000和Windows 98提供了一种方法来绕过这个问题。首先,有一个运行在低于或等于DISPATCH_LEVEL级上系统线程,该线程可以自由地使用浮点协处理器。另外,运行在低于或等于DISPATCH_LEVEL级上的任意线程背景的驱动程序可以调用两个系统函数,用这两个函数调用可以把浮点运算程序括起来:

ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
KFLOATING_SAVE FloatSave;
NTSTATUS status = KeSaveFloatingPointState(&FloatSave);
if (NT_SUCCESS(status))
{
  ...
  KeRestoreFloatingPointState(&FloatSave);
}
 

这两个调用必须成对出现,它们为当前CPU保存和恢复浮点协处理器状态,即浮点协处理器的状态可以维持到任意多个指令周期。这个状态信息包括寄存器、控制字,等等。而在某些其它种类的CPU上,这两个调用不做任何事,因为这种CPU在线程切换时可以自动保存和恢复浮点协处理器的状态。出于这种原因,Microsoft建议,除非必要,应避免在内核模式驱动程序中使用浮点运算。

调用KeSaveFloatingPointState时发生了什么,不同的CPU结构会有不同的答案。例如,在Intel处理器上,该函数通过执行FSAVE指令把整个浮点处理器状态保存起来。它既可以把状态信息保存到当前线程的上下文块中,也可以保存到一块动态分配的内存区中。它还用一个不透明的FloatSave区记录关于被保存状态的中间信息,这可以使KeRestoreFloatingPointState正确地恢复浮点协处理器的状态。

如果系统没有浮点协处理器,KeSaveFloatingPointState将失败并返回STATUS_ILLEGAL_FLOAT_CONTEXT代码。(顺便提一下,多CPU计算机的每个CPU必须同时拥有或同时没有协处理器) 因此你的驱动程序必须以其它方式实现浮点计算,或者干脆拒绝把驱动程序装入无浮点处理器的计算机上(由于DriverEntry的失败)。
good good study, day day up。
游客

返回顶部