Download presentation
Presentation is loading. Please wait.
Published byともなり たつざわ Modified 約 8 年前
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);
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.