ナビゲーションリンクをスキップ | |
印刷ビューの終了 | |
デバイスドライバの記述 Oracle Solaris 11.1 Information Library (日本語) |
パート I Oracle Solaris プラットフォーム用デバイスドライバの設計
2. Oracle Solaris カーネルとデバイスツリー
22. ドライバのコンパイル、ロード、パッケージ化、およびテスト
23. デバイスドライバのデバッグ、テスト、およびチューニング
一部のデバイスドライバでは、カーネルメモリーを割り当て、そのメモリーにユーザープログラムから mmap(2) 経由でアクセスできるようにしなければならない場合があります。たとえば、2 つのアプリケーション間で通信を行うための共有メモリーを設定する場合が挙げられます。また、ドライバとアプリケーションとの間でメモリーを共有する場合なども挙げられます。
カーネルメモリーをユーザーアプリケーションにエクスポートする場合は、次の手順に従います。
ddi_umem_alloc(9F) を使用してカーネルメモリーを割り当てます。
devmap_umem_setup(9F) を使用してメモリーをエクスポートします。
メモリーが不要になったら、ddi_umem_free(9F) を使用してメモリーを解放します。
アプリケーションにエクスポートするカーネルメモリーを割り当てるには、ddi_umem_alloc(9F) を使用します。ddi_umem_alloc() で使用される構文は、次のとおりです。
void *ddi_umem_alloc(size_t size, int flag, ddi_umem_cookie_t *cookiep);
各表記の意味は次のとおりです。
割り当てるバイト数。
スリープ条件やメモリータイプを決定するために使用されます。
カーネルメモリー cookie へのポインタ。
ddi_umem_alloc(9F) は、ページ境界割り当てされたカーネルメモリーを割り当てます。ddi_umem_alloc() は、割り当てられたメモリーへのポインタを返します。最初、メモリーにはゼロが設定されます。割り当てられるバイト数はシステムページサイズの倍数であり、size パラメータから切り上げられます。割り当てられたメモリーは、カーネル内で使用してもかまいません。このメモリーは、アプリケーションにエクスポートすることもできます。cookiep は、割り当てられるカーネルメモリーを記述するカーネルメモリー cookie へのポインタです。cookiep は、ドライバがカーネルメモリーをユーザーアプリケーションにエクスポートするときに、devmap_umem_setup(9F) で使用されます。
flag 引数は、ddi_umem_alloc(9F) がブロックするかそれともすぐにリターンするのかと、割り当てられるカーネルメモリーがページング可能かどうかを示します。flag 引数の値は次のとおりです。
ドライバは、メモリーが使用可能になるまで待機する必要はありません。メモリーが使用可能でない場合は NULL を返します。
ドライバは、メモリーが使用可能になるまで無期限に待機できます。
ドライバは、メモリーのページアウトを許可します。これを設定しないと、メモリーがロックダウンされます。
ddi_umem_lock() 関数は、デバイスロックメモリーのチェックを実行できます。 この関数は、project.max-locked-memory に指定された制限値に基づいてチェックします。現在のプロジェクトのロックメモリー使用量が制限値を下回っている場合、そのプロジェクトのロックメモリーバイト数が増やされます。制限チェックのあとでメモリーがロックされます。ddi_umem_unlock() 関数を呼び出すとメモリーのロックが解除され、プロジェクトのロックメモリーバイト数が減らされます。
使用されるアカウンティング方式は、精度の低いフルプライスモデルです。たとえば、オーバーラップしたメモリー領域を含む同一プロジェクト内で umem_lockmemory() を呼び出した 2 つの呼び出し元は、2 回課金されます。
ゾーンがインストールされた Oracle Solaris システムの project.max-locked-memory および zone.max-locked_memory 資源制御については、『Resource Management and Oracle Solaris Zones Developer’s Guide 』を参照するほか、resource_controls(5) も参照してください。
次の例は、アプリケーションアクセス用のカーネルメモリーを割り当てる方法を示したものです。ドライバは、複数のアプリケーションによって共有メモリー領域として使用される 1 枚のカーネルメモリーページをエクスポートします。メモリーの割り当ては、アプリケーションが共有ページをはじめてマップしたときに segmap(9E) 内で行われます。ドライバが複数のアプリケーションデータモデルをサポートする必要がある場合には、追加のページが割り当てられます。たとえば、64 ビットドライバが、64 ビットアプリケーションと 32 ビットアプリケーションの両方にメモリーをエクスポートするとします。このとき、64 ビットアプリケーションが 1 枚目のページを共有し、32 ビットアプリケーションが 2 枚目のページを共有します。
例 10-4 ddi_umem_alloc() ルーチンの使用
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) { int error; minor_t instance = getminor(dev); struct xxstate *xsp = ddi_get_soft_state(statep, instance); size_t mem_size; /* 64-bit driver supports 64-bit and 32-bit applications */ switch (ddi_mmap_get_model()) { case DDI_MODEL_LP64: mem_size = ptob(2); break; case DDI_MODEL_ILP32: mem_size = ptob(1); break; } mutex_enter(&xsp->mu); if (xsp->umem == NULL) { /* allocate the shared area as kernel pageable memory */ xsp->umem = ddi_umem_alloc(mem_size, DDI_UMEM_SLEEP | DDI_UMEM_PAGEABLE, &xsp->ucookie); } mutex_exit(&xsp->mu); /* Set up the user mapping */ error = devmap_setup(dev, (offset_t)off, asp, addrp, len, prot, maxprot, flags, credp); return (error); }
カーネルメモリーをユーザーアプリケーションにエクスポートするには、devmap_umem_setup(9F) を使用します。devmap_umem_setup () は、ドライバの devmap(9E) エントリポイントから呼び出す必要があります。 devmap_umem_setup() の構文は次のとおりです。
int devmap_umem_setup(devmap_cookie_t handle, dev_info_t *dip, struct devmap_callback_ctl *callbackops, ddi_umem_cookie_t cookie, offset_t koff, size_t len, uint_t maxprot, uint_t flags, ddi_device_acc_attr_t *accattrp);
各表記の意味は次のとおりです。
マッピングを記述するために使用される不透明な構造体。
デバイスの dev_info 構造体へのポインタ。
devmap_callback_ctl(9S) 構造体へのポインタ。
ddi_umem_alloc(9F) から返されたカーネルメモリー cookie。
cookie で指定されたカーネルメモリー内へのオフセット。
エクスポートされる長さ (バイト)。
エクスポートされるマッピングで使用可能な最大の保護を指定します。
DEVMAP_DEFAULTS に設定する必要があります。
ddi_device_acc_attr(9S) 構造体へのポインタ。
handle は、システムがマッピングの識別子として使用するデバイスマッピングハンドルです。handle は、devmap(9E) エントリポイントから渡されます。 dip は、デバイスの dev_info 構造体へのポインタです。callbackops は、マッピングに関するユーザーイベントの通知をドライバが受け取れるようにします。カーネルメモリーのエクスポート時には、ほとんどのドライバで callbackops が NULL に設定されます。
koff および len は、ddi_umem_alloc(9F) によって割り当てられたカーネルメモリー内の範囲を指定します。この範囲は、devmap(9E) エントリポイントから渡されたオフセットの位置で、ユーザーのアプリケーションマッピングからアクセス可能となります。通常、ドライバは devmap(9E) のオフセットを devmap_umem_setup(9F) に直接渡します。このとき、mmap(2) から返されるアドレスは、ddi_umem_alloc(9F) から返されたカーネルアドレスにマップします。koff と len は、ページ境界割り当てされる必要があります。
ドライバは maxprot を使用することで、エクスポートされるカーネルメモリー内の個々の領域ごとに保護を指定できます。たとえば、ある領域の書き込みアクセス権を許可しないようにするには、PROT_READ と PROT_USER のみを設定します。
次の例は、カーネルメモリーをアプリケーションにエクスポートする方法を示したものです。ドライバはまず、要求されたマッピングが、割り当てられたカーネルメモリー領域内に収まっているかチェックします。64 ビットドライバは、32 ビットアプリケーションからマッピング要求を受け取ると、その要求をカーネルメモリー領域の 2 枚目のページにリダイレクトします。このリダイレクトにより、同じデータモデルを使用してコンパイルされたアプリケーションのみが同一ページを共有するようになります。
例 10-5 devmap_umem_setup(9F) ルーチン
static int xxdevmap(dev_t dev, devmap_cookie_t handle, offset_t off, size_t len, size_t *maplen, uint_t model) { struct xxstate *xsp; int error; /* round up len to a multiple of a page size */ len = ptob(btopr(len)); /* check if the requested range is ok */ if (off + len > ptob(1)) return (ENXIO); xsp = ddi_get_soft_state(statep, getminor(dev)); if (xsp == NULL) return (ENXIO); if (ddi_model_convert_from(model) == DDI_MODEL_ILP32) /* request from 32-bit application. Skip first page */ off += ptob(1); /* export the memory to the application */ error = devmap_umem_setup(handle, xsp->dip, NULL, xsp->ucookie, off, len, PROT_ALL, DEVMAP_DEFAULTS, NULL); *maplen = len; return (error); }
ドライバがアンロードされたら、ddi_umem_alloc(9F) によって割り当てられたメモリーを、ddi_umem_free(9F) を呼び出して解放する必要があります。
void ddi_umem_free(ddi_umem_cookie_t cookie);
cookie は、ddi_umem_alloc(9F) から返されたカーネルメモリー cookie です。