64ビットへのいざない
こんにちは、なおきお~です。
皆さんは、職場や自宅では、どのWindows OSを使用されていますでしょうか?
先日、知人から64ビットのWindows OSは、アプリケーションの互換性が心配だし、デバイス ドライバがあるかどうかわからないので、敷居が高いと言われました。
Windows Vistaのリリース直後に64ビットに移行してしまった私としては、既に気にならないのですが、移行するときは、アプリケーションの互換性やデバイス ドライバの有無は、少なからず心配になりましたので、知人の心配も尤だと思います。
デバイス ドライバを開発されている方の立場からすると、過去に開発したデバイス ドライバの互換性が気になると思いますし、最近では、Windows 7のリリースされるのが、気になるのではないかと思います。また、Windows 7だけでなく、Windows Server 2008 R2もリリースされると思います。
特に、Windows Server 2008 R2 は、32ビット版は提供されず、64ビット版のみになり、サーバーの Windows OS は、完全に64ビットになります。
対して、ノートPCもデスクトップPCも、4GB以上のメモリを搭載PCが増えてきて、クライアント側も、ひしひしと64ビット化を感じます。
ユーザ モードのアプリケーションは、WOW64 (Windows 32-bit on Windows 64-bit ) という機能のおかげで、32ビットでも動作します。
しかしながら、デバイス ドライバは、64ビット版のWindows OS では、ユーザ モードやカーネル モードに関わらず、64ビットである必要があります。
64ビット化が近づきながらも、32ビット版のWindows OS も、まだまだ現役という現状は、32ビットと64ビットのデバイス ドライバを開発する必要があると思います。
2つもデバイス ドライバを開発しなければいけないのか!と思われるかもしれませんが、開発自体は、そんなに大変ではありません。
何故ならば、ほぼソース コードレベルで互換が可能であるということです。つまり、x86・x64・ia64 それぞれのBuild Environmentでbuildすれば、ほとんど終了してしまうのです。
しかし、ソース コード レベルで互換が可能ということは、過去に開発した全ての32ビットのデバイス ドライバに対して、ソース コード レベルで互換性を保証しているわけではありません。意識して、コーディングすれば、ソース コード レベルの互換が可能ということです。また、100%のソース コードの互換ではなく、若干 考慮しなければいけないところもあります。
とはいっても、ソース コードの互換が可能なぐらいの差異なので、過去に開発した32ビットのデバイス ドライバも比較的 容易に移行できるのではないかと思います。
まず、よく使用するデータ型は、このようになっており、ポインター型は、全て64ビット長になります。
データ型 |
ビット数 |
LONG, INT |
32 ビット符号付き |
ULONG,UINT,DWORD |
32 ビット符号なし |
LONG32, INT32 |
32 ビット符号付き |
LONG64, INT64 |
64 ビット符号付き |
ULONG32,UINT32,DWORD32 |
32 ビット符号なし |
ULONG64,UINT64,DWORD64 |
64 ビット符号なし |
データ型で、よくある問題として、-1を0xFFFFFFFFとコーディングしたり、0x80000000以上のアドレスは、カーネル アドレスと判定するなど、32ビット長に依存しているコーディングです。
こういったのは、-1にするなど、ビット長に依存しないようにコーディングするか、ヘッダ ファイルに定数を定義するなどの工夫が必要になります。
また、定数を定義する場合に、_WIN64や_IA64_や_AMD64_ を使用すると、Build Environmentで適切に定義してくれるので便利だと思います。
なお、このようなコーディングは、デバイス ドライバのみならず、ユーザ アプリケーションでも必要な一般的な考慮点で、ユーザ モードのデバイス ドライバは、このような一般的な考慮点のみで、ほぼ64ビットに移行できると思います。
強いて言えば、プリンタ ドライバの場合、32ビットのユーザ アプリケーションから呼び出される場合、SPLWOW64.EXE経由で呼び出されるため、プロセス空間が、ユーザ アプリケーションではない点です。ただ、通常 プリンタ ドライバは、動作するプロセス空間を認識する必要がないので、問題にならないと思いますが、もし、何らかの事情で、プロセスを意識しているコードがあったとしたら、変更が必要かもしれません。
対してまして、カーネル モードのデバイス ドライバの代表的な考慮点は、32ビットのユーザ アプリケーションから、DeviceIoControl()が呼ばれる場合の実装だと思います。
DeviceIoControl()で指定するInputBufferやOutputBufferの構造体は、IOCTLに依存します。IOCTLが、デバイス ドライバが管理していると同様に、InputBufferやOutputBufferの構造体も管理する必要があります。そのため、32ビットのユーザ アプリケーションから、DeviceIoControl()が呼ばれたら、32ビット用の構造体に変更する必要があります。
WDKのサンプル コード(%BASEDIR%\src\ src\storage\class\classpnp\class.c)にわかりやすい例があるので、そのコードを抜粋してみます。
ClassDeviceControl()という関数で、IOCTL_SCSI_PASS_THROUGHとIOCTL_SCSI_PASS_THROUGH_DIRECTというIOCTLのハンドリングをしています。
_WIN64 の場合のみ、32ビットのプロセスから呼ばれたかどうかをIoIs32bitProcess() という関数で確認しています。もし、32ビットのプロセスから呼ばれたのであれば、SCSI_PASS_THROUGH32という構造体でサイズチェックをしています。
---------- 抜粋 ----------
#if defined (_WIN64)
if (IoIs32bitProcess(Irp)) {
if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH32)){
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
status = STATUS_INVALID_PARAMETER;
goto SetStatusAndReturn;
}
}
else
#endif
{
if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SCSI_PASS_THROUGH)) {
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
ClassReleaseRemoveLock(DeviceObject, Irp);
ClassCompleteRequest(DeviceObject, Irp, IO_NO_INCREMENT);
status = STATUS_INVALID_PARAMETER;
goto SetStatusAndReturn;
}
}
---------- 抜粋 ----------
build するだけで、終了すると書きましたが、実際に本格的な64ビット化する場合は、ソース コードをちょっと変更してre-build するだけでなく、テストをしたり、ドライバ署名をしたりと色々と必要になるので、軽い気持ちで、64ビット化することはできないと思いますが、将来的な64ビット化に備えて、過去に開発したデバイス ドライバや現在 開発しているデバイス ドライバを64ビットのBuild Environmentでre-buildしてみたり、ソース コードを調整してみたり、少しずつ準備をされるとよいと思います。
なお、細かなチェックリストは、WHDC のサイトに公開されているので、本格的な移行際には、このチェックリストを活用していただくのがいいと思います。
64 ビット Microsoft Windows ドライバー用のチェックリスト
https://www.microsoft.com/japan/whdc/driver/kernel/64bit_chklist.mspx
ちなみに、64ビットのDumpファイルの調査は、少々厄介かもしれません。なにせ、引数がレジスタ渡しになってしまったので、32ビットのようにお気軽に引数を確認することができません。ETWトレースなど、他のトラブルシューティングの方法を充実させなければいけないかもしれません。
トラブルシューティングについては、いずれ紹介したいと思います。
それでは、また~