9 月 25

ObjectSign がようやく届きました♪

早速 x64 用ドライバに署名をしてみたのですが、Vista x64 で試してみると無効な署名扱いでドライバを読み込めませんでした。ファイルのプロパティからはちゃんとデジタル署名を確認できるのですが。う~む。

実行ファイルに署名することで、発行元が「不明な発行元」から今回とった署名の名前に変化しているので、一応証明書はちゃんとしているっぽいです。

もう少し調査した上で質問メールかな・・・。にしても、証明書発行まで1ヶ月もかかるとは。

そんなわけなので、WinRing0 1.0 のリリースはデジタル署名関連の問題が解決するまで延期とさせていただきます。

※以下 2007/9/25 23:10 追記 

を見落としていました。普通のアプリなどとは異なりクロス証明書が必須とのことでした。具体的な署名方法は、Signing a Catalog File With an SPC で紹介されております。

9 月 23

WinRing0 正式版リリースに向けてマニュアルの chm 形式化を準備中…

9 月 22

昨晩ふと思い立ち Crystal Dew World の歴史をまとめてみました。既に公開を終了したソフトたちに付属していたリリースノートを読み返しながら、懐かしんでおりました。

学部生時代に漠然と考えていた(と思う)目標のほとんどを達成したんだなぁ~とシミジミ。残念ながら CrystalMark も CrystalCPUID も世界一にはなれませんでしたが、自分の作りたいものを具現化できるだけのスキルを学生時代に身につけることができたのは本当に幸せなことだと感じています。そして、社会人になってからも情熱が尽きることなく新しいプロジェクトに取り組み続けていることを誇りに思います。

振り返ってみると社会人になってから丸々 3 年間新作を全く出せなかったわけですが、今年は、CrystalDiskMark をリリースし、数年間温め続けてきた OpenLibSys プロジェクトをついに具現化することができ、ようやく「新しい何かを」生み出す力を取り戻すことができたのではないかと思います。

来年は10周年だしなにか記念になるソフトをリリースしたいところです。まぁ、CrystalMark 1.0 をリリースするのが一番なんですが・・・。

9 月 20

…某所へ投稿するための原稿作成中… 

はじめに

.NET Framework や Web アプリケーションの台頭など、プログラミングをする上で「ハードウェア」を意識する機会は以前ほど多くはないと思いますが、CPU やチップセットなどの設定変更などハードウェアに近い部分に興味のある方は少なくないのではないでしょうか。

しかし、ハードウェアへのアクセスは Ring3* で動作する一般的なアプリケーションからは行うことができず、基本的に Ring0* で動作するデバイスドライバを経由して行う必要があるため、決してハードルが低いとは言えませんでした。

*Ring0/Ring3 とは CPU の動作モードのことで、OS やデバイスドライバなどは CPU が持つ全ての命令が使用できる Ring0 で動作し、アプリケーションは使用できる命令が制限された Ring3 で動作します。興味のある方は検索エンジンなどで調べてみてください。

本稿では、Visual C# と拙作 WinRing0 を使ったハードウェアアクセスプログラミングを紹介させていただきます。

WinRing0 について

WinRing0 は私が開発した DLL とデバイスドライバで構成された Windows 用のハードウェアアクセスライブラリです。IO ポートや MSR、PCI バス、物理メモリなどにアクセスするための機能を提供します。機能の詳細は マニュアル をご覧ください。また、本ライブラリは修正 BSD ライセンスで公開しているため、どなたでも自由に利用することが可能です。

対象読者

  • IO ポート、MSR、PCI デバイス、物理メモリへのアクセスに興味のある方
  • .NET からの CPUID 命令実行に興味のある方

必要な環境

  • Visual C# 2005 Express Edition 以降
    ※Visual C# 2008 Express Edition Beta 2 で動作確認済み
  • 実行環境としては
    [x86] Windows Vista/XP/2000/(NT4)/(Me)/(98)
    [x64] Windows Vista**/XP
    **Vista ではデジタル署名の強制を無効にする必要があります。詳細

WinRing0 導入の流れ 

  1. 実行ファイルの出力フォルダに DLL とデバイスドライバをコピーします。
    (WinRing0.dll, WinRing0×64.dll, OpenLibSys.sys, OpenLibSysX64.sys, OpenLibSysNT4.sys, OpenLibSys.vxd) 
  2. OpenLibSys.cs をプロジェクトに加えます。
  3. using OpenLibSys; 文をソースコードに加えます。

WinRing0 の初期化

  • Ols クラスのインスタンスを生成し、GetDllStatus() により、DLL が正しく初期化されたかどうかを確認します。デバイスドライバの読み込みに成功し初期化が完了した場合は、OLS_DLL_NO_ERROR が、管理者権限がない場合やネットワークドライブから実行するなどしてデバイスドライバが読み込めない場合は OLS_DLL_DRIVER_NOT_LOADED が返ります。正常に初期化が完了しなかった場合はアプリケーションを終了します。
  • なお、RunAsRestart() は Vista で導入された UAC 対策用関数で、権限昇格のダイアログを表示するようにしてアプリケーションを再起動します。

Ols ols = new Ols();
switch (ols.GetDllStatus())
{
  case (uint)Ols.OlsDllStatus.OLS_DLL_NO_ERROR:
      break;
  case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_LOADED:
  if (RunAsRestart() == false)
  {
      MessageBox.Show("DLL Status Error!! DRIVER_NOT_LOADED");
  }
      Application.Exit();
      break;
  case (uint)Ols.OlsDllStatus.OLS_DLL_UNSUPPORTED_PLATFORM:
  case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_NOT_FOUND:
  case (uint)Ols.OlsDllStatus.OLS_DLL_DRIVER_UNLOADED:
  case (uint)Ols.OlsDllStatus.OLS_DLL_UNKNOWN_ERROR:
      Application.Exit();
      break;
}

1. MSR の読み込み

初期化も完了したので早速 Ring0 でなければ実行できない MSR の読み込みに挑戦してみましょう。今回は、多くの CPU で実装されている MSR インデックス 0×10 の Time Stamp Counter の読み込みを行います。

RdmsrEx API は 第1引数に MSR インデックス、第2引数および第3引数に結果を格納するための変数(参照渡し)、第4引数に実行するプロセッサを特定するためのスレッドアフィニティマスク(Thread Affinity Mask)を設定します。

uint index = 0, eax = 0, ebx = 0, ecx = 0, edx = 0;
str += "[MSR]\r\n”;
str += “index 63-32 31-0\r\n”;
index = 0×00000010; // Time Stamp Counter
ols.RdmsrEx(index, ref eax, ref edx, (UIntPtr)1);
str += index.ToString(”X8″) + “: ” + edx.ToString(”X8″)
    + ” ” + eax.ToString(”X8″) + “\r\n”;

2. IO ポートアクセス
次に、ReadIoPortByte, WriteIoPortByte を用いた IO ポートアクセスに挑戦してみます。ここでは例としてビープで 440Hz の音を鳴らしてみることにします。※環境によっては、音が鳴らない場合があります。

uint freq = 1193180000 / 440000; // 440Hz
ols.WriteIoPortByte(0x43, 0xB6);
ols.WriteIoPortByte(0x42, (byte)(freq & 0xFF));
ols.WriteIoPortByte(0x42, (byte)(freq >> 9));
System.Threading.Thread.Sleep(100);
ols.WriteIoPortByte(0x61, (byte)(ols.ReadIoPortByte(0x61) | 0x03));
System.Threading.Thread.Sleep(1000);
ols.WriteIoPortByte(0x61, (byte)(ols.ReadIoPortByte(0x61) & 0xFC));
str += "[IO]\r\nBeep 440Hz\r\n”;

3. 物理メモリの読み込み
ReadMemBlock を使用して物理メモリの内容を用意したバッファに読み込みます。ここでは、一例として BIOS 内に含まれる SM BIOS (System Management BIOS) 構造体を探し出し、SM BIOS のバージョン情報を表示します。SM BIOS に関する詳細は、拙作 CrystalDMI および DMTF “System Management BIOS Reference Specification” をご覧ください。

const uint MAP_MEMORY_SIZE = 64 * 1024;
byte[] buf = new byte[MAP_MEMORY_SIZE];
byte[] sm = new byte[4];
sm[0] = 0×5F; // ‘_’
sm[1] = 0×53; // ‘S’
sm[2] = 0×4D; // ‘M’
sm[3] = 0×5F; // ‘_’

str += “[MEMORY]\r\n”;

fixed (byte* p = &buf[0], s = &sm[0])
{
    if (ols.ReadMemBlock((UIntPtr)0×000F0000, p, MAP_MEMORY_SIZE, 1) == MAP_MEMORY_SIZE)
    {
        for (uint j = 0; j < MAP_MEMORY_SIZE; j += 16)
        {
            if (memcmp(p + j, s, 4) == 0)
            {
                str += “SM BIOS Version : ”
                    + ((byte)(p[6 + j])).ToString(”D”)
                    + “.” + ((byte)(p[7 + j])).ToString(”D”);
                break;
            }
        }
    }
}
str += “\r\n”;

 4. PCI デバイスのリストアップ


uint address, value;
str += "[PCI]\r\n”;
// All Device
str += “Bus Dev Fnc VendorDevice\r\n”;
for (uint bus = 0; bus < 256; bus++)
{
    for (uint dev = 0; dev < 32; dev++)
    {
        for (uint func = 0; func < 8; func++)
        {
            address = ols.PciBusDevFunc(bus, dev, func);
            value = ols.ReadPciConfigDword(address, 0×00);
            if ((value & 0xFFFF) != 0xFFFF && (value & 0xFFFF) != 0×0000)
            {
                str += ols.PciGetBus(address).ToString(”X2″) + “h ”
                    +  ols.PciGetDev(address).ToString(”X2″) + “h ”
                    +  ols.PciGetFunc(address).ToString(”X2″) + “h ”
                    +  ((uint)(value & 0×0000FFFF)).ToString(”X04″) + “h ”
                    +  ((uint)((value >> 16) & 0×0000FFFF)).ToString(”X04″) + “h\r\n”;
            }
        }
    }
}

続く…

9 月 19

PCI Configuration Space を Dump する機能を C# で書いてみました。当然ですが、簡単です。すごいぞ!! WinRing0 と自画自賛。WinRing0 RC5 のサンプルにはこの機能を搭載と。

pciconfigspace.png

いまさらですが、int な数字もオブジェクトとして扱える C# はホント革命的ですよ。って、何年前の人のコメントだ(笑) CrystalCPUID と CrystalMark の次のバージョンは MFC + CDHtmlDialog で書きますが、他のちょっとしたツールは C# でサクサク書いた方が良いのかも。Express Edition でもビルド出来ますし。

9 月 17

ソースコードの整理と API の最終調整を行いました。 

来週末に最終的な確認を行い、今月中に正式版をリリースいたします。正式版リリース後は基本的に仕様変更を行えませんので、ご意見ご要望は今週中に頂きたいと思います。

主な修正点

  • IO/PCI 関連 API の引数を適切な型に(一部)変更 
    ※詳細はマニュアルをご覧ください。
  • デバイスドライバ(9x/NT)のブラッシュアップ
  • マニュアル更新

◇ダウンロード:WinRing0 RC4

9 月 17

WinRing0 仕様変更します。と言っても、適切なサイズに引数を変更するだけですが。

昨日、一昨日と sys と vxd のソースコードにかなり手を入れたので、SysInfo 時代と比べるとずっと見通しが良くなっています。デバイスドライバは一度確定すると基本的にいじる必要がないのですが、やはり見通しが良いと気持ちが良いものです。

WinRing0 RC4 は今晩リリース予定です。

9 月 16

VxD のビルド方法を思い出すのに、とてつもなく苦労したのでマニュアルにビルド方法のページを追加しました。ビルド方法と言っても exe/dll についてはほとんど触れず、ドライバのビルド方法がメインです。

ビルド方法

これで、数年後デバイスドライバの修正が必要になったときもバッチリ対応できます。ところで、現時点で WDK と Windows Server 2003 SP1 DDK は無償ダウンロードが可能ですが、Win9x に対応した古い DDK は既にダウンロードできなくなっています。VxD の修正が必要な場合は、MSDN に加入して Windows XP SP1 DDK をダウンロードする必要があります。

この手の開発キットはいつまでダウンロードできるか分からないので、しっかり保存しておく必要がありそうです。

9 月 16
  • AMD Phenom Family への暫定対応
  • Intel Core 2 Duo (Merom) を誤判定する不具合を修正
  • VIA C7 (Esther/Model=0xD) に対応
  • データベース更新

久しぶりの更新です。報告を受けている不具合は色々あるのですが、とりあえず簡単に対応できるものだけ・・・。

9 月 15

いやぁ~あれやこれやとバグがたくさん見つかったので 、結構大変でした。今回は、x64 環境への対応強化と念願?の Win98/Me 対応を行いました。

いまさら Win98/Me のサポートもなぁ~と思いかなり悩んだのですが、結局作ってしまいました(汗 まぁ、ないよりはあった方が良いでしょうしね。残念ながら VC8 でビルドしている関係で Win95 では動作いたしません。VxD 自体は 95 に対応しているはずですが・・・。

連休最終日には、RC4 をリリースしたいと思います。VxD を中心にまだまだバグがあるような気がするので時間をおいて精査したいと考えております。

マニュアルにも明記しておりますが、デバイスドライバは必ず実行ファイルと同じディレクトリに入れておく必要があります。ご注意ください。

主な修正点

  • Win 98/Me 用 VxD 搭載!!(ファイル名は OpenLS.vxd となっております。)
  • 物理メモリアクセスの制限を解消(x64 版では 32bit 以降もアクセスできるようになりました。)
  • マニュアル更新
  • NT 用ドライバ内の冗長なコードを削除 
  • サンプルプログラム更新
  • ソースコードのディレクトリ構成変更(sysとvxdはdllの配下に格納されています) 
  • ドライバファイルが存在しないに場合、OLS_DLL_DRIVER_NOT_FOUND を返すように修正(今までは、ファイルの存在確認を行っていなかったため OLS_DLL_DRIVER_NOT_LOADED を返していました)

サンプルプログラム C++ 版について

  • Rdtsc の結果表示機能を追加
  • RunAsRestart を OLS_DLL_DRIVER_NOT_LOADED が返ってきた時のみ実行するよう変更

サンプルプログラム C# 版について

  • RunAsRestart を OLS_DLL_DRIVER_NOT_LOADED が返ってきた時のみ実行するよう変更
  • OpenLibSys.cs 内で GetDriverVersion ではなく誤って GetDllVersion を呼び出すようになっていた不具合を修正

◇ダウンロード:WinRing0 RC3

※VxD のソースコードは現在ブラッシュアップ中のため含まれておりません。RC4 以降では同梱予定です。