Zephyr×Rustのインテグレーションにチャレンジ!⑧~続システムコール調査~
はじめに
ZephyrとRustのインテグレーションに挑戦しています。
これまでで、アプリケーションをRustで書いてきました。 ここからは、Driverを書く方法を調査していきます。
前回までのあらすじ
アプリケーションに公開するDriver APIを作るため、システムコールの実装を調査しています。
システムコール実装のために必要な要素のうち、__syscall
プレフィックスのついたプロトタイプ宣言について調査しました。
__syscall
プレフィックスのついたプロトタイプ宣言。ビルドプロセス内でgen_syscall.py
によって処理されます。- 実装関数。実際のシステムコール実装です。
- ハンドラ関数。引数を検証してから、実装関数に渡すためのラッパーです。
実装関数
実装関数を作る際に気を付けることは、名前の付け方です。
_impl_
プレフィックス+システムコールAPI、にする必要があります。
プロトタイプ宣言は自動生成されるため、自分でプロトタイプ宣言を作る必要はありません。
ハンドラ関数
ハンドラ関数は、ユーザースレッドがシステムコールを発行した場合、kernel側で動作します。 ユーザースレッドがスーパーバイザモードに移行するため、ソフトウェア割り込みを発生させると、共通のシステムコールエントリポイントは、システムコールIDを使って、適切なハンドラ関数を見つけて、ジャンプします。
ハンドラ関数の目的は、与えられた引数を検証することです。
- kernel objectポインタが与えられた場合、システムコールを呼び出したスレッドが、パーミッションを持っているかどうか、検証します。
- ユーザー空間から与えられたバッファの場合、システムコールを呼び出したスレッドが、読み/書きのパーミッションを持っているかどうか、検証します。
- そのほかの引数では、値が制限範囲内にあるかどうか、検証します。
引数検証
引数を検証するためのマクロが定義されています。 いくつか紹介します。
Z_SYSCALL_OBJ()
。kernel objectが期待した通りの型か、呼び出しスレッドは適切なパーミッションを持っているか、初期化されているか、を検証します。Z_SYSCALL_MEMORY_READ()
。指定サイズのメモリバッファ全体に対して、読み込み権限があるかどうか、を検証します。Z_SYSCALL_MEMORY_WRITE()
。Z_SYSCALL_MEMORY_READ()
と似ていますが、書き込み権限があるかどうか、を検証します。
検証に失敗した場合、Z_OOPS()
が呼び出され、呼び出しスレッドをkillします。
ハンドラの宣言
_SYSCALL_HANDLER()
マクロを使って宣言できます。
Z_SYSCALL_HANDLER(k_sem_init, sem, initial_count, limit) { ... }
ということで、既存のシステムコールを利用するならともかく、新しいシステムコールをRustで作ろうとすると、苦労しそうですね…。