首页
社区
课程
招聘
[求助]DPC定时器何时返回的问题
发表于: 2010-4-6 20:27 8599

[求助]DPC定时器何时返回的问题

2010-4-6 20:27
8599
小弟最近在学习驱动, 遇到个小问题, 有点不明白, 希望哪位大侠指教下。。。
在实现驱动程序调用驱动程序, 同步调用的时候,在DriverB中调用DriverA,  我在DriverA的派遣函数中设置了一个DPC定时器, 已经初始化。
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{

	PDEVICE_EXTENSION pDevExt = NULL;
	ULONG ulMicroSecond = 0;
	LARGE_INTEGER timeout ;
	_asm int 3
	KdPrint(("DriverA: Enter A HelloDDKRead\n"));
	//获取设备扩展
	pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension;
	//将挂起的IRP记录下来
	pDevExt->currentPendingIRP = pIrp;

	//将定时器的时间设置为3s
	ulMicroSecond = 3000000;

	//将32位整数转化成64位整数
	timeout = RtlConvertLongToLargeInteger(-10 * ulMicroSecond);

	//开启定时器
	KeSetTimer(&pDevExt->pollingTimer, timeout, &pDevExt->pollingDPC);
	KdPrint(("DriverA: leave A HelloDDKRead\n"));

	//返回pending状态
	return STATUS_PENDING;
}


#pragma PAGEDCODE
VOID OnTimerDpc(IN PKDPC pDpc, IN PVOID pContext, IN PVOID SysArg1, IN PVOID SysArg2)
{
	//冲上下文中获取设备对象指针
	PDEVICE_OBJECT pDevObj = NULL;
	PDEVICE_EXTENSION pdx = NULL;
	PIRP currentPendingIRP = NULL;

	pDevObj = (PDEVICE_OBJECT) pContext;
	pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

	//从设备扩展中得到挂起的IRP
	currentPendingIRP = pdx->currentPendingIRP;
	KdPrint(("DriverA: complete the Driver A IRP_MJ_READ irp\n"));

	//设置为完成状态
	currentPendingIRP->IoStatus.Status = STATUS_SUCCESS;
	//设置IRP的完成字节数
	currentPendingIRP->IoStatus.Information = 0;
	//将IRP结束
	IoCompleteRequest(currentPendingIRP, IO_NO_INCREMENT);
}

调试的过程中发现, 驱动程序进入了VOID OnTimerDpc()函数, 这个函数执行完了以后, IRP请求应该已经被结束了, 但是却始终没有返回DriverB中,
#pragma PAGEDCODE
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{
	UNICODE_STRING DeviceName;
	NTSTATUS ntstatus = STATUS_SUCCESS;
	OBJECT_ATTRIBUTES objectAttributes;
	HANDLE hDevice;                        //定义一个设备句柄
	IO_STATUS_BLOCK status_block;           //定义一个I/O状态

	_asm int 3
	KdPrint(("DriverB: Enter B HelloDDKRead\n"));
	RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDDKDeviceA");

	//初始化objectAttributes
	InitializeObjectAttributes(&objectAttributes,
		                        &DeviceName,
								OBJ_CASE_INSENSITIVE,
								NULL,
								NULL);
	//同步打开设备
	//设定了FILE_SYNCHRONOUS_IO_NANALERT 或者 FILE_SYNCHRONOUS_IO_ALERT为同步
	//打开设备
	ntstatus = ZwCreateFile(&hDevice,
		                    FILE_READ_ATTRIBUTES|SYNCHRONIZE,
							&objectAttributes,
							&status_block,
							NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, 
							FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
	//判断是否成功打开设备
	if (NT_SUCCESS(ntstatus))
	{
		//对设备进行同步读取操作
		ZwReadFile(hDevice, NULL, NULL, NULL, &status_block, NULL, 0, NULL, NULL);
	}
	//关闭设备
	ZwClose(hDevice);
	pIrp->IoStatus.Status = ntstatus;
	pIrp->IoStatus.Information = 0;
	//将IRP请求结束
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB: Leave B HelloDDKRead\n"));
	return ntstatus;
}

想不明白, 于是让DriverA直接返回 也就是将 STATUS_PENDING 改为 STATUS_SUCCESS, 则DriverA成功返回到DriverB中
希望各位可以指点一二

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 75
活跃值: (688)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
2
代码就是驱动详解的11章test1吧,我特意重新编译运行了下,好像没你说的问题

DriverA:Enter A HelloDDKRead
DriverA:Leave A HelloDDKRead

DriverA:complete the Driver A IRP_MJ_READ irp!ontimedpc调用了iocompleterequest()
此时已经返回到DriverB,才能继续调用ZwClose(hDevice);下面两行就是证据
DriverA:Enter A HelloDDKClose
DriverA:Leave A HelloDDKClose


DriverB:Leave B HelloDDKRead
DriverB:Enter B HelloDDKClose
DriverB:Leave B HelloDDKClose
watchdog!WdUpdateRecoveryState: Recovery enabled.
2010-4-6 22:26
0
雪    币: 173
活跃值: (132)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
3
谢谢, 我也调出来了, 呵呵, 加了一句“IoMarkIrpPending(pIrp);”
NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp)
{

        PDEVICE_EXTENSION pDevExt = NULL;
        ULONG ulMicroSecond = 0;
        LARGE_INTEGER timeout ;
        _asm int 3
        KdPrint(("DriverA: Enter A HelloDDKRead\n"));
       
        //获取设备扩展
        pDevExt = (PDEVICE_EXTENSION) pDevObj->DeviceExtension;
       
        //将IRP设置为挂起
        IoMarkIrpPending(pIrp);
        //将挂起的IRP记录下来
        pDevExt->currentPendingIRP = pIrp;

        //将定时器的时间设置为3s
        ulMicroSecond = 3000000;

        //将32位整数转化成64位整数
        timeout = RtlConvertLongToLargeInteger(-10 * ulMicroSecond);

        //开启定时器
        KeSetTimer(&pDevExt->pollingTimer, timeout, &pDevExt->pollingDPC);
        KdPrint(("DriverA: leave A HelloDDKRead\n"));

        //返回pending状态
        return STATUS_PENDING;
}
2010-4-6 22:38
0
雪    币: 75
活跃值: (688)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
原来楼主少了一句,额,我把那句去掉后真是没法返回到dirverB。
没搞懂为什么必须有这一句IoMarkIrpPending。
查资料查了1,2个小时,终于搞明白了,
爽!
DriverB->ZwReadfile->NtReadFile()->IopPerformSynchronousRequest()
......
[COLOR="Red"]//在此情景中,DeviceObject对应与DriverA的设备对象.IoCallDriver即是调用DriverA的Read派遣函数。
由上面的代码可以看出,DriverA的read派遣函数没做什么操作,直接返回STATUS_PENDING了[/COLOR]
  Status = IoCallDriver(DeviceObject, Irp);

...
    if (SynchIo)
    {
        /* Make sure the IRP was completed, but returned pending */
        if (Status == STATUS_PENDING)
        [COLOR="red"]{/*于是,NtReadFile就在这里一直等着,直到事件被设置。
此事件是DriverA的ontimedpc函数中的IoCompleteRequest来设置的,转到下面的IoCompleteRequest源代码[/COLOR]
            /* Wait for the IRP */
            Status = KeWaitForSingleObject(&FileObject->Event,
                                           Executive,
                                           PreviousMode,
                                           (FileObject->Flags &
                                            FO_ALERTABLE_IO),
                                           NULL);
     ................
    }

 DriverA->OnTimeDpc->IoCompleteRequest->IofCompleteRequest
.......
 do
    {
        /* Set Pending Returned */
  [COLOR="red"]     //只有在DriverA中调用IoMarkIrpPending,才能在此处使Irp->PendingRetured = 1,
从而才能调用后面蓝色部分,使DriverB等待的事件得以设置。这样就能从DriverB中返回了。
正因为如此,如果不调用IoMarkIrpPending,DriverB就只有一直等待了,终于搞明白了[/COLOR]
        Irp->PendingReturned = StackPtr->Control & SL_PENDING_RETURNED;
........
        /*
         * Either we didn't return from the request, or we did return but this
         * request was synchronous.
         */
        if (([COLOR="blue"]Irp->PendingReturned) [/COLOR]&& (FileObject))
        {
            /* So we did return with a synch operation, was it the IRP? */
            if (Irp->Flags & IRP_SYNCHRONOUS_API)
            {
                /* Yes, this IRP was synchronous, so return the I/O Status */
                *Irp->UserIosb = Irp->IoStatus;

                /* Now check if the user gave an event */
                if (Irp->UserEvent)
                {
                    /* Signal it */
                   [COLOR="blue"] KeSetEvent(Irp->UserEvent, 0, FALSE);[/COLOR]                }
                else
                {
                    /* No event was given, so signal the FO instead */
                    KeSetEvent(&FileObject->Event, 0, FALSE);
                }
            }
            else
            {
                /*
                 * It's not the IRP that was synchronous, it was the FO
                 * that was opened this way. Signal its event.
                 */
                FileObject->FinalStatus = Irp->IoStatus.Status;
                KeSetEvent(&FileObject->Event, 0, FALSE);
            }
        }

#define IoMarkIrpPending(_Irp) \
  (IoGetCurrentIrpStackLocation(_Irp)->Control |= SL_PENDING_RETURNED)
2010-4-7 00:49
0
雪    币: 75
活跃值: (688)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
5
哎,还解决了一个困扰我很久的问题,在完成例程里为什么必须传播pending位
多谢楼主了好问题,呵呵
2010-4-7 01:14
0
雪    币: 173
活跃值: (132)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
6
虽然知道要传播pending位, 但我也不知道为什么, 学习了
2010-4-7 10:17
0
雪    币: 636
活跃值: (174)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
7
不错不错!
2010-4-7 10:52
0
游客
登录 | 注册 方可回帖
返回
//