首页
社区
课程
招聘
[求助]由IoSetCompletionRoutine源代码引出的两点迷惑
发表于: 2008-8-20 01:29 8547

[求助]由IoSetCompletionRoutine源代码引出的两点迷惑

2008-8-20 01:29
8547
1.
#define IoSetCompletionRoutine(irp,routine,completioncontext,success,error,cancel)\
#{ PIO_STACK_LOCATION irpsp;\
#ASSERT((success)|(error)|(cancel)?(routine)!=NULL:TRUE);\
#irpsp=IoGetNextIrpStackLocation((irp));\
#irpsp->completionroutine=(routine);\
#irpsp->context=(completioncontext);\
#irpsp->control=0;\
#if((success)){irpsp->control=SL_INVOKE_ON_SUCCESS;}\
#if((error)){irpsp->control  |= SL_INVOKE_ON_ERROR;}\
#if((cancel)){irpsp->control  |=  SL_INVOKE_ON_CANCEL;}  }\
以上的定义中irpsp=IoGetNextIrpStackLocation((irp));为什么是IoGetNextIrpStackLocation,而不是IoCurrentIrpStackLocation?这是不是表示设置完成历程的驱动的下层驱动调用完成历程了了?

2.
书上说IO管理器给每层驱动都创建一个IRP堆栈,那么对于过滤驱动,也应该对应一层IRP堆栈单元A,在其passthrough中,调用iocalldriver前为什么有时还要调用ioskipcurrentirpstacklocation?IO管理器理应也为过滤驱动下层驱动准备了IRP堆栈单元B,直接iocalldriver,跳到此IRP堆栈单元B不就行了,如果ioskipcurrentirpstacklocation,那么下层驱动接收到的不也是IRP堆栈单元A了?

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

收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
2
1.IoSetCompletionRoutine本来就是构造IRP后往下层驱动传递IRP的时候设置的一个完成函数。
2008-8-20 19:17
0
雪    币: 224
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
第一个问题:我个人理解,每一个IRP动作完成后,如果上层有设置完成例程,那么就调用完成例程,个人认为当前的IrpStackLocation 对应的是上层的完成例程的函数指针。而且IoSetCompletionRoutine只是去设置下层这个值,并没有跳到下层去。
第二个问题:
#define IoSkipCurrentIrpStackLocation( Irp ) \
    (Irp)->CurrentLocation++; \
    (Irp)->Tail.Overlay.CurrentStackLocation++;
2008-8-27 10:58
0
雪    币: 224
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
重新看了IoCallDriver的源码学习理解如下:
NTSTATUS
FASTCALL
IopfCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )
{
    PIO_STACK_LOCATION irpSp;
    PDRIVER_OBJECT driverObject;
    NTSTATUS status;

    //
    // Ensure that this is really an I/O Request Packet.
    //

    ASSERT( Irp->Type == IO_TYPE_IRP );

    //
    // Update the IRP stack to point to the next location.
    //
    Irp->CurrentLocation--;//每次调用IoCallDriver CurrentLocation都会减去1

    if (Irp->CurrentLocation <= 0) {
        KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0, 0 );
    }

    irpSp = IoGetNextIrpStackLocation( Irp );
    Irp->Tail.Overlay.CurrentStackLocation = irpSp;

    //
    // Save a pointer to the device object for this request so that it can
    // be used later in completion.
    //

    irpSp->DeviceObject = DeviceObject;

    //
    // Invoke the driver at its dispatch routine entry point.
    //

    driverObject = DeviceObject->DriverObject;

    PERFINFO_DRIVER_MAJORFUNCTION_CALL(Irp, irpSp, driverObject);

    status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,
                                                              Irp );

    PERFINFO_DRIVER_MAJORFUNCTION_RETURN(Irp, irpSp, driverObject);

    return status;
}

每次IoCallDriver的时候,系统会自动将CurrentIrpStackLocation减去1,指向下一个IO_STACK_LOCATION
2008-8-27 11:23
0
雪    币: 224
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
5
IoSkipCurrentIrpStackLocation是将这个指针移回来,实现平衡。
2008-8-27 11:24
0
雪    币: 364
活跃值: (152)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
6
在csdn上有人讲到:IoSetCompletionRoutine()函数的作用是设置完成例程,也就是将该irp向下层传递,让下层处理.下层处理完返回时触发刚才设置的完成例程,从而又有了处理该irp的机会.
2008-8-28 10:07
0
雪    币: 224
活跃值: (16)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
如果你的驱动程序不用关心IRP传递到下层驱动程序之后的事情,你可以利用一个捷径来避免复制堆栈单元。在这种情形下,我们不需要安装完成例程。
没有必要花费处理器时间去把你的堆栈单元内容复制到下一个堆栈单元,因为那个堆栈单元已经含有下一层驱动程序要得到的参数,以及自己上一层驱动程序可能给出的任何完成例程指针。因此,你可以使用下面捷径方法:
NTSTATUS ForwardAndForget(PDEVICE_OBJECT fdo, PIRP Irp)
{
  PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
  IoSkipCurrentIrpStackLocation(Irp);
  return IoCallDriver(pdx->LowerDeviceObject, Irp);
}
这个捷径存在于IoSkipCurrentIrpStackLocation函数(它实际上是一个宏,名字有些另人误解)中。这个宏的作用就是使堆栈指针少前进一步,而IoCallDriver函数会使堆栈指针向前一步,中和的结果就是堆栈指针不变。当下一个驱动程序的派遣例程调用IoGetCurrentIrpStackLocation时,它将收到与我们正使用的完全相同的IO_STACK_LOCATION指针,因此,它所处理的将是同一个请求(相同的主副功能代码)以及相同的参数。
2008-8-29 14:58
0
游客
登录 | 注册 方可回帖
返回
//