读wrk系列 关于IRP(1)

来源:互联网 发布:csol刷枪软件免费版 编辑:程序博客网 时间:2024/05/01 07:19

NtReadFile为例,

 

1.      建立irp

PIRPIopAllocateIrpPrivate(    IN CCHAR StackSize,    IN BOOLEAN ChargeQuota)//如果大小小于IopLargeIrpStackLocations,那么从prcb->PPLookasideList[number].P;这个快查表里面拿一个,如果大于这个值则构造一个//然后初始化#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 )))); }

2.调用IopSynchronousServiceTail派发irp


NTSTATUSIopSynchronousServiceTail(    IN PDEVICE_OBJECT DeviceObject,    IN PIRP Irp,    IN PFILE_OBJECT FileObject,    IN BOOLEAN DeferredIoCompletion,    IN KPROCESSOR_MODE RequestorMode,    IN BOOLEAN SynchronousIo,    IN TRANSFER_TYPE TransferType    ){    NTSTATUS status;    PAGED_CODE();//异步操作要插入irp的thread->irpList    if (!SynchronousIo) {        IopQueueThreadIrp( Irp );    }//……    //    // 向设备发irp    //    status = IoCallDriver( DeviceObject, Irp );    if (DeferredIoCompletion) {        if (status != STATUS_PENDING) {            PKNORMAL_ROUTINE normalRoutine;            PVOID normalContext;            KIRQL irql = PASSIVE_LEVEL; // Just to shut up the compiler            ASSERT( !Irp->PendingReturned );            if (!SynchronousIo) {                KeRaiseIrql( APC_LEVEL, &irql );            }    //完成请求        IopCompleteRequest( &Irp->Tail.Apc,                                &normalRoutine,                                &normalContext,                                (PVOID *) &FileObject,                                &normalContext );            if (!SynchronousIo) {                KeLowerIrql( irql );            }        }    }//同步下等待irp完成    if (SynchronousIo) {        if (status == STATUS_PENDING) {            status = KeWaitForSingleObject( &FileObject->Event,                                            Executive,                                            RequestorMode,                                            (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),                                            (PLARGE_INTEGER) NULL );            if (status == STATUS_ALERTED || status == STATUS_USER_APC) {                IopCancelAlertedRequest( &FileObject->Event, Irp );            }            status = FileObject->FinalStatus;        }        IopReleaseFileObjectLock( FileObject );    }    return status;}

3.向设备派发irp

FORCEINLINEIopfCallDriver(    IN PDEVICE_OBJECT DeviceObject,    IN OUT PIRP Irp    ){    PIO_STACK_LOCATION irpSp;    PDRIVER_OBJECT driverObject;    NTSTATUS status;//向下一层    Irp->CurrentLocation--;irpSp = IoGetNextIrpStackLocation( Irp );//调整irpSp    Irp->Tail.Overlay.CurrentStackLocation = irpSp;    irpSp->DeviceObject = DeviceObject;    driverObject = DeviceObject->DriverObject;status = driverObject->MajorFunction[irpSp->MajorFunction]( DeviceObject,                                                              Irp );    return status;}

driverObject->MajorFunction[irpSp->MajorFunction]这个调用以ClassRead为例,

 

ClassRead调用 IoMarkIrpPending –IoStartPacket – return Status_Pending


VOIDIoStartPacket(    IN PDEVICE_OBJECT DeviceObject,    IN PIRP Irp,    IN PULONG Key OPTIONAL,    IN PDRIVER_CANCEL CancelFunction OPTIONAL    ){    KIRQL oldIrql;    KIRQL cancelIrql = PASSIVE_LEVEL;    BOOLEAN i;    KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );    if (CancelFunction) {        IoAcquireCancelSpinLock( &cancelIrql );        Irp->CancelRoutine = CancelFunction;    }//如果设备正忙,挂入设备链表队尾    if (Key) {        i = KeInsertByKeyDeviceQueue( &DeviceObject->DeviceQueue,                                      &Irp->Tail.Overlay.DeviceQueueEntry,                                      *Key );    } else {        i = KeInsertDeviceQueue( &DeviceObject->DeviceQueue,                                 &Irp->Tail.Overlay.DeviceQueueEntry );    }       if (!i) {//不忙的话直接调用startIo处理        DeviceObject->CurrentIrp = Irp;        if (CancelFunction) {            if (DeviceObject->DeviceObjectExtension->StartIoFlags & DOE_STARTIO_NO_CANCEL) {                Irp->CancelRoutine = NULL;            }            IoReleaseCancelSpinLock( cancelIrql );        }        DeviceObject->DriverObject->DriverStartIo( DeviceObject, Irp );    } else {        if (CancelFunction) {            if (Irp->Cancel) {                Irp->CancelIrql = cancelIrql;                Irp->CancelRoutine = (PDRIVER_CANCEL) NULL;                CancelFunction( DeviceObject, Irp );            } else {                IoReleaseCancelSpinLock( cancelIrql );            }        }    }    KeLowerIrql( oldIrql );}


4.完成irp 

VOIDFASTCALLIopfCompleteRequest(    IN PIRP Irp,    IN CCHAR PriorityBoost){//…// Irp->CurrentLocation为0时是栈底,每深入一层就减1//循环所有已经跑过的栈对他们调用完成历程   for (stackPointer = IoGetCurrentIrpStackLocation( Irp ),         Irp->CurrentLocation++,         Irp->Tail.Overlay.CurrentStackLocation++;         Irp->CurrentLocation <= (CCHAR) (Irp->StackCount + 1);         stackPointer++,         Irp->CurrentLocation++,         Irp->Tail.Overlay.CurrentStackLocation++) {        Irp->PendingReturned = stackPointer->Control & SL_PENDING_RETURNED;        if (!NT_SUCCESS(Irp->IoStatus.Status)) {            if (Irp->IoStatus.Status != errorStatus) {                errorStatus = Irp->IoStatus.Status;                stackPointer->Control |= SL_ERROR_RETURNED;                bottomSp->Parameters.Others.Argument4 = (PVOID)(ULONG_PTR)errorStatus;                bottomSp->Control |= SL_ERROR_RETURNED; // Mark that there is status in this location            }        }        if ( (NT_SUCCESS( Irp->IoStatus.Status ) &&             stackPointer->Control & SL_INVOKE_ON_SUCCESS) ||             (!NT_SUCCESS( Irp->IoStatus.Status ) &&             stackPointer->Control & SL_INVOKE_ON_ERROR) ||             (Irp->Cancel &&             stackPointer->Control & SL_INVOKE_ON_CANCEL)           ) {//调用完成函数            ZeroIrpStackLocation( stackPointer );            if (Irp->CurrentLocation == (CCHAR) (Irp->StackCount + 1)) {                deviceObject = NULL;            }            else {                deviceObject = IoGetCurrentIrpStackLocation( Irp )->DeviceObject;            }            status = stackPointer->CompletionRoutine( deviceObject,                                                      Irp,                                                      stackPointer->Context );            if (status == STATUS_MORE_PROCESSING_REQUIRED) {                //返回这个值就什么都别做了,表示完成例程在获得irp后还要做处理//如果驱动设置了IpCompletion 例程,那么他在上一步(第//一步)中必须使用 IoCopyCurrentIrpStackLocationToNext                return;            }        } else {            if (Irp->PendingReturned && Irp->CurrentLocation <= Irp->StackCount) {                IoMarkIrpPending( Irp );            }            ZeroIrpStackLocation( stackPointer );        }    }    //    // Check to see whether this is an associated IRP. 略if (Irp->Flags & IRP_ASSOCIATED_IRP) { …}    //    // Check to see if we have a name junction. If so set the stage to    // transmogrify the reparse point data in IopCompleteRequest.    //    if ((Irp->IoStatus.Status == STATUS_REPARSE )  && //…略// Check to see if this is paging I/O or a close operation. 略//略很多//这是一个同步操作 那么直接返回,调用方会执行IopCompleteRequest    if (Irp->Flags & IRP_DEFER_IO_COMPLETION && !Irp->PendingReturned) {        if ((Irp->IoStatus.Status == STATUS_REPARSE )  &&            (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)) {            //            // For name junctions we reinstate the address of the appropriate            // buffer. It is freed in parse.c            //            Irp->Tail.Overlay.AuxiliaryBuffer = saveAuxiliaryPointer;        }        return;    }    //    // Finally, initialize the IRP as an APC structure and queue the special    // kernel APC to the target thread.    //异步操作,向该线程投掷APC执行IopCompleteRequest    thread = Irp->Tail.Overlay.Thread;    fileObject = Irp->Tail.Overlay.OriginalFileObject;    if (!Irp->Cancel) {        KeInitializeApc( &Irp->Tail.Apc,                         &thread->Tcb,                         Irp->ApcEnvironment,                         IopCompleteRequest,                         IopAbortRequest,                         (PKNORMAL_ROUTINE) NULL,                         KernelMode,                         (PVOID) NULL );        (VOID) KeInsertQueueApc( &Irp->Tail.Apc,                                 fileObject,                                 (PVOID) saveAuxiliaryPointer,                                 PriorityBoost );}


//IopCompleteRequest  Apc//将缓冲区考回用户态,释放系统内存 释放mdlRtlCopyMemory( irp->UserBuffer,                               irp->AssociatedIrp.SystemBuffer,                               irp->IoStatus.Information );    if (irp->MdlAddress) {        for (mdl = irp->MdlAddress; mdl != NULL; mdl = nextMdl) {            nextMdl = mdl->Next;            IoFreeMdl( mdl );        }    }异步完成,可通知应用层,插用户apcKeSetEvent( irp->UserEvent, 0, FALSE );       if (irp->Overlay.AsynchronousParameters.UserApcRoutine) {            KeInitializeApc( &irp->Tail.Apc,                             &thread->Tcb,                             CurrentApcEnvironment,                             IopUserCompletion,                             (PKRUNDOWN_ROUTINE) IopUserRundown,                             (PKNORMAL_ROUTINE) irp->Overlay.AsynchronousParameters.UserApcRoutine,                             irp->RequestorMode,                             irp->Overlay.AsynchronousParameters.UserApcContext );            KeInsertQueueApc( &irp->Tail.Apc,                              irp->UserIosb,                              NULL,                              2 );        } else if (port && irp->Overlay.AsynchronousParameters.UserApcContext) {            //            // If there is a completion context associated w/this I/O operation,            // send the message to the port. Tag completion packet as an Irp.            //            irp->Tail.CompletionKey = key;            irp->Tail.Overlay.PacketType = IopCompletionPacketIrp;            KeInsertQueue( (PKQUEUE) port,                           &irp->Tail.Overlay.ListEntry );        } else {            //            // Free the IRP now since it is no longer needed.            //            IoFreeIrp( irp );        }

5.完成历程

6.取消IO

NtCancelIoFile  对thread->IrpList中的irp进行比对,凡是fileObject相符的就调用IoCancelIrp, IoCancelIrp则调用驱动注册的cancelRoutine

7.irp 完成的fix


*. tips about IpCompletion 

a.如果驱动设置了IpCompletion 例程,那么他在上一步(第一步)中必须使用IoCopyCurrentIrpStackLocationToNext

 

b.一个IoCompletion 例程能够返回两个状态值中的任一个:

STATUS_CONTINUE_COMPLETION – 继续向上完成特定 IRP 。I/O 管理器提升IRP 栈指针,并且调用上一个驱动的 IoCompletion 例程。

STATUS_MORE_PROCESSING_REQUIRED – 中断向上完成特定 IRP 的过程,并且把IRP 栈指针留在当前位置。返回这一状态的驱动通常会在过后调用

IoCompleteRequest例程来重新开始向上完成特定 IRP 的过程



原创粉丝点击