JackyWu
驱动小牛
驱动小牛
  • 注册日期2001-10-25
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
阅读:1670回复:6

关于irp堆栈

楼主#
更多 发布于:2002-05-13 11:09
请参考Walt Oney的书的第5章第2部分,书中写到:
   “IRP中的第一个堆栈单元指针被初始化成指向该堆栈单元之前的堆栈单元,因为I/O堆栈实际上是IO_STACK_LOCATION结构数组,你可以认为这个指针被初始化为指向一个不存在的“-1”元素,因此当我们要初始化第一个堆栈单元时我们实际需要的是“下一个”堆栈单元。IoCallDriver将沿着这个堆栈指针找到第0个表项,并提取我们放在那里的主功能代码,在上例中为IRP_MJ_Xxx。然后IoCallDriver函数将利用DriverObject指针找到设备对象中的MajorFunction表。IoCallDriver将使用主功能代码索引这个表,最后调用找到的地址(派遣函数)。”

我的疑问是:
1,I/O堆栈的第一个元素指针指向不存在的“-1”元素,那么是不是以后的第n个堆栈单元指向的都是实际上存在的第n-1个元素?
2,那么对我们编写驱动程序有意义的单元其实就是从I/O堆栈的第2个单元开始的?我们调用IoGetNextIrpStackLocation其实就是为了跳过第一个元素?
3,I/O堆栈这样安排的目的在于什么?是不是为了设置一个防止数组越界的检查单元?(语言表达有问题,大家见谅)

请高手指教!!多谢!

最新喜欢:

ljmmaryljmmar...
多年以后,我又回来了。
xdjm
驱动中牛
驱动中牛
  • 注册日期2001-04-02
  • 最后登录2024-01-25
  • 粉丝0
  • 关注0
  • 积分34分
  • 威望25点
  • 贡献值0点
  • 好评度3点
  • 原创分0分
  • 专家分0分
  • 社区居民
沙发#
发布于:2002-05-13 14:37
-----------------------
|无效的堆栈单元       |<----初始化的堆栈指针
|---------------------|
|IO_STACK_LOCATION    |
|---------------------|
|IO_STACK_LOCATION    |
|---------------------|
|IO_STACK_LOCATION    |
|---------------------|
|IO_STACK_LOCATION    |
|---------------------|
|IO_STACK_LOCATION    |
----------------------
I/O管理器在分配一个IRP时,同时分配相应的IO_STACK_LOCATION单元,如上图所示:假设I/O管理器为一个IRP分配了4个IO_STACK_LOCATION单元。但是,I/O管理器在初始化IRP堆栈指针时,实际上是指向第1个IO_STACK_LOCATION单元的上面一个,而这上面一个实际上是一个无效的IO_STACK_LOCATION单元,因为I/O管理器并没有为它分配内存,如果你要去访问它的话,将有可能产生Page Fault。

那为什么要这么做呢?原因是:当I/O管理器分配了一个IRP之后,然后它就调用IoCallDriver例程将这个IRP发送给最上层的驱动程序。注意!!!IoCallDriver例程会自动地把这个IRP的的堆栈指针向下移动一个IO_STACK_LOCATION单元,这样驱动程序就得到了正确的堆栈指针。

Do you understand now?
zydcat
驱动老牛
驱动老牛
  • 注册日期2001-12-06
  • 最后登录2006-04-12
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2002-05-13 15:01
我看了书
也是这样想的
但是,为什么要这样实现呢?
[color=red]肥虫虫[/color] [img]http://www.driverdevelop.com/forum/upload/bradley/2002-11-15_ig01.gif[/img]
arthurtu
驱动巨牛
驱动巨牛
  • 注册日期2001-11-08
  • 最后登录2020-12-19
  • 粉丝0
  • 关注0
  • 积分26分
  • 威望161点
  • 贡献值0点
  • 好评度35点
  • 原创分0分
  • 专家分0分
  • 社区居民
地板#
发布于:2002-05-13 15:07
我想可能因为IoCallDriver会“自动”指向下一个IRP。
JackyWu
驱动小牛
驱动小牛
  • 注册日期2001-10-25
  • 最后登录2011-04-05
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度1点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2002-05-13 15:13
这样做的目的我猜可能是如此:
    并不是只有在刚刚建立IRP的时候才有可能调用IoCallDriver的。
    比如我在第一层驱动程序(对应于第一个实际存在的I/O堆栈),我想通过IoCallDriver调用第二层驱动程序,那么这个时候就需要IoCallDriver自动往下走一个I/O堆栈。所以在IoCallDriver里面会出现IoSetNextIrpStackLocation(Irp)。
    然而在IRP刚刚建立的时候第一次调用IoCallDriver是情况有所区别的,如果这个时候我们在不预先设定一个空的I/O堆栈在最上面,IoCallDriver里面IoSetNextIrpStackLocation一下,完了,堆栈指针指向第2个I/O了。
    
    以上是我的猜测,大家看是不是对的。
多年以后,我又回来了。
zydcat
驱动老牛
驱动老牛
  • 注册日期2001-12-06
  • 最后登录2006-04-12
  • 粉丝0
  • 关注0
  • 积分9分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2002-05-13 15:24
很明显是这样
[color=red]肥虫虫[/color] [img]http://www.driverdevelop.com/forum/upload/bradley/2002-11-15_ig01.gif[/img]
comealong
驱动牛犊
驱动牛犊
  • 注册日期2003-04-30
  • 最后登录2012-01-19
  • 粉丝0
  • 关注0
  • 积分14分
  • 威望105点
  • 贡献值0点
  • 好评度10点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2004-12-06 10:51
如果不是版本不同
那么就是你理解有问题

下面我列出一些源代码(2k) 问题就清楚了

#define IopInitializeIrp( Irp, PacketSize, StackSize ) {          \
    RtlZeroMemory( (Irp), (PacketSize) );                         \
    (Irp)->Type = (CSHORT) IO_TYPE_IRP;                           \
    (Irp)->Size = (USHORT) ((PacketSize));                        \
    (Irp)->StackCount = (CCHAR) ((StackSize));                    \
    (Irp)->CurrentLocation = (CCHAR) ((StackSize) + 1);           \
    (Irp)->ApcEnvironment = KeGetCurrentApcEnvironment();         \
    InitializeListHead (&(Irp)->ThreadListEntry);                 \
    (Irp)->Tail.Overlay.CurrentStackLocation =                    \
        ((PIO_STACK_LOCATION) ((UCHAR *) (Irp) +                  \
            sizeof( IRP ) +                                       \
            ( (StackSize) * sizeof( IO_STACK_LOCATION )))); }



NTSTATUS
FASTCALL
IopfCallDriver(
    IN PDEVICE_OBJECT DeviceObject,
    IN OUT PIRP Irp
    )

/*++

Routine Description:

    This routine is invoked to pass an I/O Request Packet (IRP) to another
    driver at its dispatch routine.

Arguments:

    DeviceObject - Pointer to device object to which the IRP should be passed.

    Irp - Pointer to IRP for request.

Return Value:

    Return status from driver's dispatch routine.

--*/

{
    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--;

    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;
}

很明显,与你们说的几乎相反, 不是在前面, 而是在最后面
的无效位置

游客

返回顶部