FreeBSDの デバイスドライバについて

Slides:



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

2.5 プログラムの構成要素 (1)文字セット ① ASCII ( American Standard Code for Interchange ) JIS コードと同じ ② EBCDIC ( Extended Binary Coded Decimal for Information Code ) 1.
プロセスの生成とコマンドの実行 プロセスの生成とコマンドの実行 プロセス生成のシステムコール プロセス生成のシステムコール プロセス生成のプログラム例 プロセス生成のプログラム例 プログラム実行のシステムコール プログラム実行のシステムコール 子プロセスの終了を待つシステムコール 子プロセスの終了を待つシステムコール.
第2回 プロセス管理 ジョブ、プロセスとは? プロセスの状態遷移 プロセス制御ブロック スケジューリング.
計算機システム概論・3回目 本日のトピック:割込みと入出力制御について 割込み制御について 問題点の明確化 割込みとは
セキュリティ機構のオフロードを考慮した仮想マシンへの動的メモリ割当
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
記 憶 管 理(1) オペレーティングシステム 第9回.
■パス検索 各種ファイルを操作するには、まずパス名をiノードに変換しなければならない。 以下にパス名をiノードに変換する関数の説明を行う。
入 出 力 管 理 オペレーティングシステム 6/26/09.
京都大学情報学研究科 通信情報システム専攻 湯淺研究室 M2 平石 拓
プログラミング基礎I(再) 山元進.
組み込み環境における ユーザレベル・デバイスドライバの検討 (進捗報告)
システムプログラミング 第6回、7回 main関数の引数 usageメッセージ システムコールのエラーメッセージ ファイル
坂井 修一 東京大学 大学院 情報理工学系研究科 電子情報学専攻 東京大学 工学部 電気工学科
実行時のメモリ構造(1) Jasminの基礎とフレーム内動作
■デバイスドライバIF - ドライバの登録 ブロックデバイスのドライバの登録は、register_blkdev関数を用いて、ブロックデバイスドライバの 登録テーブルblkdev[ ]に、デバイス名とデバイス操作関数テーブルの登録を行う。 unregister_blkdev関数はその逆に登録を抹消する。
プログラミング基礎I(再) 山元進.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
オペレーティングシステム (OSの機能と構造)
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング システムプログラミング プロセス間通信(パイプ) 担当:青木義満
第3回 CPUの管理と例外処理 OSによるハードウェアの管理 CPUの構成、動作 CPUの管理 例外処理、割り込み処理 コンテキストスイッチ
Linuxカーネルについて 2014/01.
CC/7700,CC32を用いた データ収集システム 筑波大学 木村 博美 小松原 哲郎 (c)2007 木村博美 筑波大学.
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
Ibaraki Univ. Dept of Electrical & Electronic Eng.
オペレーティングシステム2005 デバイス管理 (1)
第8回入出力制御 デバイスコントローラ ポーリングと割込み 入出力の方式 PIO DMA 入出力のためのソフトウェア技法.
型付きアセンブリ言語を用いた安全なカーネル拡張
プログラミング言語入門 手続き型言語としてのJava
システムプログラミング 第6回、7回、8回 情報工学科 篠埜 功.
EVENT プログラミングのスタイル 手続き型: ある決められた場所から開始され, その後は純粋に上から下に流れて行く方式. 実行したいことを, 順番に記述してゆく. 逐次処理形式コーディングの方法である。 今までの授業(情報処理2や3)で 行ってきたプログラミングの演習 bcc32やmake 手続き型.
前坂 たけし (北大院・理) 其の壱 はじめての BIOS 前坂 たけし (北大院・理)
プログラミング演習I 2003年6月25日(第10回) 木村巌.
アルゴリズムとデータ構造 補足資料11-1 「mallocとfree」
メモリの準備 メモリには、その準備の方法で2種類ある。 静的変数: コンパイル時にすでにメモリのサイズがわかっているもの。 普通の変数宣言
オペレーティングシステム イントロダクション
岩村雅一 知能情報工学演習I 第10回(後半第4回) 岩村雅一
アルゴリズムとデータ構造 補足資料5-1 「メモリとポインタ」
第7回 授業計画の修正 中間テストの解説・復習 前回の補足(クロックアルゴリズム・PFF) 仮想記憶方式のまとめ 特別課題について
コンピュータの基本構成について 1E16M001-1 秋田梨紗 1E16M010-2 梅山桃香 1E16M013-3 大津智紗子
全体ミーティング 6月6日 島本 大輔(M2) 2006年6月6日(火).
担当:青木義満 情報工学科 3年生対象 専門科目 システムプログラミング 第6回 システムプログラミング概要 プロセスの生成 担当:青木義満
プログラムの制御構造 配列・繰り返し.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
フロントエンドとバックエンドのインターフェース
オペレーティングシステムJ/K 2004年11月15日2時限目
オペレーティングシステム (ファイル) 2009年11月9日
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
第5回 メモリ管理(2) オーバレイ方式 論理アドレスとプログラムの再配置 静的再配置と動的再配置 仮想記憶とメモリ階層 セグメンテーション
C言語ファミリー C# 高級言語(抽象的) Java オブジェクト指向 C++ C 機械語(原始的)
オペレーティングシステム (OSの機能と構造)
プログラミング演習I 2003年7月2日(第11回) 木村巌.
実装について 前田俊行.
システムプログラミング 第6回 システムコールのエラーメッセージ ファイルシステム 情報工学科 篠埜 功.
オペレーティングシステムJ/K 2004年10月4日
アルゴリズムとデータ構造1 2009年6月15日
ネットワーク・プログラミング デバイスドライバと環境変数.
高度プログラミング演習 (11).
オペレーティングシステム (ファイル) 2006年11月16日
オペレーティングシステム (ファイル) 2008年11月17日
ネットワーク・プログラミング TCPサーバ.
アルゴリズムとデータ構造 2010年6月17日
ネットワーク・プログラミング 1対多のプロセス間通信.
オペレーティングシステム (OSの機能と構造)
岩村雅一 知能情報工学演習I 第10回(後半第4回) 岩村雅一
システムプログラミング 第11回 シグナル 情報工学科  篠埜 功.
ネットワーク・プログラミング プロセスとファイルシステム管理.
L4-Linux のメモリ管理における問題点とその解決策
Presentation transcript:

FreeBSDの デバイスドライバについて

デバイスドライバ 多くのオペレーティングシステムでは、入出力デバイスへのアクセスはデバイスドライバと呼ばれるデバイス依存の処理を行なうインターフェイス部分を経由して行なう 各種デバイスを簡単に利用できるようにする 各種の入出力デバイスの詳細を,ユーザは意識しない デバイスとしては性質の異なるディスクもフロッピーディスクも同様の方法でマウントすることができ、ファイルの入出力を行なうことができる リソースマネージャとしての機能 複数のプロセスが同時に動作している状態でも,ユーザは安全にデバイスを利用することができる。 例えば,複数のプロセスから同時にディスクに対するアクセスを行なっても,ファイルの内容が混ざったり、命令の混合によってデバイスが誤動作を起こしたりしない。

キャラクタ型、ブロック型 UNIX系のOSの場合、キャラクタ型デバイスとブロック型デバイスに大別できる キャラクタ型デバイス: デバイス特有の性質に応じたデータ長単位の入出力を行なう シリアル、キーボード、パラレルインターフェイスなど標準的なデバイスの多くでは、1バイト単位の入出力を行ないます ブロック型デバイス: ある大きさのバッファをもち、バッファリングが行なわれるのが特徴です 一般的には,ブロック型のデバイスも,キャラクタ型としての利用も可能

エントリポイント デバイスドライバには利用するためのエントリポイント(関数)が必要 主なものは open, close, read, write, ioctl など エントリポイントは,ユーザプログラムがデバイスへのアクセスを行なうときに利用される カーネルにデバイスを登録するときに使用するデバイス構造体(cdevsw)に記述される 入出力応答 アクセス方法の統一、アクセス保護、 スケジューリング、バッファリング デバイス初期化、割り込み、 DMA処理、そのほかのデバイス依存                    の処理 出力要求 ユーザプロセス OS(デバイス依存部分を含まない) デバイスドライバ ハードウェアデバイス

デバイスを識別するための番号 メジャー番号(8ビット) とマイナー番号(24ビット)の組 メジャー番号: 個々のデバイスドライバに対応.最大256種類のデバイスドライバが存在可能です マイナー番号: 同じドライバで扱われる機器の番号に対応.同じデバイスの何台目かを識別したり、デバイスの機能を指定するために用いられます

デバイスドライバに対する操作 デバイスの初期化 open/close/read/write Ioctl など

デバイスの初期化 プロセスの入出力要求の処理には,「デバイスの初期化」が必要 1.プローブ ・入出力装置の存在の確認 2.アタッチ ファイルシステムのモジュールから,各デバイスドライバが「ファイル」として見える 「デバイスの初期化」によって,デバイスドライバが物理的な入出力装置の存在を確認し、必要な初期化を行なって,動作可能になる 初期化の過程では、登録された各デバイスドライバにつぎの2つの操作が行われる 1.プローブ ・入出力装置の存在の確認 2.アタッチ ・入出力装置を扱えるようにデバイスドライバ内のデータ構造を設定 ・割り込み処理ルーチンを登録する

デバイスの初期化に必要な情報 デバイスドライバでこれらの操作を行なうためには最低でも次の2つが既知である必要がある I/Oアドレス 入出力装置の制御ハードウェアとデータ交換するためにI/O命令で使用するアドレス 割り込み番号 入出力装置の状態が変化したときにCPUへ通知する

open/close/read/write デバイスドライバを利用したデータの入出力 一般のファイル同様に,デバイスファイルの open, read, write で行う デバイスファイルの役割 ユーザプログラムがopen/close、read/writeを行なうためのエントリとして用意されているのが/dev以下に置かれているデバイスファイル デバイスファイルをopenすることでデバイスドライバへの入出力の準備を行なう デバイスファイルへのread/writeを行なうことで、デバイスドライバへのread/writeファンクションを実行する

ioctl デバイスドライバ特有の機能 デバイスやデバイスドライバの動作モードの設定などを行なうためのもの read/writeの一般的な入出力機能ではできないことをするためのインターフェイスです

マウス用ドライバ(psm.c) 以下の構造体は、カーネルにマウスを登録するときに使用するデバイス構造体 (cdevsw) の例 static struct cdevsw psm_cdevsw = { /* open */ psmopen, /* close */ psmclose, /* read */ psmread, /* write */ nowrite, /* ioctl */ psmioctl, /* poll */ psmpoll, /* mmap */ nommap,

以下,マウス用のドライバの基本的な部分であるpsmopen, psmclose, psmread,psmioctl の説明を行う /* strategy */ nostrategy, /* name */ "psm", /* maj */ CDEV_MAJOR, /* #define CDEV_MAJOR 21 */ /* dump */ nodump, /* psize */ nopsize, /* flags */ 0, /* bmaj */ -1 }; 以下,マウス用のドライバの基本的な部分であるpsmopen, psmclose, psmread,psmioctl の説明を行う

static d_open_t psmopen(dev_t dev, int flag, int fmt, struct proc *p) 返り値: 正常に処理が終了: 0 エラー: 整数値 引数 flag: システムコールopen()の第二引数 fmt: 文字型であることを示すS\_IFCHR p: オープンを要求したプロセス psmopen 関数は,システムコールopen()のたびに呼ばれる

static d_close_t psmclose(dev_t dev, int flag, int fmt, struct proc *p) 返り値 正常に処理が終了: 0 エラー: 整数値 引数 flag: ファイル記述子に設定されたフラグ fmt: 文字型であることを示すS\_IFCHR p: オープンを要求したプロセス psmclose 関数は,devを参照するvノード(ファイル/ディレクトリに関する固定長の管理情報(iノード)を抽象化したもの)がなくなるときに呼ばれる (システムコールclose()が呼ばれるたびに毎回呼ばれるとは限らない)

static d_read_t psmread(dev_t dev, struct uio *uio, int flag) デバイスdevからuioで表わされる領域へデータを読み出す 返り値 正常に処理が終了:  0 エラー: 正整数値 引数 flag: IO\_NDELAYが指定される場合があるそうです psmread 関数は,システムコールread()のたびに毎回呼ばれる

システムコールioctl()の処理のために呼ばれる static d_ioctl_t psmioctl(dev_t dev, u_long cmd, caddr_t addr, int  flag, struct proc *p) システムコールioctl()の処理のために呼ばれる デバイスdevに対して,cmdとaddrで表わされる制御コマンドを適用する 返り値 正常に処理が終了: 0 エラー:   正整数値 引数 flag: ファイル記述子に設定されたフラグ システムコールioctl()の引数は,カーネルのメモリ空間にコピーされ、戻るときに必要に応じてプロセスのメモリ空間にコピーされる

マウスの状態を表わす構造体 struct psm_softc { /* Driver status information */ struct selinfo rsel; /* Process selecting for Input */ unsigned char state; /* Mouse driver state */ int config; /* driver configuration flags */ int flags; /* other flags */ KBDC kbdc; /* handle to access the keyboard controller */ struct resource *intr; /* IRQ resource */ void *ih; /* interrupt handle */ mousehw_t hw; /* hardware information */ mousemode_t mode; /* operation mode */ mousemode_t dflt_mode; /* default operation mode */

mousestatus_t status; /* accumulated mouse movement */ ringbuf_t queue; /* mouse status queue */ unsigned char ipacket[16]; /* interim input buffer */ int inputbytes; /* # of bytes in the input buffer */ int button; /* the latest button state */ int xold; /* previous absolute X position */ int yold; /* previous absolute Y position */ int watchdog; /* watchdog timer flag */ struct callout_handle callout; /* watchdog timer call out */ dev_t dev; dev_t bdev; };

struct uio( /usr/include/sys/uio.h ) 文字型の入出力の引数に使われる構造体 struct uio( /usr/include/sys/uio.h ) struct uio { struct iovec *uio_iov; /* 領域の「先頭アドレスとバイトサイズ」 */ int uio_iovcnt; /* 領域の個数 */ off_t uio_offset; /* データを詰めた/取り出したアドレス */ int uio_resid; /* 入出力するデータ数 */ enum uio_seg uio_segflg; /* 領域のアドレス空間(プロセス/カーネル) */ enum uio_rw uio_rw; /* 入力、出力の区別 */ struct proc *uio_procp; /* 使用しているプロセス */ };

・デバイスドライバでは uiomove( caddr_t cp, int n, struct uio ・デバイスドライバでは uiomove( caddr_t cp, int n, struct uio *uio )を用いて、cp から uio へ n バイトをコピー(入力の場合)、あるいは、uio からcp へ n バイトをコピー(出力の場合)を行なう ・正しくコピーできれば0が、さもなければエラーを表わす正整数が返される ・コピーの方向はuioに設定された情報をuiomove()が判断して決定され、uioのメンバーも適宜更新される。

static int psmopen(dev_t dev, int flag, int fmt, struct proc *p) { /* マウスの状態を確認し、問題があればエラーを返す。問題がなければ、マウ スの状態を初期化し、マウスがオープン状態であることを記録する。 */ int unit = PSM_UNIT(dev); struct psm_softc *sc; int command_byte; int err; int s; /* Get device data */ sc = PSM_SOFTC(unit); if ((sc == NULL) || (sc->state & PSM_VALID) == 0) return (ENXIO); /* マウスの状態を確認して問題があればENXIOを返す */ if (sc->state & PSM_OPEN) return (EBUSY); /* デバイスが既にオープンされているならばEBUSYを返す */

device_busy(devclass_get_device(psm_devclass, unit)); /* マウスの状態を初期化 */ sc->rsel.si_flags = 0; sc->rsel.si_pid = 0; sc->mode.level = sc->dflt_mode.level; sc->mode.protocol = sc->dflt_mode.protocol; sc->watchdog = FALSE; /* マウスのイベントキューをクリア */ sc->queue.count = 0; sc->queue.head = 0; sc->queue.tail = 0; sc->status.flags = 0;

sc->status.button = 0; sc->status.obutton = 0; sc->status.dx = 0; sc->status.dy = 0; sc->status.dz = 0; sc->button = 0; /* 入力バッファをクリア */ bzero(sc->ipacket, sizeof(sc->ipacket)); sc->inputbytes = 0; /* まだいろいろと処理を行なうが長いので省略 */ err = doopen(unit, command_byte);

/* done */ if (err == 0) sc->state |= PSM_OPEN; kbdc_lock(sc->kbdc, FALSE); return (err); } static int psmread(dev_t dev, struct uio *uio, int flag) { /* マウスの状態を調べて、問題があればエラーを返す。問題がなければ、マウスから(マウスが使用しているバッファから)uioにデータを読み出す */ register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev));

unsigned char buf[PSM_SMALLBUFSIZE]; int error = 0; int s; int l; /* マウスに問題があればEIOを返す */ if ((sc->state & PSM_VALID) == 0) return EIO; /* block until mouse activity occured */ s = spltty(); while (sc->queue.count <= 0) { if (PSM_NBLOCKIO(dev)) { splx(s); return EWOULDBLOCK; }

sc->state |= PSM_ASLP; error = tsleep((caddr_t) sc, PZERO | PCATCH, "psmrea", 0); sc->state &= ~PSM_ASLP; if (error) { splx(s); return error; } else if ((sc->state & PSM_VALID) == 0) { /* the device disappeared! */ return EIO; }

/* copy data to the user land */ while ((sc->queue.count > 0) && (uio->uio_resid > 0)) { /* 入力すべきデータがあるならば*/ s = spltty(); l = min(sc->queue.count, uio->uio_resid); if (l > sizeof(buf)) /* sizeof(buf)はバッファの最大値 */ l = sizeof(buf); /* キューに入っているデータをバッファにコピー */ if (l > sizeof(sc->queue.buf) - sc->queue.head) { bcopy(&sc->queue.buf[sc->queue.head], &buf[0], sizeof(sc->queue.buf) - sc->queue.head); bcopy(&sc->queue.buf[0], &buf[sizeof(sc->queue.buf) - sc->queue.head], l - (sizeof(sc->queue.buf) - sc->queue.head));

} else { bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l); } /* キューのカウントを減らし、キューの先頭を移動 */ sc->queue.count -= l; sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf); splx(s); /* 入力として受け取った構造体 uio にデータをコピー */ error = uiomove(buf, l, uio); if (error) break; return error;

static int psmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { /* マウスに対する様々な操作(マウスの情報を得る、マウスの設定をする など)を行なう。cmdで行なうコマンドを指定。*/ struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); mousemode_t mode; mousestatus_t status; #if (defined(MOUSE_GETVARS)) mousevar_t *var; #endif mousedata_t *data;

int stat[3]; int command_byte; int error = 0; int s; /* Perform IOCTL command */ switch (cmd) { case OLD_MOUSE_GETHWINFO: s = spltty(); ((old_mousehw_t *)addr)->buttons = sc->hw.buttons; ((old_mousehw_t *)addr)->iftype = sc->hw.iftype; ((old_mousehw_t *)addr)->type = sc->hw.type; ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff;

splx(s); break; case MOUSE_GETHWINFO: /* … 長いので省略 … */ case OLD_MOUSE_GETMODE: case MOUSE_GETMODE: case OLD_MOUSE_SETMODE: case MOUSE_SETMODE:

case MOUSE_GETLEVEL: /* … 長いので省略 … */ break; case MOUSE_SETLEVEL: case MOUSE_GETSTATUS: #if (defined(MOUSE_GETVARS)) case MOUSE_GETVARS: case MOUSE_SETVARS:

return ENODEV; #endif /* MOUSE_GETVARS */ case MOUSE_READSTATE: case MOUSE_READDATA: /* … 長いので省略 … */ break; #if (defined(MOUSE_SETRESOLUTION)) case MOUSE_SETRESOLUTION: #endif /* MOUSE_SETRESOLUTION */ #if (defined(MOUSE_SETRATE)) case MOUSE_SETRATE:

#endif /* MOUSE_SETRATE */ #if (defined(MOUSE_SETSCALING)) case MOUSE_SETSCALING: /* … 長いので省略 … */ break; #endif /* MOUSE_SETSCALING */ #if (defined(MOUSE_GETHWID)) case MOUSE_GETHWID:

#endif /* MOUSE_GETHWID */ default: return ENOTTY; } return error;