このチェックリストは、64 ビット エディションの Windows オペレーティング システムで実行されるドライバーを作成する開発者用の、コーディングとインストールに関する懸念点の簡単な一覧です。
この情報は、下記のオペレーティング システムに適用されます。
Microsoft Windows Vista
Microsoft Windows Server 2008
64 ビット エディションの Microsoft Windows Server 2003
Microsoft Windows XP
| 64 ビット Windows 用のドライバー: はじめに | |
| 64 ビット Windows プログラミング モデル | |
| コーディング ガイドラインと移植に関する問題 | |
| 64 ビット Windows でのドライバーのインストール | |
| 64 ビット ドライバー開発のためのリソース |
64 ビット システムの採用は、特にエンタープライズの領域で、速やかに進む見込みです。64 ビット システム用に広範なデバイスがカバーされ、高品質のドライバーが利用可能になるにつれ、この採用はいっそう速く進むでしょう。
自社のデバイスで 64 ビット システムのサポートを開始するには:
| • | デバイスが 64 ビットの物理メモリをアドレス指定することを確認します。 | ||||||
| • | 64 ビット セーフなプログラミング方法で Microsoft Windows ドライバーをコーディングし、64 ビット コンパイラを使用して、問題領域を見つけます。
|
32 ビット ドライバーをサポートしていない点に注意してください。
| • | カーネル モード ドライバーは、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 Vista およびそれ以前の物理メモリの 40%、最大 128 GB まで: |
物理メモリ アドレス | 64 ビット | 64 ビット |
コーディング ガイドライン
| • | Windows 64 ビットおよび 32 ビットのセーフ データ型を使用します。 |
| • | すべてのポインターの使用、特にポインターの計算を検査します。 |
| • | インライン アセンブリ コードを削除します (組み込みまたはネイティブ アセンブリ コードを使用します)。 |
| • | x64 固有のコードの場合: |
| • | Itanium 固有のコードの場合: |
ドライバーの移植に関する問題
| • | ドライバーは、IOCTL コマンドの 32 ビットと 64 ビット バージョンをサポートする必要があります。 | ||||||||
| • | DMA サポートは、32 ビットの物理アドレスのみをアドレスできるハードウェア用に実装される必要があります。 | ||||||||
| • | ポインター、多形使用、および配置の問題は、すべてのドライバーに該当します。 | ||||||||
| • | すべてのドライバーは、プラグ アンド プレイと電源の管理を適切にサポートする必要があります。
| ||||||||
| • | 64 ビット ミニポートの場合:
|
ビルド環境とツール
| • | x64 用のビルド環境は、AMD64 です。 | ||||||||
| • | 64 ビット ツールと開発プロセスは、32 ビットと類似しています。
|
BIOS、ACPI、および修正に関するメモ
| • | Itanium ベースのシステムは、ACPI 2.0 64 ビット テーブルをサポートする必要があります。 | ||||||||||
| • | GUID パーティション テーブル (GPT) ディスクは、64 ビット Windows によってサポートされます。 | ||||||||||
| • | BIOS コールバックは、x64 システム上で許容されません。 | ||||||||||
| • | x64 ベースのシステム用 Windows との互換性のため、ドライバーは下記の行為を避ける必要があります。
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() を使用して、ポインターを切り捨てます。
| ||||
| • | ポインター 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;
}
|
配置の詳細については、"メモリ管理: すべてのドライバー作成者が知る必要のある事項"を参照してください。
コーディングに関する他の問題
| • | 下記の点を、注意して調べてください。
| ||||||||
| • | 実行ハンドルを 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 進の定数と符号なしの値は、注意して使用します。 | ||||||||
| • | 符号なしの数値を下付き文字として使用する場合、注意します。
|
その他のクリーンアップ
| • | -1 != 0xFFFFFFFF 0xFFFFFFFF != 無効なハンドル |
| • | DWORD は常に 32 ビットです。DWORD の変数を使用して、ポインターまたはハンドルを格納しないでください。 |
| • | ポインターを PCHAR にキャストして、ポインターを計算してください。 ptr = (PVOID)((PCHAR)ptr + pageSize); |
| • | %I を使用して、デバッグ ステートメントにポインターを出力します。 |
| • | Addresses >= 0x80000000 は、必ずしもカーネル アドレスではありません。 |
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 エミュレータです。インストーラーは、プラットフォームに対して正しいドライバー パッケージをインストールできるよう、自身が動作しているプラットフォームを検出できる必要があります。
| • | |
| • | |
| • | |
| • | Beyond Windows XP: Get Ready Now for the Upcoming 64-Bit Version of Windows |
| • | |
| • | |
| • | |
| • | |
| • | |
| • |