Oracle Solaris カーネルは、32 ビットアプリケーションと 64 ビットアプリケーションの両方をサポートしている適切なハードウェア上では 64 ビットモードで動作します。両方のサイズのプログラムからの入出力制御コマンドをサポートするには、64 ビットのデバイスドライバが必要です。32 ビットプログラムと 64 ビットプログラムの違いは、C 言語の型モデルです。32 ビットプログラムは ILP32 であり、64 ビットプログラムは LP64 です。C データ型モデルについては、Appendix C, Making a Device Driver 64-Bit Readyを参照してください。
プログラムとカーネルの間を流れるデータの形式が同じでない場合は、ドライバがモデルの不一致に対処できる必要があります。モデルの不一致に対処するには、データに対して適切な調整を行う必要があります。
モデルの不一致が存在するかどうかを判定するために、ioctl (9E) のモードパラメータは、ドライバにデータモデルのビットを渡します。Example 15–14 に示すように、このモードパラメータは次に、何らかのモデル変換が必要かどうかを判定するために ddi_model_convert_from(9F) に渡されます。
ioctl(9E) ルーチンにデータモデルを渡すために、モード引数のフラグサブフィールドが使用されます。このフラグは、次のいずれかの値に設定されます。
DATAMODEL_ILP32
DATAMODEL_LP64
FNATIVE は、カーネル実装のデータモデルに一致するように条件付きで定義されます。mode 引数からフラグを抽出するには、FMODELS マスクを使用します。これにより、ドライバは、明示的にデータモデルを検査してアプリケーションのデータ構造体をコピーする方法を判定できます。
DDI 関数の ddi_model_convert_from(9F) は、ioctl() 呼び出しに関して一部のドライバを支援できる簡易ルーチンです。この関数は引数としてユーザーアプリケーションのデータ型モデルを受け取り、次のいずれかの値を返します。
DDI_MODEL_ILP32 – ILP32 アプリケーションから変換する
DDI_MODEL_NONE – 変換は必要なし
アプリケーションとドライバのデータモデルが同じである場合のように、データ変換が必要ない場合は DDI_MODEL_NONE が返されます。LP64 モデルにコンパイルされていて、32 ビットアプリケーションと通信するドライバには DDI_MODEL_ILP32 が返されます。
次の例では、ドライバは、ユーザーアドレスを含むデータ構造体をコピーします。このデータ構造体は、ILP32 から LP64 にサイズが変更されます。それに応じて、64 ビットのドライバは、32 ビットアプリケーションとの通信には構造体の 32 ビットバージョンを使用します。
使用例 15-14 32 ビットアプリケーションと 64 ビットアプリケーションをサポートする ioctl(9E) ルーチンstruct args32 { uint32_t addr; /* 32-bit address in LP64 */ int len; } struct args { caddr_t addr; /* 64-bit address in LP64 */ int len; } static int xxioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { struct xxstate *xsp; struct args a; xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) { return (ENXIO); } switch (cmd) { case XX_COPYIN_DATA: switch(ddi_model_convert_from(mode)) { case DDI_MODEL_ILP32: { struct args32 a32; /* copy 32-bit args data shape */ if (ddi_copyin((void *)arg, &a32, sizeof (struct args32), mode) != 0) { return (EFAULT); } /* convert 32-bit to 64-bit args data shape */ a.addr = a32.addr; a.len = a32.len; break; } case DDI_MODEL_NONE: /* application and driver have same data model. */ if (ddi_copyin((void *)arg, &a, sizeof (struct args), mode) != 0) { return (EFAULT); } } /* continue using data shape in native driver data model. */ break; case XX_COPYOUT_DATA: /* copyout handling */ break; default: /* generic "ioctl unknown" error */ return (ENOTTY); } return (0); }