Presentation is loading. Please wait.

Presentation is loading. Please wait.

Linux Device Driver 輪講 Che++. 第 6 章 キャラクタ型ドライバの高度な 機 第 1 回 (全 2 回)

Similar presentations


Presentation on theme: "Linux Device Driver 輪講 Che++. 第 6 章 キャラクタ型ドライバの高度な 機 第 1 回 (全 2 回)"— Presentation transcript:

1 Linux Device Driver 輪講 Che++

2 第 6 章 キャラクタ型ドライバの高度な 機 第 1 回 (全 2 回)

3 この章で学ぶ事 「完全な」キャラクタ型デバイスドライ バ作成のための概念 –ioctl システムコールの実装 – プロセスのスリープ – 非ブロッキング I/O の実装 – ユーザ空間へのアクセス許可通知 – いくつかのアクセスポリシーの実装方法 題材として scull ドライバを使う –3 章で作ったドライバの修正版

4 ioctl デバイスへの操作は ioctl システムコールで 行う int ioctl(int fd, unsigned long cmd,...); –UNIX システムコールの中では異色な存在 普通システムコールに ”…” は使わない – 第 3 引数の型が第 2 引数によって異なるため、 コンパイル時の型チェック回避のために ”…” が使われる

5 ioctl ioctl ドライバメソッドのプロトタイプ int (*ioctl) (struct inode* inode, struct file* filp,unsigned int cmd, unsigned long arg); –inode と filp はファイル記述子 fd に対応する値 open メソッドに対して渡されたパラメータと同じ –cmd はマクロでシンボリック名を用意する事 が多い –arg は整数値でもポインタでも unsigned long として渡される

6 ioctl コマンドの選び方 ioctl に渡す cmd の値はシステム全体でユ ニークになるように選ぶべき –0 や 1 から始めるのはよくない 他のドライバの ioctl との混同を避けるため カーネル内で使われる番号もある include/asm/ioctl.h と Documentation/ioctl- number.txt を調べる

7 ioctl コマンドの選び方 4 つのビットフィールドを使ってコマンド番号を 生成する –type マジック番号 –number 順序番号 –direction データ転送の方向 –size 対象となるユーザデータのサイズ マクロを使って生成

8 ioctl の選び方 scull での例 /* Use 'k' as magic number */ #define SCULL_IOC_MAGIC 'k' /* Please use a different 8-bit number in your code */ #define SCULL_IOCRESET _IO(SCULL_IOC_MAGIC, 0) /* * S means "Set" through a ptr, * T means "Tell" directly with the argument value * G means "Get": reply by setting through a pointer * Q means "Query": response is on the return value * X means "eXchange": switch G and S atomically * H means "sHift": switch T and Q atomically */ #define SCULL_IOCSQUANTUM _IOW(SCULL_IOC_MAGIC, 1, int) #define SCULL_IOCSQSET _IOW(SCULL_IOC_MAGIC, 2, int) #define SCULL_IOCTQUANTUM _IO(SCULL_IOC_MAGIC, 3) #define SCULL_IOCTQSET _IO(SCULL_IOC_MAGIC, 4) #define SCULL_IOCGQUANTUM _IOR(SCULL_IOC_MAGIC, 5, int) #define SCULL_IOCGQSET _IOR(SCULL_IOC_MAGIC, 6, int) #define SCULL_IOCQQUANTUM _IO(SCULL_IOC_MAGIC, 7) #define SCULL_IOCQQSET _IO(SCULL_IOC_MAGIC, 8) #define SCULL_IOCXQUANTUM _IOWR(SCULL_IOC_MAGIC, 9, int) #define SCULL_IOCXQSET _IOWR(SCULL_IOC_MAGIC,10, int) #define SCULL_IOCHQUANTUM _IO(SCULL_IOC_MAGIC, 11) #define SCULL_IOCHQSET _IO(SCULL_IOC_MAGIC, 12) #define SCULL_IOC_MAXNR 14

9 戻り値 ioctl は通常 cmd に応じる switch 文から成る –default 節の(一致するコマンド番号がない) 場合の戻り値は? -EINVAL (無効な引数)はよく使われる – 理にかなってはいる 標準では -ENOTTY (デバイスにとって不 適切な ioctl )が推奨される – 一般的にはこちらのメッセージの方が適切

10 あらかじめ定義されたコマンド いくつかの ioctl コマンドはカーネル本体に よって処理される – これらのコマンドがデバイスドライバコード に渡される事はない 普通のファイルや特殊なファイルに対す るコマンド、ファイルシステム固有なコ マンド等が該当する

11 ioctl 引数の使い方 ioctl 引数は整数値だったりポインタだった りする – 整数値だったら直接使えば問題ない – ポインタだったらユーザ空間にアクセスする 必要が生じる 第 3 章で出てきた copy_from_user や copy_to_user が使える – ただし効率が悪い

12 ioctl 引数の使い方 効率の良いデータ転送 – まずはアドレスの検証 int access_ok(int type, const void *addr, unsigned long size); – データ転送マクロ put_user(datum, ptr) __put_user(datum, ptr) get_user(local, ptr) __get_user(local, ptr)

13 互換性と制限される操作 通常デバイスドライバはパーミッション のチェックを行わない – デバイスへのアクセスはデバイスファイルの パーミッションによって制御されるべき 特定の動作についてはユーザの ” 能力 ” に よって制御したい – 読み書きはできてもフォーマットはさせたく ない – デバイスの設定は特定ユーザにしか許可した くない

14 互換性と制限される操作 デバイスドライバで扱う ” 能力 ” CAP_DAC_OVERRIDE CAP_NET_ADMIN CAP_SYS_MODULE CAP_SYS_RAWIO CAP_SYS_ADMIN CAP_SYS_TTY_CONFIG capable 関数で ” 能力 ” の有無のチェック int capable(int capability);

15 ioctl を使わないデバイス制御 ioctl を使わなくてもデバイスは制御可能 – 例えばコンソールでのエスケープシーケンス – デバイスによってはこちらの方が適している 場合もある 実装も利用も簡単になる

16 I/O のブロック デバイスドライバはプロセスをブロック する場合がある – デバイスが read や write の呼び出しにすぐに応 じることができない場合等

17 スリープとは スケジューラの待ち列から削除される事 アトミックなコンテキストを実行している時は スリープさせてはいけない 誰かがどこかでプロセスを起こすという確信が なければ、スリープさせてはいけない Linux では待ち列は wait_queue_head_t 構造体で 管理される – 初期化 DECLARE_WAIT_QUEUE_HEAD(name); または wait_queue_head_t my_queue; init_waitqueue_head(&my_queue);

18 簡単なスリープの例 wait_event マクロでプロセスをスリープさせる wait_event(queue, condition) wait_event_interruptible(queue, condition) wait_event_timeout(queue, condition, timeout) wait_event_interruptible_timeout(queue, condition, timeout) wake_up マクロでスリープしているプロセスを 起こす void wake_up(wait_queue_head_t *queue); void wake_up_interruptible(wait_queue_head_t *queue);

19 簡単なスリープの例 static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag = 0; ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) going to sleep\n", current->pid, current->comm); wait_event_interruptible(wq, flag != 0); flag = 0; printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm); return 0; /* EOF */ } ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count, loff_t *pos) { printk(KERN_DEBUG "process %i (%s) awakening the readers...\n", current->pid, current->comm); flag = 1; wake_up_interruptible(&wq); return count; /* succeed, to avoid retrial */ }

20 ブロックと非ブロック処理 プロセスの中にはブロックしてほしくな いものもある –flip->f_flags に O_NONBLOCK がセットされて いるものはブロックしてはいけない

21 排他的な待ち wake_up マクロは全ての待ちプロセスを実行可 能にする – それぞれのプロセスがリソースの取り合いをして、 勝ったプロセスが実行を続ける – その他のプロセスは再びスリープ – 待ち列が大量にある時は困る 待ち列エントリに WQ_FLAG_EXCLUSIVE を指 定すると 1 個ずつプロセスを起こせる void prepare_to_wait_exclusive(wait_queue_head_t* queue, wait_queue_t *wait, int state);


Download ppt "Linux Device Driver 輪講 Che++. 第 6 章 キャラクタ型ドライバの高度な 機 第 1 回 (全 2 回)"

Similar presentations


Ads by Google