I/O デバイスの具体例は、USB・Disk (SSD等)・Printer・キーバード・マウスなどです。
Linux カーネルの機能 | |||
---|---|---|---|
I/O デバイスの種類
I/O デバイスは次の2種類があります。
- キャラクターデバイス
- ブロックデバイス
キャラクターデバイスの具体例は、キーボード、マウス、tty などです。
通常、キャラクターデバイスは「ランダムアクセス」や「バッファ」をサポートしておらず、ストリーム処理となります。(すでに読み書きしたデータに戻れず、再度デバイスから入力する必要がある)
Linux では、デバイスをファイルとして扱い、キャラクターデバイスのシンボルは c となります。
crw-rw-rw- 1 root tty 5, 0 7月 21 21:03 /dev/tty
ブロックデバイスの具体例は、SSD、USBメモリ、CD などです。
ブロックデバイスは、以下の特徴を持ちます。
- メモリバッファをサポートしているので、1バイトより大きなデータを転送可能
- アドレスを指定可能なため、ランダムアクセス、シーケンシャルアクセスが可能
Linux では、デバイスをファイルとして扱い、ブロックデバイスのシンボルは b となります。
brw-rw---- 1 root disk 259, 1 7月 21 21:03 /dev/nvme0n1
ドライバーとコントローラー
I/O デバイスを処理する際には、以下の2つを利用します。
- デバイスドライバー (Kernel 側)
- デバイスコントローラー (I/O デバイス側)
I/O デバイスごとに、対応するデバイスドライバーをプラグインとして後から追加できます。
デバイスドライバーが必要な理由
デバイスドライバーはデバイスごとに差異を吸収するため、プログラマーは特定のデバイス専用のプログラムを書かずに済みます。
例:A 社の SSD も、B 社の SSD も write() で書き込み可能となります
デバイスコントローラーは、I/O デバイスに組み込まれた小さな CPU と理解して問題ないです。
コントローラーとデバイスの通信
コンピュータに接続された全てのデバイスコントローラーは、共通のバスを経由してデバイスドライバーと通信します。
CPU と I/O デバイスの通信
CPU が I/O デバイスとデータをやりとりする方法は次の2つです。
- Programmed I/O
- Direct memory access (DMA)
Programmed I/O は、CPU 上で実行しているプログラムが I/O 操作をする時に使用します。
Programmed I/O は次の2つの方式があります。
- port-mapped I/O
- Memory-mapped I/O
インテル x86 の CPU はこちらの方式を使います。
インテル x86 には、IN 命令と OUT 命令が用意されているので、こちらを使います。
モトローラの CPU はこちらの方式を使います。
メモリアドレス空間の一部を I/O デバイスに割り当てることで、I/O デバイスへアクセスします。
CPU は、以下の手順で I/O デバイスやメモリにデータの読み書きを行います。(参考1、参考2)
- I/O デバイスやメモリのデバイスコントローラーは、アドレスバスを監視
- アドレスバスのアドレスが自分にマッピングされている場合、コントロールバスを確認
- コントロールバスの値に応じて次の処理
- 読み込みの場合:データバスのデータを取り込む
- 書き込みの場合:データバスにデータを流す
DMA は I/O 処理を、CPU の代わりにデバイスコントローラーに任せます。
これは、I/O 処理の度に CPU が割り込まれると、他の処理ができなくなるためです。
現代では、CPU は中央演算装置という位置付けで、DMA を経由して各コントローラーに指示し、実際の I/O 処理は各コントローラーで行います。
DMA は次のように動作します (参考)。CPU が関与するのは開始と終了時のみです。
- CPU が DMA Controller に I/O 処理を依頼(開始アドレス、バイト数、Read/Write を指定)
- DMA Controller が I/O デバイスコントローラーに転送準備 OK なことを通知
- データを送信:I/O デバイスコントローラー --(送信)--> DMA Controller --(転送)--> メモリ
- メモリにすべてのデータを転送すると、DMA Controller が CPU に通知
I/O デバイスの入力の検出方法
CPU は I/O デバイスの入力を検出する方法は次の2つです。
- Polling I/O
- Interrupts I/O
I/O デバイスが処理待ちをして無い場合は、CPU の時間を無駄に使うため非効率な方式です
CPU は割り込み要求を受信した時、現在のプロセスを保存し、I/O デバイスの処理を行います。
I/O デバイスの処理が完了すると、CPU は保存したプロセスの処理を再開します。
アプリケーションと I/O デバイスの通信
ユーザーアプリケーションと I/O デバイスの通信は、以下のとおりです。
- User I/O Libraries(stdio等) でシステムコールを呼び出す
- システムコール(write等)でデバイスドライバーを呼び出す(Kernelモードへ)
- デバイスドライバーがバイトブロックをデバイスコントローラーに送信(Hardwareへ)
- デバイスコントローラーがバイトブロックをシリアルビットストリームに変換
- シリアルビットストリームを元にデバイスが処理を行う
カーネル I/O サブシステム
カーネルは I/O 処理に関連する以下の機能を持ちます。
機能 | 説明 |
---|---|
スケジューリング | プロセスが I/O リクエストがデバイスを使う順番を決める |
キャッシング | メモリにキャッシュする I/O データを決める |
バッファリング | 異なるデバイス間でデータをやりとりするためにメモリに一時的にデータを保管 |
スプーリング | 低速なデバイスを利用する場合はスプーリングファイルに一時的にデータを溜める |
エラーハンドリング | 保護されたメモリ領域へアクセスした場合のエラーハンドリング |
関連情報
Linux カーネルの機能 | |||
---|---|---|---|