[Windowsドライバ開発](三)基礎知識——ドライバルーチン


一、NT式駆動の基本ルーチン
1.駆動入口関数——DriverEntry
//           

NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);

// 

DriverEntryの主な作業はドライバの初期化です.システムプロセスSystemによって呼び出されます.
ドライバがロードされると、ドライバに対応するレジストリ・アイテムを問い合わせるドライバ・オブジェクトが作成されます.
DriverEntryが呼び出されると2つのパラメータが渡されます.これらは、さっき作成したドライバオブジェクトのポインタと、デバイスサービスキーを指すキー名文字列ポインタです.この文字列の内容は一般的にRESGISTRYMACHINESYSTEMControlSetServices[サービス名]です.ドライバでは、文字列は一般的にUNICODE形式で存在します.
注意:デバイス・サービス・キーのキー名を保存する必要がある場合があります.関数が返されると、この値が空になる可能性があります.
DriverEntryなどのカーネル関数の戻り値は一般にNTSTATUSタイプである.マクロNT_の使用SUCCESS(NTSTATUS status)は、戻り状態が正常かどうかを検出します.
DriverEntryでは、一般的にいくつかのことをする必要があります.
a.駆動アンインストールルーチンの設定
b.IRPの配布関数
c.デバイスオブジェクトの作成
ここで、ドライバアンインストールルーチンとIRP配布関数は、ドライバオブジェクトに対して設定されます.デバイスオブジェクトには、兄のIRP配布関数の関数ポインタを格納するMajorFunction数字があります.
NTドライバでは、デバイスオブジェクトを作成してIoCreateDeviceを呼び出すことができます.
// IoCreateDevice WDK    

NTKERNELAPI
NTSTATUS
IoCreateDevice(
    __in  PDRIVER_OBJECT DriverObject,
    __in  ULONG DeviceExtensionSize,
    __in_opt PUNICODE_STRING DeviceName,
    __in  DEVICE_TYPE DeviceType,
    __in  ULONG DeviceCharacteristics,
    __in  BOOLEAN Exclusive,
    __out
    __drv_out_deref(
        __drv_allocatesMem(Mem)
        __drv_when((((inFunctionClass$("DRIVER_INITIALIZE"))
             ||(inFunctionClass$("DRIVER_DISPATCH")))),
             __drv_aliasesMem)
        __on_failure(__null))
    PDEVICE_OBJECT *DeviceObject
    );

//

DriverObject:現在の駆動対象ポインタ.
DeviceExtensionSize:デバイス拡張のサイズ.IOマネージャは、このサイズに基づいてメモリにデバイス拡張子を作成し、ドライバオブジェクトに関連付けます.
DeviceName:デバイスオブジェクトの名前.
DeviceCharacteristics:デバイスオブジェクトの特徴.
Exclusive:デバイスオブジェクトがカーネルモードで使用されているかどうかは、一般的にTRUEに固定されています.
DeviceObject:作成したデバイスオブジェクトポインタ.
注意:デバイス名文字列は、Device[デバイス名]の形式でなければなりません.
ユーザー・ステータスのアプリケーションがデバイスを識別できるようにするには、一般的に2つの方法があります.
a.シンボルリンク
b.デバイスインタフェース(NT式駆動ではあまり使用されない)
シンボルリンクは、デバイスオブジェクトのユーザ状態の名前として理解できます.すなわち、デバイス名はカーネル状態で使用され、シンボルリンクはユーザー状態で使用されます.
シンボルリンクを作成するには、IoCreateSymbolicLinkを使用します.
// IoCreateSymbolicLink WDK    

NTKERNELAPI
NTSTATUS
IoCreateSymbolicLink(
    __in PUNICODE_STRING SymbolicLinkName,
    __in PUNICODE_STRING DeviceName
    );

//

SymbolicLinkName:シンボルリンク名.
DeviceName:デバイスオブジェクト名.
注意:カーネル状態では、シンボルリンクは「??」または「DosDevices」で始まります.ユーザーモードでは「\.」で始まる.
デバイス拡張は、使用時に次のコードを使用できます.
// Code:      

PDEVICE_EXTENSION pDeviceExtension = (PDEVICE_EXTENSION)pDeviceObject->DeviceExtension;

// 

2.駆動アンインストールルーチン——DriverUnload
このルーチンは、ドライバのアンインストール時に呼び出されます.NTドライバでは、DriverEntryで作成したデバイスオブジェクトを削除し、それに関連付けられたシンボルリンクを削除します.また、一部のリソースの回収も担当しています.
デバイスオブジェクトを削除する関数はIoDeleteDeviceです
// IoDeleteDevice WDK    

NTKERNELAPI
VOID
IoDeleteDevice(
    __in __drv_mustHold(Memory) __drv_freesMem(Mem) PDEVICE_OBJECT DeviceObject
    );

//

DeviceObject:削除するデバイスオブジェクトポインタ.
シンボルリンクを削除する関数はIoDeleteSymbolicLinkです
// IoDeleteSymbolicLink WDK    

NTKERNELAPI
NTSTATUS
IoDeleteSymbolicLink(
    __in PUNICODE_STRING SymbolicLinkName
    );

//

SymbolicLinkName:既に登録されている、削除するシンボルリンク.
駆動オブジェクトに基づいて、駆動によって作成されたすべてのデバイスオブジェクトを巡回できます.ドライバオブジェクトのDeviceObjectドメインでは、ドライバオブジェクトの最初のデバイスを見つけることができ、デバイスオブジェクトのNextDeviceドメインに基づいて、デバイスチェーンテーブル内の他のデバイスオブジェクトを見つけることができます.
二、WDM式駆動の基本ルーチン//
WDMモデルでは、1つのデバイスの動作は、少なくとも2つのデバイスオブジェクトが共に完了する必要がある.一つは物理デバイスオブジェクト(Physical Device Object、略称PDO)であり、一つは機能デバイスオブジェクト(Function Device Object、略称FDO)である.コンピュータがデバイスを挿入すると、バスドライバはPDOを自動的に作成します.PDOはデバイスを単独で操作することはできず、FDOと一緒に使用する必要があります.Windowsがドライバのインストールを要求すると、実際にはWDMドライバがインストールされ、FDOの作成を担当し、PDOに添付されます.
FDOがPDOに付加されると、PDOのAttachedDeviceはFDOの位置を記録します.PDOは下層駆動(下層駆動)であり、FDOは上層駆動(上層駆動)である.
FDOとPDOの間にはフィルタ駆動も存在する.FDOの上にあるものを上層フィルタ駆動、FDOの下にあるものを下層フィルタ駆動と呼ぶ.1つのWDM駆動は、複数の上位フィルタ駆動および下位フィルタ駆動を有することができる.デバイスオブジェクトのStackSizeサブドメインは、デバイスオブジェクトが最下層の物理デバイスの間に存在するデバイスオブジェクトの数を示す.
1.WDM駆動の入口関数——DriverEntry
NT式駆動と同様にWDM駆動のエントリプログラムもDriverEntryである.しかし、デバイスオブジェクトを作成する機能はDriverEntryではなく、新しいルーチンであるAddDeviceに渡されます.同時に対IRP_を追加しましたMJ_PNP処理の配布関数.
AddDeviceルーチンはWDM特有であり、DriverEntryではAddDeviceルーチンの関数アドレスを設定する必要がある.設定は、ドライバオブジェクトのDriverExtensionサブドメインのAddDeviceサブドメインにAddDeviceの実際のルーチンの関数アドレスを保存します.AddDeviceルーチンの名前は任意に命名できます.
// AddDevice    
NTSTAUS MyAddDevice(IN PDRIVER_OBJECT pDriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject)

//   AddDevice       
pDriverObject->DriverExtension-> AddDevice = MyAddDevice;

//

2.ドライバアンインストールルーチン——DriverUnload()
WDM駆動では、実際のアンインストール作業はIRP_MN_REMOVE_DEVICE対応の配布関数が処理され、ここでのDriverUnloadは主にDriverEntryで申請したメモリを処理します.
    a. IRP_MN_REMOVE_DEVICE処理
駆動ヒゲ内部はIRP駆動、IRP_MN_REMOVE_DEVICEというIRPは、デバイスをアンインストールする必要がある場合に、プラグアンドプレイマネージャによって作成され、ドライバに送信されます.IRPは一般的に2つの番号によってそのIRPの具体的な意味を指定し、1つは主IRP番号(Major IRP)、1つは補助IRP番号(Minor IRP)である.
デバイスがアンインストールされる必要がある場合、複数のIRPが相次いで発行されます.MJ_PNP.これらのIRPの補助IRP番号は異なります.そのうちの1つであるIRP_MN_REMOVE_DEVICE.
WDMドライバでは、デバイスのアンインストールは通常IRP_MN_REMOVE_DEVICEの出口関数でアンインストールします.学部を削除したり、シンボルリンクをキャンセルしたりするほか、PDOのスタックからFDOを削除する必要があります.IoDetachDeviceを呼び出す必要があります:
// IoDetachDevice WDK    :

NTKERNELAPI
VOID
IoDetachDevice(
    __inout PDEVICE_OBJECT TargetDevice    //           
    );

// 

このとき、FDOはデバイスチェーンから削除されるが、PDOはまだ存在する.PDOはオペレーティングシステムによって削除されます.
AddDevice基本手順:
1.AddDevice IoCreateDevice関数によるFDOの作成、FDOのシンボルリンクの作成
2.ドライバ拡張で作成したFDOのアドレスを保存します.
3.IoAttachDeviceToDeviceStack()を呼び出してPDOにFDOを添付します.
// IoAttachDeviceToDeviceStack WDK    

NTKERNELAPI
PDEVICE_OBJECT
IoAttachDeviceToDeviceStack(
    __in __drv_mustHold(Memory) __drv_when(return!=0, __drv_aliasesMem)
    PDEVICE_OBJECT SourceDevice,
    __in PDEVICE_OBJECT TargetDevice
    );

//

SourceDevice:PDOにFDOが添付されている場合、このパラメータはFDOを表します.
TargetDevice:付加されたデバイス.FDOとPDOとの間にフィルタ駆動が存在する場合、FDOは実際にはフィルタ駆動に付加され、フィルタ駆動はPDOに付加される.
戻り値:SourceDeviceの下位デバイスを返します.
//              

typedef struct _DEVICE_EXTENSION
{
    PDEVICE_OBJECT pFunctionDeviceObject;  //     (FDO)
    UNICODE_STRING ustrDeviceName;         //     
    UNICODE_STRING ustrSymbolicLinkName;   //      

    PDEVICE_OBJECT pNextStackDevice;       //        (FDO)   
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;


// 

4.デバイス拡張pFunctionDeviceObject->Flagsを設定します.
    DO_BUFFERED_IO:バッファメモリ装置
    ~DO_DEVICE_INITIALIZING:これはFlagsの初期化が完了したことを示す設定が必要です.