天天看點

windows核心原理與實作筆記之IO請求包

IRP 定義:

typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP {

    CSHORT Type;

    USHORT Size;

    PMDL MdlAddress;//該I/O請求的使用者緩沖區的MDL,僅用于“直接I/O”類型

    ULONG Flags;//用于記錄各種标志

    union {

        struct _IRP *MasterIrp;//若這是一個關聯IRP,則指向主IRP

        LONG IrpCount;//若這是一個主IRP,則必須先完成多少個關聯IRP

        PVOID SystemBuffer;//該操作被緩沖起來,指向系統位址空間緩沖區的位址

    } AssociatedIrp;

    LIST_ENTRY ThreadListEntry;//連結清單向,可以加入到線程的未完成的I/O請求連結清單中

    IO_STATUS_BLOCK IoStatus;//I/O操作的狀态

    KPROCESSOR_MODE RequestorMode;//核心模式I/O請求或使用者模式I/O請求

    BOOLEAN PendingReturned;//未完成傳回

    CHAR StackCount;//棧單元計數

    CHAR CurrentLocation;//目前棧單元位置

    BOOLEAN Cancel;//該I/O請求是否已被取消

    KIRQL CancelIrql;//取消自旋鎖在哪級IROQ上被擷取

    CCHAR ApcEnvironment;//用于當該IRP被初始化時儲存APC環境

    UCHAR AllocationFlags;//該IRP記憶體的配置設定控制狀态

    PIO_STATUS_BLOCK UserIosb;//使用者的I/O狀态塊

    PKEVENT UserEvent;//使用者事件對象

    union {

        struct {

            PIO_APC_ROUTINE UserApcRoutine;//當I/O請求完成時指向的APC例程

            PVOID UserApcContext;//傳遞UserApcRoutine的環境參數

        } AsynchronousParameters;

        LARGE_INTEGER AllocationSize;//配置設定塊的大小

    } Overlay;

    PDRIVER_CANCEL CancelRoutine;//若是可取消的I/O請求,該域包含了取消時調用的例程

PVOID UserBuffer;//調用者(即發起者)提供的輸出緩沖區的位址

//以下Tail聯合成員用于當I/O管理器處理該I/O請求時存放各種工作資訊

    union {

        struct {

            union {

                KDEVICE_QUEUE_ENTRY DeviceQueueEntry;//裝置隊列項

                struct {

                    PVOID DriverContext[4];//由驅動程式解釋和使用

                } ;

            } ;

            PETHREAD Thread;//指向發起者線程的ETHREAD

            PCHAR AuxiliaryBuffer;//輔助緩沖區

            struct {

                LIST_ENTRY ListEntry;//存放到完成隊列中的連結清單項

                union {

                    struct _IO_STACK_LOCATION *CurrentStackLocation;//指向目前棧單元,驅動程式不可直接通路

                    ULONG PacketType;//Minipacket 的類型

                };

            };

            PFILE_OBJECT OriginalFileObject;//指向原始的檔案對象

        } Overlay;

        KAPC Apc;//特殊核心模式APC或發起者的APC

        PVOID CompletionKey;//完成鍵,用于辨別在不同檔案句柄上的I/O請求

    } Tail;

} IRP, *PIRP;

IRP對象從一個I/O請求被發起時開始存在,一直到該I/O請求被完成或者取消為止。

IRP對象的設計特點:

  1. 所有的I/O請求都被抽象成針對檔案對象的操作,OriginalFileObject 記錄了該檔案對象,代表一個I/O 請求的目标
  2. 棧單元。由于可能由多個驅動程式一次參與到一個I/O請求的處理過程中,是以,一個IRP對象出了以上列出的IRP資料結構,其後還有一個稱為棧單元的數組。每個參與處理的驅動程式都可以有它自己的棧單元。
  3. 支援取消。線程可以指定一個取消例程,以便當I/O請求被取消時可以執行相關的動作。
  4. I/O請求的完成。當一個驅動程式的分發例程認為它已經完成了該I/O請求時,會顯式的告訴I/O管理器,此I/O請求已完成。

棧單元IO_STACK_LOCATION 定義:

typedef struct _IO_STACK_LOCATION {

    UCHAR MajorFunction;//在該裝置對象上的I/O請求主功能碼

    UCHAR MinorFunction; //在該裝置對象上的I/O請求次功能碼

    UCHAR Flags;

    UCHAR Control;

    union {

        struct {...} Create; //NtCreateFile 的參數

        struct {...} CreatePipe;// NtCreaeNamedPipeFile 的參數

        struct {...} CreateMailslot;// NtCreateMailslotFile 的參數

        struct {...} Read;// NtReadFile 的參數

        struct {...} Write;// NtWriteFile 的參數

        struct {...} QueryDirectory;// NtQueryDirectory 的參數

        struct {...} NotifyDirectory;// NtNotifyChangeDirectroyFile的參數

        struct {...} QueryFile;// NtQueryInformationFile 的參數

        struct {...} SetFile;// NtSetInformationFile 的參數

        struct {...} QueryEa;// NtQueryEaFile 的參數

        struct {...} SetEa;//NtSetEaFile 的參數

        struct {...} QueryVolume;// NtQueryvolumeInformationFile 的參數

        struct {...} SetVolume;// NtSetvolumeInformationFile 的參數

        struct {...} FileSystemControl;// NtFsControlFile 的參數

        struct {...} LockControl;// NtLock/NtUnlockFile 的參數

//NtFlushBuffersFile的參數

//NtCancelIoFile的參數

        struct {...} DeviceIoControl;//NtDeviceIoControFile的參數

        struct {...} QuerySecurity;// NtQuerySecurityObject 的參數

        struct {...} SetSecurity;// NtSetSecurityObject 的參數

        struct {...} MountVolume;// MountVolume的參數

        struct {...} VerifyVolume;// VerifyVolume的參數

        struct {...} Scsi;//SCSI 内部裝置控制的參數

        struct {...} QueryQuota;// NtQueryQuotaInformationFile 的參數

        struct {...} SetQuota;//NtSetQuotaInformationFile 的參數

        struct {...} QueryDeviceRelations;//IRP_MN_QUERY_DEVICE_RELATIONS的參數

        struct {...} QueryInterface;//IRP_MN_QUERY_INTERFACE的參數

        struct {...} DeviceCapabilities;//IRP_MN_QUERY_CAPABILITIES的參數

        struct {...} FilterResourceRequirements;

//IRP_MN_FILTER_RESOURCE_REQUITEMENTS的參數

        struct {...} ReadWriteConfig;//IRP_MN_READ_CONFIG和IRP_MN_WRITE_CONFIG的參數

        struct {...} SetLock;//IRP_MN_SET_LOCK 的參數

        struct {...} QueryId;//IRP_MN_QUERY_ID的參數

        struct {...} QueryDeviceText;//IRP_MN_QUERY_DEVICE_TEXT的參數

        struct {...} UsageNotification;//IRP_MN_DEVICE_USAGE_NOTIFICATION的參數

        struct {...} WaitWake;//IRP_MN_WAIT_WAKE的參數

        struct {...} PowerSequence;//IRP_MN_POWER_SEQUENCE的參數

        struct {...} Power;//IRP_MN_SET_POWER、IRP_MN_QUERY_POWER的參數

        struct {...} StartDevice;//StartDevice 的參數、Cleanup的參數

        struct {...} WMI;//WMI IRP的參數

        struct {...} Others;//其他,由驅動程式自己定義和解釋

    } Parameters;

    PDEVICE_OBJECT DeviceObject;

    PFILE_OBJECT FileObject;

    PIO_COMPLETION_ROUTINE CompletionRoutine;

    PVOID Context;

} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

Control 域包含了棧單元的控制标志,該域對驅動程式是隻讀的,請參考宏定義

#define SL_PENDING_RETURNED             0x01

#define SL_ERROR_RETURNED               0x02

#define SL_INVOKE_ON_CANCEL             0x20

#define SL_INVOKE_ON_SUCCESS            0x40

#define SL_INVOKE_ON_ERROR              0x80

DeviceObject :指向與該棧單元相對應的裝置對象

FileObject: 指向與DeviceObject相關聯的檔案對象

CompletionRoutine:是該棧單元對應的驅動程式通過IoSetCompletionRoutine設定的完成例程

Context :由驅動程式指定的、傳遞給CompletionRoutine 的參數

IRP與檔案對象、裝置對象和驅動程式之間的關系,如下圖:

windows核心原理與實作筆記之IO請求包

IRP對象是通過IoAllocateIrp 配置設定的,IoAllocateIrp 轉發給pIoAllocateIrp 函數指針。pIoAllocateIrp 在初始化時指向IopAllocateIrpPrivate。是以,IRP對象實際是在IopAllocateIrpPrivate 完成的,通過IopFreeIrp 釋放IRP對象。