Archive List for デバイス操作の基本

ユーザー空間とカーネル空間

デバイスドライバを開発する場合、ユーザー空間とカーネル空間について理解しておく必要があります。 一般的なアプリケーション開発の場合、カーネル空間を意識したプログラミングは必要ありません。 しかし、デバイスドライバはカーネルの一部であるため、カーネル空間を意識したプログラミングを行わなくてはなりません。 では、ユーザー空間、カーネル空間とはそれぞれ何なのでしょう。 ユーザー空間とは、アプリケーション(OS上で動作するソフトウェア)が使用するメモリ領域のことであり、 カーネル空間とは、カーネルが使用するメモリ領域のことを指します。 つまり両者の違いは使用するメモリ領域の違いと言えます。 例えば、パソコンに4Gバイトのメモリが搭載されていたとします。 このときLinuxは、3Gバイトをユーザー空間としてアプリケーションに割り当て、残りの1Gバイトをカーネル空間としてカーネルに割り当てます。 ユーザー空間とカーネル空間はそれぞれ独立しており、互いが互いのメモリ領域に直接アクセスすることはできません。 では、何のためにメモリ領域を二つに分けるのでしょう。 カーネルはシステムの中枢であるため、カーネルが動いているメモリ領域が侵されてしまったらOSごと停止してしまいます。 例えば、アプリケーションにバグがあった場合、カーネル空間にまでその影響が及んでしまう可能性も十分あります。 しかし、メモリ領域をユーザー空間とカーネル空間に分け、互いが互いの領域にアクセスできないようにしておけば、少なくともOSごと停止してしまう事態は防ぐことができます。

デバイスファイル

デバイスファイルはデバイス(ハードウェア)をファイルとして表現したものです。 アプリケーション(ユーザー空間)とデバイスドライバ(カーネル空間)間でデータを送受信するためには、両者を結びつける「何か」が必要です。 その「何か」がデバイスファイルです。 デバイスファイルは通常、「/dev」配下に保存されており、原則ひとつのデバイスに対して、ひとつのデバイスファイルが存在します。 例えば、「/dev/hda」ファイルは1台目のIDE(ATA)ハードディスクを表しています。 「表している」とはつまり、ソフトウェア(ユーザー空間)から見れば、「/dev/hda」がIDEハードディスクあると見えるわけです。 そしてこのファイルを操作することは、IDEハードディスクを操作するということに対応します。 デバイスファイルには下記の種別が存在します。 ・ブロック型デバイス(block) ・キャラクタ型デバイス(character, unbuffered) ・名前付きパイプ(pipe) ハードディスクやUSBメモリはブロック型デバイス、プリンタやモデムはキャラクタ型デバイスに該当します。 名前付きパイプはプロセス間通信を行う際に使用するデバイスファイルです。

システムコール

システムコールについては以前の記事でも少し解説していますが、今回はもう少し掘り下げてみます。 アプリケーション(ユーザー空間)とデバイスドライバ(カーネル空間)間でデータを送受信するために、デバイスファイルを使用するということは前回の記事で解説しました。 このデバイスファイルを操作することが、デバイス(ハードウェア)を操作することにつながります。 それはつまり、デバイスファイルがデバイス(ハードウェア)を表しているということです。 では、デバイスファイルの操作はどのように行うのでしょう。 その方法が「システムコール」というわけです。 システムコールにはいくつか種類がありますが、まずは基本的な下記の4つについて考えてみます。 ・open ・close ・read ・write デバイスファイルは特殊なファイルではありますが、ファイルであることには変わりありません。 ですので、まずファイルを開いてやる必要があります。 そのためのシステムコールが「open」です。 あとはデバイスに対して何らかのデータを送ったり、受け取ったりする方法です。 「read」がデータを読み込む、つまり、デバイスから送られるデータを受け取るためのシステムコールです。 逆に「write」はデータを書き込む、つまり、デバイスにデータを送るためのシステムコールとなります。 そして最後に、用が済んだら開いていたファイルを閉じてやる必要があります。 そのためのシステムコールが「close」です。 このようにデバイス(ハードウェア)を操作してくわけです。 これらの手順は、普通のテキストファイルをプログラム上から扱うときとそっくりだということがわかります。