ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
ユーザーアクセス用にエクスポートされたカーネルメモリーの解放
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
このセクションでは、segmap(9E) および devmap(9E) エントリポイントの使用方法について説明します。
segmap(9E) エントリポイントは、mmap(2) システムコールからリクエストされたメモリーマッピングを設定する役割を担います。多くのメモリーマッピングデバイスに対応するドライバは、独自の segmap(9E) ルーチンを定義する代わりに、ddi_devmap_segmap(9F) をエントリポイントとして使用します。ドライバは、segmap() エントリポイントを提供することにより、マッピング作成の前後で一般的なタスクを処理できます。たとえば、ドライバ内でマッピング許可を確認し、非公開のマッピングリソースを割り当てることができます。また、ドライバ内でマッピングを調整し、ページ境界割り当てされていないデバイスバッファーに対応させることもできます。segmap() エントリポイントは、戻り値を返す前に ddi_devmap_segmap(9F) 関数を呼び出す必要があります。ddi_devmap_segmap() 関数は、ドライバの devmap(9E) エントリポイントを呼び出すことで実際のマッピングを実行します。
segmap() 関数の構文は次のとおりです。
int segmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp);
各表記の意味は次のとおりです。
マップするメモリーを含むデバイス。
マッピングの開始位置となる、デバイスメモリー内のオフセット。
デバイスメモリーのマッピング先となるアドレス空間へのポインタ。
この引数には、例 10-1 に示した struct as *、例 10-2 に示した ddi_as_handle_t のどちらを指定してもかまいません。これは、ddidevmap.h に次の宣言が含まれているからです。
typedef struct as *ddi_as_handle_t
デバイスメモリーのマッピング先となる、アドレス空間内のアドレスへのポインタ。
マップするメモリーの長さ (バイト)。
保護を指定するビットフィールド。指定可能な設定は、PROT_READ、PROT_WRITE、PROT_EXEC、PROT_USER、および PROT_ALL です。詳細はマニュアルページを参照してください。
試みられたマッピングで使用可能な最大の保護フラグ。ユーザーが特殊ファイルを読み取り専用で開いた場合には、PROT_WRITE ビットをマスキングして除外できます。
マッピングのタイプを示すフラグ。指定可能な値は MAP_SHARED と MAP_PRIVATE です。
ユーザー資格構造体へのポインタ。
次の例のドライバは、書き込み専用マッピングを許可するフレームバッファーを制御しています。このドライバは、アプリケーションが読み取りアクセス権の取得を試みた場合に EINVAL を返し、続いて ddi_devmap_segmap(9F) を呼び出してユーザーマッピングを設定します。
例 10-1 segmap(9E) ルーチン
static int xxsegmap(dev_t dev, off_t off, struct as *asp, caddr_t *addrp, off_t len, unsigned int prot, unsigned int maxprot, unsigned int flags, cred_t *credp) { if (prot & PROT_READ) return (EINVAL); return (ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, cred)); }
次の例は、レジスタ空間内でページ境界割り当てされていないバッファーを持つデバイスの処理方法を示したものです。この例では、バッファーの先頭に対応するアドレスが mmap(2) から返されるように、オフセット 0x800 から始まるバッファーをマップしています。devmap_devmem_setup(9F) 関数は、ページの全体をマップし、マッピングがページ境界割り当てされるように要求したあと、ページの先頭のアドレスを返します。このアドレスが segmap(9E) をパススルーしたり、segmap() エントリポイントが未定義の場合には、バッファーの先頭に対応するアドレスではなくページの先頭に対応するアドレスが mmap() から返されます。この例では、結果として返されるアドレスが目的とするバッファーの先頭位置になるように、devmap_devmem_setup からの戻り値であるページ境界割り当てされたアドレスに、バッファーのオフセットが加算されています。
例 10-2 mmap() 呼び出しから返されるアドレスを segmap() 関数を使用して変更する
#define BUFFER_OFFSET 0x800 int xx_segmap(dev_t dev, off_t off, ddi_as_handle_t as, caddr_t *addrp, off_t len, uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp) { int rval; unsigned long pagemask = ptob(1L) - 1L; if ((rval = ddi_devmap_segmap(dev, off, as, addrp, len, prot, maxprot, flags, credp)) == DDI_SUCCESS) { /* * The address returned by ddi_devmap_segmap is the start of the page * that contains the buffer. Add the offset of the buffer to get the * final address. */ *addrp += BUFFER_OFFSET & pagemask); } return (rval); }
devmap(9E) エントリポイントは、ddi_devmap_segmap(9F) エントリポイントの内側にある segmap(9E) 関数から呼び出されます。
devmap(9E) エントリポイントは、mmap(2) システムコールの結果として呼び出されます。devmap(9E) 関数は、デバイスメモリーまたはカーネルメモリーをユーザーアプリケーションにエクスポートするために呼び出されます。devmap() 関数は次の操作のために使用されます。
デバイスメモリーまたはカーネルメモリーへのユーザーマッピングが妥当かどうか検査する
アプリケーションマッピング内の論理オフセットをデバイスメモリーまたはカーネルメモリー内の対応するオフセットに変換する
マッピング情報をシステムに渡し、マッピングを設定できるようにする
devmap() 関数の構文は次のとおりです。
int devmap(dev_t dev, devmap_cookie_t handle, offset_t off, size_t len, size_t *maplen, uint_t model);
各表記の意味は次のとおりです。
マップするメモリーを含むデバイス。
システムがデバイス内またはカーネル内の連続するメモリーへのマッピングを記述するために作成して使用するデバイスマッピングハンドル。
アプリケーションマッピング内の論理オフセット。ドライバはこのオフセットを、デバイスメモリーまたはカーネルメモリー内の対応するオフセットに変換する必要があります。
マップするメモリーの長さ (バイト)。
ドライバが、異なるカーネルメモリー領域または物理的に不連続な複数のメモリー領域を、連続する 1 つのユーザーアプリケーションマッピングに関連付けることを可能にします。
現在のスレッドのデータモデルタイプ。
システムは、1 つの mmap(2) システムコールで複数のマッピングハンドルを作成します。たとえば、マッピングには、物理的に不連続なメモリー領域が複数含まれる可能性があります。
最初、パラメータ off と len を指定して devmap(9E) が呼び出されます。これらのパラメータは、アプリケーションから mmap(2) に渡されます。devmap(9E) は、*maplen を、off から連続するメモリー領域の末尾までの長さに設定します。*maplen の値は、ページサイズの倍数に切り上げる必要があります。 *maplen の値は、元のマッピング長 len よりも小さい値に設定してもかまいません。そうした場合、システムは、新しいマッピングハンドルと調整後の off および len パラメータを使用しながら、最初のマッピング長に達するまで devmap(9E) を繰り返し呼び出します。
ドライバが複数のアプリケーションデータモデルをサポートする場合は、ddi_model_convert_from(9F) に model を渡す必要があります。ddi_model_convert_from() 関数は、現在のスレッドとデバイスドライバとの間にデータモデルの不一致が存在しているかどうかを判定します。ユーザースレッドが異なるデータモデルをサポートしている場合、デバイスドライバは、データ構造体の構造を調整したあとでその構造体をユーザースレッドにエクスポートしなければならない可能性があります。詳細については、付録 C 64 ビットデバイスドライバの準備のページを参照してください。
devmap(9E) エントリポイントは、論理オフセット off がドライバからエクスポートされるメモリーの範囲外である場合には -1 を返す必要があります。