Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

32 ビットと 64 ビットのデータ構造体マクロ

使用例 83 の方法は、多くのドライバで正常に機能します。この代わりに、<sys/model.h> で提供されているデータ構造体マクロを使用して、アプリケーションとカーネルの間でデータを移動する方法があります。これらのマクロによってコードが整理され、機能の点から見てまったく同様に動作するようになります。

使用例 84  データ構造体マクロを使用したデータの移動
int
    xxioctl(dev_t dev, int cmd, intptr_t arg, int mode,
        cred_t *cr, int *rval_p)
    {    
        STRUCT_DECL(opdata, op);

        if (cmd != OPONE)
            return (ENOTTY);

        STRUCT_INIT(op, mode);

        if (copyin((void *)arg,
            STRUCT_BUF(op), STRUCT_SIZE(op)))
                return (EFAULT);

        if (STRUCT_FGET(op, flag) != XXACTIVE ||     
            STRUCT_FGET(op, size) > XXSIZE)
                return (EINVAL);
        xxdowork(device_state, STRUCT_FGET(op, size));
        return (0);
}

構造体マクロの動作のしくみ

64 ビットのデバイスドライバでは、構造体マクロを使用すると、両方のサイズのデータ構造体でカーネルメモリーの同じ部分を使用できます。メモリーバッファーには、データ構造体のネイティブ形式 (つまり、LP64 形式と ILP32 形式) の内容が保持されます。構造体への各アクセスは、条件式によって実装されます。32 ビットのドライバとしてコンパイルされた場合は、1 つのデータモデル (ネイティブ形式) のみがサポートされます。条件式は使用されません。

64 ビットバージョンのマクロは、データ構造体のシャドウバージョンの定義に依存します。シャドウバージョンには、固定幅の型を含む 32 ビットインタフェースが記述されます。シャドウデータ構造体の名前は、ネイティブなデータ構造体の名前に「32」を追加することによって作成されます。将来の保守コストを軽減するために、便宜上、シャドウ構造体の定義はネイティブな構造体と同じファイル内に置きます。

これらのマクロは、次の引数を取ることができます。

structname

struct キーワードのあとに入力されたデータ構造体のネイティブ形式の構造体名。

umodel

ioctl(9E) のモードパラメータから抽出されたユーザーのデータモデル (FILP32FLP64 など) が格納されたフラグワード。

handle

これらのマクロで操作される構造体の特定のインスタンスを参照するために使用される名前。

fieldname

構造体内のフィールドの名前。

構造体マクロを使用する場合

マクロを使用すると、あるデータ項目のフィールドのみへのインプレース参照を行うことができます。マクロでは、データモデルに基づいた別のコードパスを取るための方法は提供されません。データ構造体内のフィールドの数が多い場合は、マクロを避けるべきです。また、これらのフィールドを参照する頻度が高い場合も、マクロを避けるべきです。

マクロでは、データモデル間の違いの多くがマクロの実装内に覆い隠されます。その結果、このインタフェースを使用して記述されたコードは一般に読みやすくなります。32 ビットのドライバとしてコンパイルされた場合、結果のコードは煩わしい #ifdefs が必要ないため簡潔になりますが、データ型のチェックは引き続き保持されます。

構造体ハンドルの宣言と初期化

STRUCT_DECL(9F)STRUCT_INIT(9F) を使用すると、スタック上の ioctl をデコードするためのハンドルと領域を宣言して初期化できます。STRUCT_HANDLE(9F)STRUCT_SET_HANDLE(9F) は、スタック上の領域を割り当てることなくハンドルを宣言して初期化します。構造体が非常に大きいか、またはほかのデータ構造体に含まれている場合は、後者のマクロが役立つことがあります。


注 - STRUCT_DECL(9F) マクロと STRUCT_HANDLE(9F) マクロはデータ構造体の宣言まで拡張されるため、これらのマクロは C コードでこのような宣言を使用してグループ化されます。

構造体を宣言して初期化するためのマクロは次のとおりです。

STRUCT_DECL(structname , handle)

structname データ構造体のための、handle という名前の構造体ハンドルを宣言します。STRUCT_DECL は、スタック上のネイティブ形式のための領域を割り当てます。ネイティブ形式は、構造体の ILP32 形式より大きいか、または等しいと見なされます。

STRUCT_INIT(handle, umodel)

handle のデータモデルを umodel に初期化します。このマクロは、STRUCT_DECL(9F) を使用して宣言された構造体ハンドルへの何らかのアクセスが行われる前に呼び出す必要があります。

STRUCT_HANDLE(structname , handle)

handle という名前の構造体ハンドルを宣言します。STRUCT_DECL(9F) と対比されます。

STRUCT_SET_HANDLE(handle, umodel, addr)

handle のデータモデルを umodel に初期化し、addr を以降の操作に使用されるバッファーとして設定します。このマクロは、STRUCT_HANDLE(9F) を使用して宣言された構造体ハンドルへのアクセスの前に呼び出します。

構造体ハンドルに対する操作

構造体に対する操作を実行するためのマクロは次のとおりです。

size_t STRUCT_SIZE(handle)

handle によって参照される構造体のサイズを、その組み込みのデータモデルに応じて返します。

typeof fieldname STRUCT_FGET(handle, fieldname)

handle によって参照されるデータ構造体内の示されているフィールドを返します。このフィールドはポインタ以外の型です。

typeof fieldname STRUCT_FGETP(handle, fieldname)

handle によって参照されるデータ構造体内の示されているフィールドを返します。このフィールドはポインタ型です。

STRUCT_FSET(handle, fieldname, val)

handle によって参照されるデータ構造体内の示されているフィールドを値 val に設定します。val の型は、fieldname の型に一致します。このフィールドはポインタ以外の型です。

STRUCT_FSETP(handle, fieldname, val)

handle によって参照されるデータ構造体内の示されているフィールドを値 val に設定します。このフィールドはポインタ型です。

typeof fieldname *STRUCT_FADDR(handle, fieldname)

handle によって参照されるデータ構造体内の示されているフィールドのアドレスを返します。

struct structname *STRUCT_BUF(handle)

handle で記述されたネイティブな構造体へのポインタを返します。

その他の操作

その他の構造体マクロのいくつかを次に示します。

size_t SIZEOF_STRUCT(struct_name, datamodel)

指定されたデータモデルに基づいた struct_name のサイズを返します。

size_t SIZEOF_PTR(datamodel)

指定されたデータモデルに基づいたポインタのサイズを返します。