64 ビット Microsoft Windows ドライバー用のチェックリスト

最終更新日: 2008年7月15日

このチェックリストは、64 ビット エディションの Windows オペレーティング システムで実行されるドライバーを作成する開発者用の、コーディングとインストールに関する懸念点の簡単な一覧です。

この情報は、下記のオペレーティング システムに適用されます。
Microsoft Windows Vista
Microsoft Windows Server 2008
64 ビット エディションの Microsoft Windows Server 2003
Microsoft Windows XP

*
トピック
64 ビット Windows 用のドライバー: はじめに64 ビット Windows 用のドライバー: はじめに
64 ビット Windows プログラミング モデル64 ビット Windows プログラミング モデル
コーディング ガイドラインと移植に関する問題コーディング ガイドラインと移植に関する問題
64 ビット Windows でのドライバーのインストール64 ビット Windows でのドライバーのインストール
64 ビット ドライバー開発のためのリソース64 ビット ドライバー開発のためのリソース

64 ビット Windows 用のドライバー: はじめに

64 ビット システムの採用は、特にエンタープライズの領域で、速やかに進む見込みです。64 ビット システム用に広範なデバイスがカバーされ、高品質のドライバーが利用可能になるにつれ、この採用はいっそう速く進むでしょう。

自社のデバイスで 64 ビット システムのサポートを開始するには:

デバイスが 64 ビットの物理メモリをアドレス指定することを確認します。

64 ビット セーフなプログラミング方法で Microsoft Windows ドライバーをコーディングし、64 ビット コンパイラを使用して、問題領域を見つけます。

Windows Driver Foundation (WDF)Windows Driver Model (WDM)、および各ツールが、32 ビット Windows と 64 ビット Windows で同じままであることに留意します。

入出力制御 (IOCTL)、直接メモリ アクセス (DMA)、およびレガシ デバイス ドライバー インターフェイス (DDI) に関連したドライバー固有の問題についてのコーディング ガイドラインに従います。

ドライバーがプラグ アンド プレイと電源の管理をサポートすることを確認します。

32 ビット ドライバーをサポートしていない点に注意してください。

カーネル モード ドライバーは、64 ビット Windows と同じアドレス スペースで動作します。

大きなシステムに適合するドライバーは、ページ プールまたは非ページ プールおよびシステム キャッシュ用に、より大きなアドレス スペースを使用できます。

ページのトップへページのトップへ

64 ビット Windows プログラミング モデル

Windows 64-Bit Edition は、Windows プログラミング モデルと Win32® API の進化によって実現しています。Windows は、下記のような 32 ビットと 64 ビット プラットフォームに単一のソース コード ベースを提供します。

既存のアプリケーションが、エンタープライズの容量に適合できます。

巨大なアドレス スペースとメモリを使用する新しい設計を有効にします。

既存の 32 ビット アプリケーションをサポートします。

さらに、

64 ビット Windows プログラミング モデルは、同じ Win32 DDI と API を使用します。

LLP64 (LongLong およびポインター) データ モデルでは、ポインターのみ 64 ビットに拡張されます。他のすべての基本的なデータ型 (整数と long) は、長さ 32 ビットのままです。16 TB もの仮想メモリを持つシステムに対応するには 64 ビットのポインターが必要ですが、ほとんどのデータは、32 ビットの整数に収まります。ほとんどのアプリケーションの場合、既定の整数サイズを 64 ビットに変更するのは、スペースを浪費するだけです。

64 ビット Windows プログラミング モデルは、新しい、明示的なサイズの型を追加し、ポインターの精度に一致する新しい整数型も追加しています。型の一覧については、「データ型」テーブルを参照してください。

ポインターは長さ 64 ビットですが、整数型と long データ型は 32 ビットのままです。

ほとんどのメモリ割り当ては 64 ビットです。

CPU マスクは 64 ビットに拡張されます。

入出力要求と Unicode 文字列の長さは、32 ビットのままです。

データ型

型の名前内容

固定幅のデータ型

 

LONG32, INT32

32 ビット符号付き

LONG64, INT64

64 ビット符号付き

ULONG32,UINT32,DWORD32

32 ビット符号なし

ULONG64,UINT64,DWORD64

64 ビット符号なし

ポインター精度のデータ型

 

INT_PTR, LONG_PTR

符号付き整数、
ポインター精度

UINT_PTR, DWORD_PTR

符号なし整数、
ポインター精度

SIZE_T

符号なしカウント、ポインター精度

SSIZE_T

符号付きカウント、
ポインター精度

メモリ レイアウト

メモリx64 ベースIntel Itanium ベース

ユーザー アドレス範囲

0x10000 – 0x000007FFFFFEFFFF

0x10000 – 0x000006FBFFFEFFFF

システム キャッシュ

1 TB

1 TB

HyperSpace

512 GB

16 GB

システム アドレス スペース (カーネル スレッドなど用)

128 GB

128 GB

ページ サイズ

4K

8K

ページ プール

128 GB

128 GB

非ページ プール

Windows Vista およびそれ以前の物理メモリの 40% で、最大 128 GB まで:
Windows Server 2008、Windows Vista SP1、およびそれ以降の物理メモリの 75% で、最大 128 GB まで。

Windows Vista およびそれ以前の物理メモリの 40%、最大 128 GB まで:
Windows Server 2008、Windows Vista SP1、およびそれ以降の物理メモリの 75%、および最大 128 GB まで。

物理メモリ アドレス

64 ビット

64 ビット

ページのトップへページのトップへ

コーディング ガイドラインと移植に関する問題

コーディング ガイドライン

Windows 64 ビットおよび 32 ビットのセーフ データ型を使用します。

すべてのポインターの使用、特にポインターの計算を検査します。

インライン アセンブリ コードを削除します (組み込みまたはネイティブ アセンブリ コードを使用します)。

x64 固有のコードの場合:
#if defined (__AMD64__)
No __X64__ definition は使用可能です。

Itanium 固有のコードの場合:
#if defined(__IA64__)

ドライバーの移植に関する問題

ドライバーは、IOCTL コマンドの 32 ビットと 64 ビット バージョンをサポートする必要があります。
「IOCTL サポート」セクションを参照してください。

DMA サポートは、32 ビットの物理アドレスのみをアドレスできるハードウェア用に実装される必要があります。
「DMA サポート」セクションを参照してください。

ポインター、多形使用、および配置の問題は、すべてのドライバーに該当します。
「ポインター、多形使用、および配置の問題」セクションを参照してください。

すべてのドライバーは、プラグ アンド プレイと電源の管理を適切にサポートする必要があります。

WDM ドライバーでは、ドライバー中心からデバイス中心のモデルに移行します。つまり、プラグ アンド プレイと電源の管理入出力要求パケット (IRP) を処理するか、ミニポート ガイドラインに従います。

ユーザー モード ドライバーは、印刷、スキャン、およびカメラ用に、64 ビットである必要があります。

レガシ API (Windows NT® 4.0 に固有) は、許容されません。

64 ビット ミニポートの場合:

Windows Driver Kit (WDK) のミニポート固有のガイドラインに従います。

PAGE_SIZE の違い(Itanium ベースのシステムでは 8 K、x64 システムでは 4 K) に留意します。

ポインター、多形使用、および配置の問題が該当します。

IOCTL、プラグ アンド プレイ、および DMA の問題は、ほとんどのミニポートに該当しません。

ビルド環境とツール

x64 用のビルド環境は、AMD64 です。

64 ビット ツールと開発プロセスは、32 ビットと類似しています。

Windows 用デバッグ ツール

64 ビット バージョンの Debugging Tools for Windows を使用すると、64 ビット プロセッサ上で動作する、ユーザー モードの 32 ビット アプリケーションと 64 ビット アプリケーションの両方をデバッグできます。このパッケージを使用して、アプリケーションと Windows-32-bit-on-Windows-64-bit (WOW64) エミュレータの両方をデバッグしてください。

Intel Itanium または x64 プロセッサ上でアプリケーションをデバッグするには、固有のプロセッサ用に設計されたパッケージを使用します。パッケージは、http://www.microsoft.com/japan/whdc/devtools/debugging/install64bit.mspx でダウンロードできます。

WDK 内のクロス コンパイラ

WDK の 64 ビット ビルド環境には、x64 ベースのプロセッサで動作する 64 ビット ドライバー コードのビルドとテストに使用できる 64 ビット コンパイラが含まれています。問題および制限については、http://msdn.microsoft.com/en-us/library/aa489554.aspx を参照してください。

チェック ビルド

ドライバー開発者は、オペレーティング システム レベルの問題を識別して診断するため、Windows のチェック ビルドを使用します。チェック ビルドでのほとんどのチェックは、パラメータまたはデータ構造体の値が、予期される通常の範囲内に収まっているかどうかを判定します。詳細については、http://www.microsoft.com/japan/whdc/DevTools/tools/chkblds.mspx を参照してください。

Driver Verifier

このツールは、通常の操作では見落とされる可能性のある多くの条件をテストし、トラップします。Driver Verifier は、ドライバーが無効な関数呼び出しを行ったり、システム障害を起こしたりしないことを確認します。このツールは、メモリ破損、IRP の誤った処理、DMA バッファの無効な使用、デッドロックの可能性などの状態を識別できます。詳細については、http://msdn.microsoft.com/en-us/library/ms792872.aspx を参照してください。

BIOS、ACPI、および修正に関するメモ

Itanium ベースのシステムは、ACPI 2.0 64 ビット テーブルをサポートする必要があります。

GUID パーティション テーブル (GPT) ディスクは、64 ビット Windows によってサポートされます。

BIOS コールバックは、x64 システム上で許容されません。

x64 ベースのシステム用 Windows との互換性のため、ドライバーは下記の行為を避ける必要があります。

KeServiceDescriptorTable をフックすることなどによって、システム サービス テーブルを変更すること。

割り込みディスパッチ テーブル (IDT) を変更すること。

グローバルディスクリプタテーブル (GDT) を変更すること。

カーネルによって割り当てられないカーネル スタックを使用すること。

カーネルの任意の部分 (AMD64 ベースのシステムでのみ検出される) を修正すること。

Windows は、これらの規則を、x64 プラットフォームに適用します。そのような変更を行うと、バグチェックが生じます。

IOCTL サポート

ポインター依存の型を含む IOCTL 構造体は、64 ビット アプリケーションと 32 ビット アプリケーションで、サイズが異なります。ドライバーは、32 ビット スレッドから発行された IOCTL と、64 ビット スレッドから発行された IOCTL とを区別する必要があります。ドライバーは、発行者のビット幅に基づいて、入力と出力のバッファ長を検証します。

ドライバーは、32 ビットと 64 ビットの呼び出し側の両方をサポートするために可能な 3 つのソリューションのいずれかを使用できます。

IOCTL 構造体でポインター型を使用するのを避けます。

IoIs32bitProcess() API を使用します。

64 ビットの呼び出し側用に、IOCTL コードの Function コード フィールドで、ビットを定義します。

IoIs32BitProcess() を使用するには、コードで 32 ビットの IOCTL 構造体を定義し、発行しているプロセスが 32 ビットと 64 ビットのいずれであるか判定します。

ヘッダー ファイル内の IOCTL 構造体

typedef struct _IOCTL_PARAMETERS {
    PVOID   Addr;
    SIZE_T  Length;
    HANDLE  Handle;
} IOCTL_PARAMETERS, *PIOCTL_PARAMETERS;

			


32 ビットの IOCTL 構造体:

//
// This structure is defined 
// inside the driver source code
//
typedef struct _IOCTL_PARAMETERS_32 {
    VOID*POINTER_32  Addr;
    INT32            Length;
    VOID*POINTER_32  Handle;
} IOCTL_PARAMETERS_32, *PIOCTL_PARAMETERS_32;

			


IoIs32BitProcess を使用した、32 ビットと 64 ビットの IOCTL の例

#ifdef _WIN64
case IOCTL_REGISTER:
if (IoIs32bitProcess(Irp)) {
  /* If this is a 32 bit process */             
  params32 =
 
   (PIOCTL_PARAMETERS_32)(Irp>AssociatedIrp.SystemBuffer);
  if(irpSp->Parameters.DeviceIoControl.InputBufferLength <

                    sizeof(IOCTL_PARAMETERS_32)) {
         status = STATUS_INVALID_PARAMETER;
       } else {
       LocalParam.Addr = params32->Addr;
        LocalParam.Handle = params32->Handle; 
           LocalParam.Length = params32->Length;
     /* Handle the ioctl here */
        status = STATUS_SUCCESS;
        Irp->IoStatus.Information = sizeof(IOCTL_PARAMETERS);
    }
} else { /* 64bit process IOCTL */
  params = (PIOCTL_PARAMETERS)
           (Irp->AssociatedIrp.SystemBuffer);
  if (irpSp->Parameters.DeviceIoControl.InputBufferLength
                            < sizeof(IOCTL_PARAMETERS)) {
         status = STATUS_INVALID_PARAMETER;
                 
  } else {                    
        RtlCopyMemory(&LocalParam, params,

sizeof(IOCTL_PARAMETERS));
     /*  Handle the ioctl here */
     status = STATUS_SUCCESS;
    }
    Irp->IoStatus.Information = sizeof(IOCTL_PARAMETERS);
}
break;

64 ビットの呼び出し側用にビットを定義する場合、Function フィールドで高位ビットを使用します。

現在の IOCTL コードには 5 フィールドがあり、11 ビットの Function フィールドが含まれます:

Device Type (16)

Access (2)

Custom (1)

Function (11)               

Method (2)

新しい IOCTL コードでは、Function フィールドで高位ビットを使用して、64 ビットの呼び出し側用を定義します。

Device Type (16)

Access (2)

Custom (1)

64Bit (1)

Function (10)

Method (2)

DMA サポート

PHYSICAL_ADDRESS typedef を使用して、物理アドレスにアクセスします。PHYSICAL_ADDRESS は 64 ビット長です。

64 ビットすべてを、有効な物理アドレスとして扱います。ハイ エンドの 32 ビットを無視しないでください。

カーネル モード ドライバー フレームワーク (KMDF) または Windows DMA DDI を使用して、すべてのプラットフォーム上で正しい操作が確実に行われるようにします。KMDF または Windows DMA ルーチンを使用する場合、Windows がサイズの問題を処理します。

必要に応じて、scatter/gather DMA モデルを使用します。

64 ビット アドレス指定機能でデバイスを使用することにより、パフォーマンスがかなり向上します。

ポインター、多形使用、および配置の問題

ポインターのサイズは、アプリケーションとドライバー全体で共通です。アプリケーション移植用のガイドラインも、下記の状況でドライバーに適用されます。

多形データの使用 (ポインター サイズに関連)。

配置の問題。

定数とマクロの計算。

最初の 2 つの項目は、このセクションで説明します。第 3 の項目は、MSDN® の記事 "Beyond Windows XP: Get Ready Now for the Upcoming 64-Bit Version of Windows" で説明します。

多形データの使用

int、long、ULONG、または DWORD にポインターをキャストしないでください。

UINT_PTR、INT_PTR、ULONG_PTR などを使用してください。

下記に例を示します。

ImageBase = (PVOID)
            ((ULONG)ImageBase | 1);

上記は、次のように書き換える必要があります。

ImageBase = (PVOID)
          ((ULONG_PTR)ImageBase | 1);

PtrToUlong()PtrToLong() を使用して、ポインターを切り捨てます。

切り捨てられたポインターを格納する int または ULONG をポインターに再キャストしないでください。

バッファ サイズを計算する際には注意してください。サイズは、ULONG の容量を上回る場合があります。

ポインター OUT パラメータを持つ関数を呼び出す場合、正しいサイズを使用するよう注意してください。

void GetBufferAddress(OUT PULONG *ptr);
{
	*ptr=0x1000100010001000;
}
void foo()
{
  ULONG bufAddress;
  //
  // this call causes memory corruption
  //
  GetBufferAddress((PULONG*)&bufAddress);
}


配置の問題

Itanium ベースのシステムは、メモリ参照用に、自然な配置を必須とします。つまり、32 ビットのアクセスは、4 バイトの境界線で行われます。きちんと配置されていないメモリ参照を行うと、Itanium ベースのシステムで例外が生じ、システムがバグ チェックされます。

配置は、x64 サポートがより良いパフォーマンスを得るために必要ですが、x64 はより許容性があります。

構造体をパックするディレクティブを使用する場合、配置の問題に注意してください。

単一のヘッダー ファイルで異なる PACK レベルを使用する場合、特に注意が必要です。

最高の結果を得るには、64 ビットの値とポインターを構造体の先頭に置きます。

RtlCopyMemory()memcpy() は、フォールトしません。

UNALIGNED マクロを使用して、配置の問題を修正してください。

#pragma pack (1) /* also set by /Zp switch */
struct AlignSample {
	ULONG size;
	void *ptr;  
};
struct AlignSample s;
void foo(void *p) {
		*p = p;	// causes alignment fault
	...
}
foo((PVOID)&s.ptr);
void foo(void *p) {
	struct AlignSample s; 
    *(UNALIGNED void *)&s.ptr = p; 
}

配置の詳細については、"メモリ管理: すべてのドライバー作成者が知る必要のある事項"を参照してください。

コーディングに関する他の問題

下記の点を、注意して調べてください。

ポインターを含む明示的および暗黙的 union。

ディスクに格納される、または 32 ビット プロセスと交換されるデータ構造体。

セキュリティディスクリプタ。

メモリ領域のサイズを扱うコード:

len = ptr2 - ptr1

len は、2^32 より大きい可能性があります

実行ハンドルを 32 ビットに切り捨てます。

断片的なサイズの割り当てを使用します。

struct foo {
	DWORD NumberOfPointers;
	PVOID Pointers[1];
} xx;
Wrong:
malloc(sizeof(DWORD)+100*sizeof(PVOID)); 
Correct:
malloc(FIELD_OFFSET(struct foo,Pointers)
    +100*sizeof(PVOID));

16 進の定数と符号なしの値は、注意して使用します。

符号なしの数値を下付き文字として使用する場合、注意します。

DWORD index = 0;

CHAR *p;

if (p[index - 1] == '0') は、Itanium ベースのシステムでアクセス違反が生じます。

32 ビット コンピューターの場合:

64 ビット コンピューターの場合:

p[index-1] == p[0xffffffff] == p[-1]

p[index-1] == p[0x00000000ffffffff] != p[-1]  

その他のクリーンアップ

-1 != 0xFFFFFFFF

0xFFFFFFFF != 無効なハンドル

DWORD は常に 32 ビットです。DWORD の変数を使用して、ポインターまたはハンドルを格納しないでください。

ポインターを PCHAR にキャストして、ポインターを計算してください。

ptr = (PVOID)((PCHAR)ptr + pageSize);

%I を使用して、デバッグ ステートメントにポインターを出力します。

Addresses >= 0x80000000 は、必ずしもカーネル アドレスではありません。

ページのトップへページのトップへ

64 ビット Windows でのドライバーのインストール

64 ビット ドライバーの INF に関する要件

Windows Server 2003 SP1 以降のバージョンの Windows では、x64 ベース システムには、Un-Decorated INF セクションがあるドライバー パッケージはインストールされません。

Intel Itanium システムとの互換性のため、Windows Server 2003 SP1 は、デコレートされていない INF セクションを含むドライバー パッケージをインストールします。ただし、INF のデコレートがハードウェアの Designed for Windows ロゴ プログラムで必要なため、デコレートされていない INF セクションを含むドライバー パッケージは、ロゴの資格認定を得ることができません。

x64 ベースのシステムにドライバー パッケージをインストールするには、INF の [Manufacturer] セクションのエントリと [Models] セクション名をデコレートする必要があります。また、Intel Itanium ベースのシステムでも、それらをデコレートする必要があります。これらのデコレーションは、Windows XP オリジナル リリース以降のすべての Windows バージョンでサポートされています。したがって、非 x86 ベースの各プラットフォーム用のすべてのリリース済み NT ベース Windows オペレーティング システムで、このようにデコレートされた INF は動作します。

ユーザーは各プラットフォームの違いを理解していないため、目標は、誤ったドライバー バイナリのインストールを防ぐことにあります。

Windows XP で導入された TargetOsVersion を使用してください。

Windows Server 2003 SP1 およびそれ以降のバージョンでは、[Manufacturer] と [Models] INF セクションは、64 ビット プラットフォーム用にデコレートする必要があります。下記に例を示します。

[Manufacturer] %mycompany% = MyCompanyModels, NTamd64
[MyCompanyModels.NTamd64] %MyDev% = mydevInstall, mydevHwid


32 ビットおよび 64 ビット プラットフォーム用のドライバーのインストール

32 ビット インストーラーから 64 ビット ドライバーをインストールするのを簡略化するため、Microsoft は、WDK で Driver Install Frameworks (DIFx) ツールの 64 ビット バージョンを提供します。DIFx ツールは、下記のものなどです。

Driver Package Installer (DPInst)。

Driver Installation Frameworks for Applications (DIFxApp)。

64 ビット プラットフォーム用に別々の 64 ビット インストーラーを作成する代わりに、単一の 32 ビット インストーラーから、DPInst または DIFxApp の正しいバージョンを起動できます。

32 ビット ドライバーのインストール パッケージを使用して、64 ビット ドライバーを直接インストールすることはできません。しかし、それらのパッケージを使用して、どのアーキテクチャが実行されているかを判定し、それから適切なインストーラーを起動することはできます。64 ビット プラットフォームで、32 ビット インストーラーは、WOW64 の下で動作します。WOW64 は、Win32 ベースのアプリケーションを 64 ビット Windows で実行できる、x64 エミュレータです。インストーラーは、プラットフォームに対して正しいドライバー パッケージをインストールできるよう、自身が動作しているプラットフォームを検出できる必要があります。

ページのトップへページのトップへ

64 ビット ドライバー開発のためのリソース

WDK の "64-bit Issues"

IA-64 システムと ACPI 2.0 64 ビット テーブル

Windows のメモリ管理の進歩

Beyond Windows XP: Get Ready Now for the Upcoming 64-Bit Version of Windows

KMDF ドライバーでの DMA サポート

WHDC Web サイトのハードウェア関連情報

64 ビット システムのための INF ファイルの要件

x64 ベース システムのパッチ ポリシー

Programming Guide for 64-bit Windows

メモリ管理: すべてのドライバー作成者が知る必要のある事項


ページのトップへページのトップへ