Oracle® Solaris 11.2 デバイスドライバの記述

印刷ビューの終了

更新: 2014 年 9 月
 
 

64 ビットに対応したデバイスドライバに対する入出力制御のサポート

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);
}