读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 的过程
- 读wrk系列 关于IRP(1)
- 读wrk系列 关于IRP(1)
- 读wrk系列 Mark一下MDL
- 驱动入门科普:从WRK理解IRP IRP Stack之理论篇
- 驱动入门科普:从WRK理解IRP IRP Stack之实践篇
- WRK
- 关于irp堆栈
- IRP详解(1)----请求类型
- Windows 内核(WRK)简介
- Windows 内核(WRK)简介 .
- Windows 内核(WRK)简介
- Windows 内核(WRK)简介
- Windows 内核(WRK)简介
- IRP
- irp
- IRP
- IRP
- IRP
- java.lang.OutOfMemoryError: PermGen space tomcat的处理办法
- 条款9:绝不在构造和析构过程中调用virtual函数
- 黑马程序员_异常
- FTP上传下载的断点续传实现
- java方向笔试题3- Java web部分
- 读wrk系列 关于IRP(1)
- javase_24(正则表达式的学习)
- java按字节截取字符串
- GIC (General Interrupt Controller)之一
- 用于ftp断点续传,得到本地和ftp服务器上的 文件大小
- java方向笔试题4- 数据库
- 计算机科学中最重要的32个算法
- 条款10:令operator=返回一个reference to *this
- java方向笔试题5- XML和框架