64 ビット Microsoft Windows ドライバー用のチェックリスト
最終更新日: 2008年 7月 15日
このチェックリストは、64 ビット エディションの Windows オペレーティング システムで実行されるドライバーを作成する開発者用の、コーディングとインストールに関する懸念点の簡単な一覧です。
この情報は、下記のオペレーティング システムに適用されます。
Windows Vista
Windows Server 2008
64 ビット エディションの Windows Server 2003
Windows XP
目次
64 ビット Windows 用のドライバー: はじめに
64 ビット Windows プログラミング モデル
コーディング ガイドラインと移植に関する問題
64 ビット Windows でのドライバーのインストール
64 ビット ドライバー開発のためのリソース
64 ビット Windows 用のドライバー: はじめに
64 ビット システムの採用は、特にエンタープライズの領域で、速やかに進む見込みです。64 ビット システム用に広範なデバイスがカバーされ、高品質のドライバーが利用可能になるにつれ、この採用はいっそう速く進むでしょう。
自社のデバイスで 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 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 の問題は、ほとんどのミニポートに該当しません。
ビルド環境とツール
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() を使用して、ポインターを切り捨てます。
ポインター 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; }
配置の詳細については、"メモリ管理: すべてのドライバー作成者が知る必要のある事項"を参照してください。
コーディングに関する他の問題
その他のクリーンアップ
-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 は動作します。
ユーザーは各プラットフォームの違いを理解していないため、目標は、誤ったドライバー バイナリのインストールを防ぐことにあります。
32 ビットおよび 64 ビット プラットフォーム用のドライバーのインストール
32 ビット インストーラーから 64 ビット ドライバーをインストールするのを簡略化するため、Microsoft は、WDK で Driver Install Frameworks (DIFx) ツールの 64 ビット バージョンを提供します。DIFx ツールは、下記のものなどです。
64 ビット プラットフォーム用に別々の 64 ビット インストーラーを作成する代わりに、単一の 32 ビット インストーラーから、DPInst または DIFxApp の正しいバージョンを起動できます。
32 ビット ドライバーのインストール パッケージを使用して、64 ビット ドライバーを直接インストールすることはできません。しかし、それらのパッケージを使用して、どのアーキテクチャが実行されているかを判定し、それから適切なインストーラーを起動することはできます。64 ビット プラットフォームで、32 ビット インストーラーは、WOW64 の下で動作します。WOW64 は、Win32 ベースのアプリケーションを 64 ビット Windows で実行できる、x64 エミュレータです。インストーラーは、プラットフォームに対して正しいドライバー パッケージをインストールできるよう、自身が動作しているプラットフォームを検出できる必要があります。
64 ビット ドライバー開発のためのリソース