JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
デバイスドライバの記述     Oracle Solaris 10 8/11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

パート I Solaris プラットフォーム用デバイスドライバの設計

1.  Solaris デバイスドライバの概要

2.  Solaris カーネルとデバイスツリー

3.  マルチスレッド

4.  プロパティー

5.  イベントの管理とタスクのキュー

6.  ドライバの自動設定

7.  デバイスアクセス: プログラム式入出力

8.  割り込みハンドラ

9.  ダイレクトメモリーアクセス (DMA)

10.  デバイスメモリーおよびカーネルメモリーのマッピング

11.  デバイスコンテキスト管理

12.  電源管理

13.  Solaris ドライバの強化

14.  階層化ドライバインタフェース (LDI)

パート II 特定の種類のデバイスドライバの設計

15.  文字デバイスのドライバ

16.  ブロックデバイスのドライバ

17.  SCSI ターゲットドライバ

18.  SCSI ホストバスアダプタドライバ

19.  ネットワークデバイスのドライバ

20.  USB ドライバ

パート III デバイスドライバの構築

21.  ドライバのコンパイル、ロード、パッケージ化、およびテスト

22.  デバイスドライバのデバッグ、テスト、およびチューニング

ドライバのテスト

ハードハングを避けるためのデッドマン機能の有効化

シリアル接続を使用したテスト

tip 接続用にホストシステムを設定するには

SPARC プラットフォームのターゲットシステムの設定

x86 プラットフォーム上のターゲットシステムの設定

テストモジュールの設定

カーネル変数の設定

テストモジュールのロードとアンロード

kmem_flags デバッグフラグの設定

テストシステムでのデータ損失の回避

重要なシステムファイルをバックアップする

代替カーネルでブートするには

代替バックアップ計画の検討

システムクラッシュダンプの取得

デバイスディレクトリの復旧

デバッグツール

事後デバッグ

kmdb カーネルデバッガの使用

SPARC プラットフォームでの代替カーネルを使用した kmdb のブート

x86 プラットフォームでの代替カーネルを使用した kmdb のブート

kmdb でのブレークポイントの設定

ドライバ開発者向けの kmdb マクロ

mdb モジュラーデバッガの使用

モジュラーデバッガの使用開始

kmdbmdb を使用した便利なデバッグタスク

kmdb によるシステムレジスタの調査

カーネルメモリーリークの検出

mdb を使用したデバッガコマンドの記述

カーネルデータ構造体情報の取得

デバイスツリー情報の取得

ドライバのソフト状態情報の取得

カーネル変数の変更

ドライバのチューニング

カーネル統計

カーネル統計構造体のメンバー

カーネル統計構造体

カーネル統計関数

Solaris Ethernet ドライバのカーネル統計

動的計測を行うための DTrace

23.  推奨されるコーティング方法

パート IV 付録

A.  ハードウェアの概要

B.  Solaris DDI/DKI サービスの概要

C.  64 ビットデバイスドライバの準備

D.  コンソールフレームバッファードライバ

索引

ドライバのテスト

データ損失などの問題を避けるため、新しいデバイスドライバをテストするときには、特に注意を払うようにしてください。この節では、さまざまなテスト方針について説明します。たとえば、シリアル接続経由で制御可能な別個のシステムを設定するのが、新しいドライバをテストする場合にもっとも安全な方法です。さまざまなカーネル変数設定を含むテストモジュールをロードし、さまざまなカーネル条件の下でパフォーマンスをテストできます。システムがクラッシュした場合に備え、バックアップデータの復元、任意のクラッシュダンプの解析、およびデバイスディレクトリの再構築を行う準備を整えておくべきです。

ハードハングを避けるためのデッドマン機能の有効化

システムがハードハング状態に陥ると、デバッガを起動できなくなります。デッドマン機能を有効にすると、システムはいつまでもハングする代わりにパニック状態になります。その後、kmdb(1) カーネルデバッガを使用して問題の解析を行えます。

デッドマン機能は 1秒に一度、システムクロックが更新されているかどうかをチェックします。システムクロックが更新されていない場合、システムが無期限のハングに陥っていることになります。システムクロックが 50 秒間更新されないと、デッドマン機能によってパニックが引き起こされ、デバッガが起動されます。

デッドマン機能を有効化するには、次の手順に従います。

  1. クラッシュイメージの取得中であることを dumpadm(1M) で確認します。

  2. /etc/system ファイル内で snooping 変数を設定します。/etc/system ファイルについては、system(4) のマニュアルページを参照してください。

    set snooping=1
  3. /etc/system ファイルが再度読み取られて snooping 設定が有効になるように、システムをリブートします。

システム上のすべてのゾーンもデッドマン設定を継承します。

デッドマン機能が有効な状態でシステムがハングすると、次の例のような出力がコンソール上に表示されるはずです。

panic[cpu1]/thread=30018dd6cc0: deadman: timed out after 9 seconds of
clock inactivity

panic: entering debugger (continue to save dump)

デバッガの内部から ::cpuinfo コマンドを使用することで、クロック割り込みの発行に失敗してシステム時間を進めることができなかった原因を調査します。

シリアル接続を使用したテスト

ドライバをテストするときには、シリアル接続を使用することをお勧めします。ホストシステムとテストシステムの間でシリアル接続を確立するには、tip(1) コマンドを使用します。このアプローチでは、ホストコンソールの tip ウィンドウがテストマシンのコンソールとして使用されます。詳細については、tip(1) のマニュアルページを参照してください。

tip ウィンドウには次のような利点があります。


注 - Solaris デバイスドライバのデバッグに tip 接続や 2 台目のマシンが必須というわけではありませんが、それでもこの手法を使用することをお勧めします。


tip 接続用にホストシステムを設定するには

  1. ホストシステムとテストマシンとを、両マシン上のシリアルポート A を使用して接続します。

    この接続を行う際にはヌルモデムケーブルを使用する必要があります。

  2. ホストシステム上で、/etc/remote 内に接続用のエントリが存在していることを確認します。詳細は、remote(4) のマニュアルページを参照してください。

    この端末エントリは、使用するシリアルポートに一致している必要があります。シリアルポート B については、Solaris オペレーティングシステムに適切なエントリが含まれていますが、シリアルポート A については端末エントリを追加する必要があります。

    debug:\
            :dv=/dev/term/a:br#9600:el=^C^S^Q^U^D:ie=%$:oe=^D:

    注 - ボーレートは 9600 に設定する必要があります。


  3. ホストのシェルウィンドウで tip(1) を実行し、エントリの名前を指定します。
    % tip debug
    connected

    これによって、そのシェルウィンドウがテストマシンのコンソールへの接続を含む tip ウィンドウになります。


    注意

    注意 - テストマシンを停止するとき、ホストマシンが SPARC マシンの場合は STOP-A キーを、x86 アーキテクチャーマシンの場合は F1-A キーを、それぞれホストマシン上で使用しないでください。この操作を行うと、実際にはホストマシンが停止されます。テストマシンに BREAK 信号を送信するには、tip ウィンドウで ~# と入力します。~# などのコマンドが認識されるのは、それらの文字が行の先頭にある場合のみです。このコマンドで効果がない場合は、Return キーまたは Control-U キーを押してください。


SPARC プラットフォームのターゲットシステムの設定

SPARC プラットフォームのテストマシンを設定する簡単な方法は、マシンの電源を入れる前にキーボードを取り外すことです。これによって、マシンのシリアルポート A が自動的にコンソールとして使用されます。

テストマシンを設定するもう 1 つの方法は、ブート PROM コマンドを使用してシリアルポート A をコンソールにすることです。テストマシンのブート PROM の ok プロンプトで、コンソール入出力をシリアル回線に転送します。テストマシンの起動時に必ずシリアルポート A がコンソールとして使用されるようにするには、環境変数 input-deviceoutput-device を設定します。

例 22-1 ブート PROM コマンドによる input-deviceoutput-device の設定

ok setenv input-device ttya
ok setenv output-device ttya

eeprom コマンドを使用すると、シリアルポート A をコンソールにすることもできます。スーパーユーザーとして次のコマンドを実行することで、input-device および output-device パラメータがシリアルポート A を指すようにします。次に eeprom コマンドの例を示します。

例 22-2 eeprom コマンドによる input-deviceoutput-device の設定

# eeprom input-device=ttya
# eeprom output-device=ttya

この eeprom コマンドにより、その後システムがブートされるたびにコンソールがシリアルポート A にリダイレクトされます。

x86 プラットフォーム上のターゲットシステムの設定

x86 プラットフォームでは、eeprom コマンドを使用してシリアルポート A をコンソールにします。その手順は、SPARC プラットフォームの手順と同じです。「SPARC プラットフォームのターゲットシステムの設定」を参照してください。この eeprom コマンドにより、リブート中にコンソールがシリアルポート A (COM1) に切り替わります。


注 - x86 マシンでは、BIOS がシリアルポートへのコンソールリダイレクションをサポートしていないかぎり、ブート処理のある初期段階に達するまでコンソールの制御が tip 接続に移りません。SPARC マシンではブート処理の全体を通じて、tip 接続がコンソールの制御を維持します。


テストモジュールの設定

/etc ディレクトリ内の system(4) ファイルを使用すると、ブート時にカーネル変数の値を設定できます。カーネル変数を使用すると、ドライバの複数の動作を切り替えたり、カーネルが提供するデバッグ機能を活用したりできます。デバッグ時に非常に役立つ可能性のあるカーネル変数 moddebugkmem_flags については、この節で後述します。「ハードハングを避けるためのデッドマン機能の有効化」も参照してください。

ブート後のカーネル変数の変更は、信頼できません。/etc/system はカーネルのブート時に一度だけ読み取られるからです。このファイルを変更したあと、その変更を有効にするには、システムをリブートする必要があります。ファイルの変更後にシステムが機能しなくなった場合は、ask (-a) オプションを指定してブートします。その後、/dev/null をシステムファイルとして指定します。


注 - 将来のリリースでもカーネル変数が存在すると仮定することはできません。


カーネル変数の設定

set コマンドは、モジュール変数またはカーネル変数の値を変更します。モジュール変数を設定するには、次のようにモジュール名と変数を指定します。

set module_name:variable=value

たとえば、myTest という名前のドライバの変数 test_debug を設定するには、set を次のように使用します。

% set myTest:test_debug=1

カーネル自体によってエクスポートされた変数を設定する場合は、モジュール名を省略します。

値の設定には、ビット単位の論理和演算を使用することもできます。次に例を示します。

% set moddebug | 0x80000000

テストモジュールのロードとアンロード

コマンド modload(1M)modunload(1M)、および modinfo(1M) を使用するとテストモジュールを追加できます。これは、ドライバのデバッグや負荷テストを行うための便利な手法です。一般に、これらのコマンドは通常運用時には必要ありません。必要なモジュールのロードや未使用モジュールのアンロードは、カーネルが自動的に行うからです。情報の提供と制御の設定を行うため、moddebug カーネル変数はこれらのコマンドと連携して動作します。

modload() 関数の使用

あるモジュールを強制的にメモリー内にロードするには、modload(1M) を使用します。modload コマンドは、ドライバのロード時にそのドライバに未解決の参照が含まれていないことを確認します。ドライバのロードは必ずしも、そのドライバが接続可能であることを意味するわけではありません。ドライバのロードが成功すると、ドライバの _info(9E) エントリポイントが呼び出されます。attach() エントリポイントは、必ずしも呼び出されるわけではありません。

modinfo() 関数の使用

ドライバがロードされたことを確認するには、modinfo(1M) を使用します。

例 22-3 modinfo によるロード済みドライバの確認

$ modinfo
 Id Loadaddr   Size Info Rev Module Name
  6 101b6000    732   -   1  obpsym (OBP symbol callbacks)
  7 101b65bd  1acd0 226   1  rpcmod (RPC syscall)
  7 101b65bd  1acd0 226   1  rpcmod (32-bit RPC syscall)
  7 101b65bd  1acd0   1   1  rpcmod (rpc interface str mod)
  8 101ce8dd  74600   0   1  ip (IP STREAMS module)
  8 101ce8dd  74600   3   1  ip (IP STREAMS device)
...
$ modinfo | grep mydriver
169 781a8d78   13fb   0   1  mydriver (Test Driver 1.5)

info フィールドの番号は、そのドライバ用に選択されたメジャー番号です。モジュール ID を利用できる場合は、modunload(1M) コマンドを使用してモジュールをアンロードできます。モジュール ID は、modinfo 出力の左側の列に表示されます。

modunload の発行後に予期したとおりにドライバがアンロードされない場合がありますが、これはドライバがビジー状態であると判定されたためです。この状況が発生するのは、ドライバが実際にビジー状態であるか、または detach エントリポイントの実装が間違っているために、ドライバの detach(9E) が失敗した場合です。

modunload() の使用

現時点で使用されていないすべてのモジュールをメモリーから削除するには、モジュール ID に 0 を指定して modunload(1M) を実行します。

# modunload -i 0
moddebug カーネル変数の設定

moddebug カーネル変数は、モジュールのロード処理を制御します。moddebug の使用可能な値は次のとおりです。

0x80000000

モジュールのロードまたはアンロード時にコンソールにメッセージを出力します。

0x40000000

より詳しいエラーメッセージを提供します。

0x20000000

ロードまたはアンロード時に、アドレスやサイズを含めるなど、より詳しい情報を出力します。

0x00001000

ドライバの自動アンロードを行いません。システムリソースが少なくなっても、システムがデバイスドライバのアンロードを試みません。

0x00000080

ストリームの自動アンロードを行いません。システムリソースが少なくなっても、システムが STREAMS モジュールのアンロードを試みません。

0x00000010

すべてのタイプのカーネルモジュールの自動アンロードを行いません。

0x00000001

kmdb を使用して実行する場合、各モジュールの _init() ルーチンが呼び出される前に、moddebug によってブレークポイントが実行され、kmdb への復帰がただちに発生します。また、この設定ではモジュールの _info() および _fini() ルーチンの実行時に追加のデバッグメッセージが生成されます。

kmem_flags デバッグフラグの設定

kmem_flags カーネル変数は、カーネルのメモリーアロケータのデバッグ機能を有効化します。アロケータのデバッグ機能を有効化するには、kmem_flags0xf に設定します。これらの機能には、次のコード条件を検出するための実行時チェックが含まれます。

カーネルメモリーアロケータを使用してそのような問題を解析する方法については、『Solaris モジューラデバッガ』を参照してください。


注 - kmem_flags0xf に設定した状態でテストや開発を行うと、潜在的なメモリー破壊バグの検出が容易になる可能性があります。kmem_flags0xf に設定するとカーネルメモリーアロケータの内部動作が変化するため、kmem_flags を使用しない状態でも完全なテストを実施するべきです。


テストシステムでのデータ損失の回避

ドライバのバグにより、システムがブートできなくなる場合があります。この節で説明するように、予防策を実施しておくことで、このようなイベントが発生した場合でもシステムの再インストールを回避できます。

重要なシステムファイルをバックアップする

多数のドライバ関連システムファイルを再構築することは、不可能でないにしても非常に困難です。ドライバのインストール中にドライバが原因でシステムがクラッシュすると、/etc/name_to_major/etc/driver_aliases/etc/driver_classes/etc/minor_perm などのファイルが破壊される可能性があります。add_drv(1M) のマニュアルページを参照してください。

安全のため、テストマシンの設定が正しく完了したあとで、ルートファイルシステムのバックアップコピーを作成します。/etc/system ファイルの変更を予定している場合には、変更を実施する前にこのファイルのバックアップコピーを作成します。

代替カーネルでブートするには

システムが動作不能になるのを防ぐには、デフォルトカーネルからブートする代わりに、カーネルと関連バイナリのコピーからブートするべきです。

  1. /platform/* 内のドライバのコピーを作成します。
    # cp -r /platform/`uname -i`/kernel /platform/`uname -i`/kernel.test
  2. /platform/`uname -i`/kernel.test/drv 内にドライバモジュールを配置します。
  3. デフォルトカーネルの代わりに代替カーネルをブートします。

    代替カーネルの作成および格納が完了したら、このカーネルをさまざまな方法でブートできます。

    • 次のようにリブートすることで、代替カーネルをブートできます。

      # reboot -- kernel.test/unix
    • SPARC システムの場合、次のように PROM からブートすることもできます。

      ok boot kernel.test/sparcv9/unix

      注 - kmdb デバッガを使用してブートするには、「モジュラーデバッガの使用開始」で説明するように -k オプションを使用します。


    • x86 システムの場合、ブート処理で Select (b)oot or (i)nterpreter: メッセージが表示されたときに、次のように入力します。

      boot kernel.test/unix

例 22-4 代替カーネルのブート

次の例は、代替カーネルでのブート方法を示したものです。

ok boot kernel.test/sparcv9/unix
Rebooting with command: boot kernel.test/sparcv9/unix
Boot device: /sbus@1f,0/espdma@e,8400000/esp@e,8800000/sd@0,0:a File and \
    args:
kernel.test/sparcv9/unix

例 22-5 -a オプションを使用した代替カーネルのブート

ask (-a) オプションを指定してブートすることで、モジュールパスを変更することもできます。このオプションを指定すると、ブート方法を設定するための一連のプロンプトが表示されます。

ok boot -a
Rebooting with command: boot -a
Boot device: /sbus@1f,0/espdma@e,8400000/esp@e,8800000/sd@0,0:a File and \
args: -a
Enter filename [kernel/sparcv9/unix]: kernel.test/sparcv9/unix
Enter default directory for modules
[/platform/sun4u/kernel.test /kernel /usr/kernel]: <CR>
Name of system file [etc/system]: <CR>
SunOS Release 5.10 Version Generic 64-bit
Copyright 1983-2002 Sun Microsystems, Inc. All rights reserved.
root filesystem type [ufs]: <CR>
Enter physical name of root device
[/sbus@1f,0/espdma@e,8400000/esp@e,8800000/sd@0,0:a]: <CR>

代替バックアップ計画の検討

システムがネットワークに接続されている場合、テストマシンをサーバーのクライアントとして追加できます。問題が発生した場合には、ネットワークからシステムをブートできます。その後、ローカルディスクをマウントして任意の修正を行えます。Solaris システムの CD-ROM から直接システムをブートすることもできます。

障害から復旧するためのもう 1 つの方法は、別のブート可能なルートファイルシステムを用意することです。format(1M) を使用して、元のパーティションとまったく同じサイズのパーティションを作成します。次に、dd(1M) を使用して、そのブート可能なルートファイルシステムをコピーします。コピーの完了後、新しいファイルシステムに対して fsck(1m) を実行し、その整合性を確認します。

その後、元のルートパーティションからシステムをブートできなくなったら、バックアップパーティションをブートします。dd(1M) を使用してバックアップパーティションを元のパーティションにコピーします。ルートファイルシステムが破損していないにもかかわらず、システムをブートできないような状況が発生する可能性もあります。たとえば、破損箇所がブートブロックやブートプログラムに限定されていることがあります。そのような場合は、ask (-a) オプションを使用してバックアップパーティションからブートできます。その後、元のファイルシステムをルートファイルシステムとして指定できます。

システムクラッシュダンプの取得

システムがパニック状態になると、システムはカーネルメモリーのイメージをダンプデバイスに書き込みます。デフォルトでは、もっとも適したスワップデバイスがダンプデバイスになります。このダンプはシステムのクラッシュダンプであり、アプリケーションによって生成されるコアダンプに似ています。パニックが発生したあとのリブート時に、savecore(1M) はダンプデバイス内でクラッシュダンプの存在の有無をチェックします。ダンプが見つかった場合、savecore は、unix.n という名前のカーネルシンボルテーブルのコピーを作成します。次に savecore ユーティリティーは、vmcore.n という名前のコアファイルをコアイメージディレクトリ内にダンプします。デフォルトでは、コアイメージディレクトリは /var/crash/machine_name になります。/var/crash の容量不足によりコアダンプを格納できない場合には、システムによって必要な容量が表示されるものの、実際のダンプの保存が行われません。その後、コアダンプや保存済みカーネルに対して mdb(1) デバッガを使用できます。

Solaris オペレーティングシステムでは、クラッシュダンプはデフォルトで有効になっています。dumpadm(1M) コマンドは、システムクラッシュダンプを設定するために使用されます。dumpadm コマンドを使用すると、クラッシュダンプが有効になっていることを確認したり、保存されたコアファイルの場所を特定したりできます。


注 - savecore ユーティリティーがファイルシステムをいっぱいにしてしまうのを防ぐことができます。minfree という名前のファイルを、ダンプの保存先となるディレクトリに追加します。savecore の実行後に空き領域として残すキロバイト数を、このファイル内に指定します。十分な容量を確保できない場合、コアファイルは保存されません。


デバイスディレクトリの復旧

attach(9E) の実行中にドライバがクラッシュすると、/devices および /dev ディレクトリが破損する可能性があります。いずれかのディレクトリが破損した場合にそのディレクトリを再構築するには、システムをブートし、fsck(1m) を実行して破損したルートファイルシステムを修復します。これによって、ルートファイルシステムをマウントできるようになります。/devices および /dev ディレクトリを作成し直すには、devfsadm(1M) を実行し、マウントされたディスク上で /devices ディレクトリを指定します。

次の例は、SPARC システム上の破損したルートファイルシステムを修復する方法を示しています。この例で、破損したディスクは /dev/dsk/c0t3d0s0、代替ブートディスクは /dev/dsk/c0t1d0s0 になっています。

例 22-6 破損したデバイスディレクトリの復旧

ok boot disk1
...
Rebooting with command: boot kernel.test/sparcv9/unix
Boot device: /sbus@1f,0/espdma@e,8400000/esp@e,8800000/sd@31,0:a File and \
    args:
kernel.test/sparcv9/unix
...
# fsck /dev/dsk/c0t3d0s0** /dev/dsk/c0t3d0s0
** Last Mounted on /
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3 - Check Connectivity
** Phase 4 - Check Reference Counts
** Phase 5 - Check Cyl groups
1478 files, 9922 used, 29261 free
     (141 frags, 3640 blocks, 0.4% fragmentation)
# mount /dev/dsk/c0t3d0s0 /mnt
# devfsadm -r /mnt

注 - /devices および /dev ディレクトリを修正すると、システムのほかの部分が壊れたままでも、システムをブートできる可能性があります。そのような修復は、システムを再インストールする前にシステムクラッシュダンプなどの情報を保存するための一時的な修正にすぎません。