PR

【IT用語解説】デバイスドライバとは?OSとハードウェアをつなぐ仕組みを解説

デバイスドライバとは?をコンピュータ基礎シリーズの統一デザインで表すアイキャッチ IT-Skills

デバイスドライバとは、OSの共通的なI/O要求を、特定機器のコマンド・記述子・レジスタ操作へ変換し、完了結果やエラーをOSの共通形式へ戻すソフトウェアです。

「OSとハードウェアの橋渡し」という説明は正しい入口ですが、橋を渡るだけではありません。ドライバは要求をキューへ割り当て、機器がアクセスできるメモリアドレスを準備し、開始を通知し、割り込みまたはポーリングで完了を回収します。

この記事では、テキストエディタでmemo.txtAを追記する例を、LinuxのブロックI/OとPCIe接続のNVMe SSDを具体例として最後まで追います。NVMe固有の用語は一般原理を見える形にするための実装例であり、USB機器、GPU、ネットワークアダプターではコマンドや転送方式が異なります。

ドライバは「翻訳機」に例えられます。ただし翻訳するのは文章ではなく、操作、アドレス、キュー、完了状態です。「どこへ何バイト書く」という共通要求を、「この装置のこの形式で、ここへ並べ、開始レジスタを更新する」へ具体化します。

このページで学べる内容
  • 共通I/O要求の何を、機器固有の何へ変換するのか
  • memo.txt保存時のrequest、DMA、MMIO、doorbell、completionの往復
  • ドライバ、OSサブシステム、バス/プロトコル、コントローラ、ファームウェアの境界
  • Plug and Playで機器とドライバが結び付く仕組み
  • カーネルモード/ユーザーモード、署名、権限、クラッシュ影響
  • 互換性、更新、障害を切り分ける基準
スポンサーリンク

ドライバが変換するのは「要求」と「完了」

アプリは「NVMe Submission Queueの何番へ命令を置くか」や「どのMMIOレジスタを更新するか」を指定しません。ファイルへ書くという意味をOSへ渡し、ファイルシステムやブロック層が機器に依存しない要求を組み立てます。

ドライバへ届く共通的な情報 機器固有へ具体化する例 完了時に共通形式へ戻すもの
読み取り/書き込み等の操作 NVMe Write等のopcode 成功、再試行可能な失敗、致命的な失敗
論理ブロック範囲と長さ namespace、開始LBA、ブロック数 処理済み量、残量、エラー位置
データがあるRAM領域 DMA mapping、PRP/SGL等のデータポインタ DMA完了、mappingの解放
同期・優先度・flush等の属性 command field、queue選択、制御フラグ 装置statusをOSのエラーへ対応付け
要求を識別する情報 queue slot、command ID、tag どの待機中要求が終わったか照合

つまり、ドライバはデータ形式だけを変えるのではありません。OSが管理する要求のライフサイクルを、装置が理解するプロトコルのライフサイクルへ対応付けるのが中心です。

memo.txtの書き込みで、VFS・ファイルシステム・ブロック層の共通requestがドライバへ渡り、ドライバがtag、NVMe command descriptor、DMA mapping、Submission Queue、MMIO doorbellへ変換し、コントローラとファームウェアがDMAでRAMからデータを取得して媒体へ書き、Completion QueueとMSI-Xまたはpollingで完了・エラーがドライバへ戻り、OSの共通completionへ変換される往復を示す図
制御経路はrequest→descriptor→doorbell、データ経路はDMA、完了経路はCompletion Queue→interrupt/pollingです。ドライバは三つを対応付けます。

memo.txtのAがSSDへ届くまで

ここでは、ページキャッシュ上の変更をストレージへ書き戻す段階から見ます。保存ボタン、write成功、媒体への永続化は同じ時点ではありません。この前段はファイルシステムとは、待ちとflushの境界はバッファとはで詳しく説明しています。

1. VFS・ファイルシステム・ブロック層が共通requestを作る

テキストエディタはシステムコールの入口からOSへ書き込みを依頼します。VFSとファイルシステムはパス、開いたファイル、権限、論理オフセット、ファイルシステム上の割り当てを扱います。その結果、ストレージへ必要な論理ブロック範囲とデータのあるメモリ領域がI/O要求になります。

Linuxのblk-mqでは、bioからブロックドライバへ渡すstruct requestが作られ、ソフトウェア側キューとハードウェアdispatch queueで管理されます。この段階の「write request」は、NVMeやSATAの細かな命令形式にはまだ依存しない共通モデルです。

2. ドライバがqueue・tag・command descriptorを割り当てる

ブロック層がNVMeドライバのqueue_rq相当を呼ぶと、ドライバは空いているqueue slotとtagを確保し、共通requestからNVMe Write commandを作ります。開始LBA、ブロック数、namespace、command ID、制御フラグなどを、NVMe仕様で定められたcommand entryへ配置します。

tagやcommand IDが重要なのは、複数の要求を同時に進め、完了順が投入順と異なっても、どのOS requestが終わったかを特定するためです。NVMe仕様でも、commandは順不同で完了し得ると定められています。

3. DMA mappingで「装置から見えるRAMの住所」を作る

CPUが使う仮想アドレスを、そのままPCIe装置が使えるとは限りません。ドライバはOSのDMA APIへRAM領域を渡し、IOMMU等で必要な対応付けを作り、装置が使うDMA addressを受け取ります。NVMe commandにはPRPやSGLのようなデータポインタとして、この転送先情報を載せます。

ここでの重要点は、ドライバが毎回CPUでデータ本体を装置へコピーするとは限らないことです。ドライバは主に転送可能な領域とアドレスを準備し、DMA engineを持つコントローラがRAMと装置の間でデータを転送します。CPUは設定と完了処理を担います。

DMAは「装置がどこへでも自由にアクセスする」仕組みではありません。 OSとIOMMUは、必要な期間・方向・範囲だけをmappingすることで、装置が利用できるメモリを制御します。mapping失敗や同期規則をドライバが誤ると、データ破損やセキュリティ問題になり得ます。

4. commandをSubmission Queueへ置き、doorbellを鳴らす

PCIe接続NVMeでは、Submission QueueとCompletion Queueはホストからアクセスできるメモリ上に置かれます。ドライバはcommand entryをSubmission Queueへ書き、必要な順序を保証したうえで、MMIOのSubmission Queue Tail Doorbellレジスタを更新します。

doorbellはデータ本体ではなく、「queueのtailがここまで進み、新しいcommandがある」ことをコントローラへ知らせる制御信号です。Linuxでは、機器のMMIOレジスタへアクセスするためにioremapreadlwritel等のAPIが使われます。バスの順序規則があるため、普通のメモリ変数と同じ書き方では扱えません。

5. コントローラとファームウェアがcommandを実行する

NVMeコントローラはdoorbellの更新を知るとSubmission Queueからcommandを取得し、DMAでRAM上のデータを読み、装置内部で処理します。SSDのファームウェアはコントローラ内のプロセッサ等で動き、論理ブロックをNAND上の配置へ対応付け、誤り訂正、ウェアレベリング、ガベージコレクションなどを制御します。

ドライバがNANDセルへ直接電荷を書き込むわけではありません。ドライバはホスト側でNVMeという公開インターフェースを扱い、コントローラとファームウェアが装置内部の詳細を扱います。物理的な保持原理はストレージとはへ分離します。

6. Completion Queueへstatusが書かれ、割り込みまたはpollingで回収する

commandが完了すると、コントローラは対応するCompletion Queueへcompletion entryを書きます。そこには、どのSubmission Queue・command IDに対応するか、成功かエラーか、といったstatusが入ります。

コントローラはMSI-X等の割り込みで「新しいcompletionがある」とCPUへ通知できます。ただし、割り込みをまとめるcoalescingや、ドライバがqueueを能動的に確認するpollingを使う場合もあり、1要求につき必ず1割り込みとは限りません。

7. ドライバが装置statusをOSのcompletionへ戻す

ドライバはcompletion entryのqueue IDとcommand ID/tagから元のrequestを特定し、DMA mappingやqueue slotを解放します。装置固有statusを、成功、I/O error、timeout、再試行、媒体エラー等のOS側statusへ対応付け、ブロック層へ完了を返します。

その上でファイルシステムや待機中の処理が完了を受け取ります。ページキャッシュを使う通常の書き込みでは、アプリのwriteがこの媒体I/Oより前に成功している場合があります。一方、同期的な永続化要求なら、この下位completionを待つ経路が重要になります。

境界 渡すもの その時点でまだ終わっていないこと
ファイルシステム → ブロック層 論理ブロック範囲、RAM上のデータ、I/O属性 機器固有commandの作成
ブロック層 → ドライバ 共通requestとqueue情報 DMA mapping、descriptor、MMIO通知
ドライバ → コントローラ Submission Queue entry、DMA address、doorbell command実行、媒体反映
コントローラ → ドライバ Completion Queue entry、status、interrupt等 OS requestへの対応付け、上位への完了
ドライバ → ブロック層 共通status、処理済み量、解放可能な資源 ファイルシステム・アプリへの最終通知

5つの境界を混ぜない

「ハードウェア側」という一言には、異なる役割が含まれます。境界を分けると、ドライバがどこまで担当するかが見えます。

構成要素 中心役割 NVMe SSDの例 担当しないことの例
OSサブシステム 機器に依存しない抽象化、保護、共有、要求管理 VFS、ファイルシステム、page cache、block layer 個別SSDのdoorbell形式
デバイスドライバ 共通requestと機器固有protocolの対応付け NVMe command作成、DMA mapping、queue、MMIO、completion処理 ファイル名のパス探索、NANDセル配置の内部アルゴリズム
バス/プロトコル 接続、列挙、アドレス、転送、順序、command形式の規則 PCIe transport、NVMe command set 特定OSでのrequest lifecycle
デバイスコントローラ host commandを受け、DMA engineや媒体制御回路を動かす Submission Queue取得、DMA、Completion Queue更新 OSのファイル権限判断
ファームウェア 機器内部のプロセッサ等で制御ロジックを実行 FTL、誤り訂正、ウェアレベリング、回復処理 Windows/Linuxのdriver API実装

ドライバとファームウェアは協調しますが、同じものではありません。ドライバは通常ホストOS側、ファームウェアは通常デバイス内部で動きます。両者のversionや機能交渉が合わなければ、認識はしても一部機能が使えない、復帰に失敗する、timeoutになる、といった問題が起き得ます。

Plug and Playは「ID照合 → 初期化 → 資源割り当て」

機器を接続すると、まずPCIe、USB等のバス側が機器を列挙し、device ID、compatible ID、MMIO範囲、interrupt等の資源情報をOSへ知らせます。OSは、そのIDをサポートすると宣言するドライバを探します。

Linuxのdriver modelでは、bus固有のmatchでdevice IDとdriverの対応を調べ、一致するとdriverのprobeを呼びます。probeは実機を確認し、deviceを有効化し、MMIOをmapし、DMA条件を設定し、queueやinterrupt handlerを準備します。成功して初めてdeviceとdriverがbindされます。

Windowsでも、機器が報告したhardware ID/compatible IDとdriver packageのINFを照合します。候補が複数あると、署名、機能、IDの一致度等を含むrankが優先され、同rankなら日付・versionが比較されます。単にversion番号が最大のdriverを無条件で選ぶわけではありません。

専用driverが常に必要とは限りません。 USB mass storage、HID、標準NVMe等の共通仕様に準拠する機器は、OS標準のclass/in-box driverで動く場合があります。機器差を標準protocolへ押し込めるほど、1つのdriverで多くの製品を扱えます。

すべてのドライバがカーネルモードとは限らない

MMIO、DMA、interrupt、電源管理などへ直接関わる低水準driverは、強い権限と短い応答時間が必要なためkernel modeで動くことが多いです。しかし、「driver=必ずkernel mode」ではありません。

Windows Driver FrameworksにはKMDF(Kernel-Mode Driver Framework)とUMDF(User-Mode Driver Framework)があります。UMDF driverはdriver host processで動き、I/O requestやPlug and Play通知を受けます。必要ならkernel mode部分とuser mode部分に分ける構成も可能です。

観点 カーネルモードdriver ユーザーモードdriver
アクセス範囲 OS内部資源や低水準hardware機能へ広くアクセスできる frameworkが許可するinterfaceとuser spaceの範囲が中心
障害影響 不正なmemory accessでOS全体をcrashさせ得る 主にdriver host processの失敗として隔離・再起動できる場合がある
向く処理 boot、厳しいlatency、直接interrupt/DMA等が必要な処理 frameworkで扱えるUSB等、隔離を優先できる処理
代償 権限と障害範囲が大きい 使える機能や対象deviceに制約があり、遷移のoverheadもある

Microsoftの公式説明では、kernel mode codeはOSや他driverと同じvirtual address spaceを共有するため、誤ったaddressへの書き込みやcrashがOS全体へ影響します。UMDFではdriver failureを検出し、device stackを再構築してdriverを再起動または無効化する仕組みがあります。

署名・権限・互換性は別々に確認する

署名は「出所と改ざん検出」であり、無欠陥の保証ではない

driverは高い権限で動く場合があるため、OSはdriver packageの署名と信頼経路を確認します。現在のWindowsでは、新しいkernel-mode driverをloadする際にMicrosoftの署名policyが適用されます。

ただし、正しく署名されたdriverにもbugや脆弱性はあり得ます。署名は主に発行者・配布経路・改ざんを検証する材料であり、性能向上、完全な安全性、対象deviceへの最適性を自動的に保証しません。

権限が大きいのは、機器がmemoryとOS状態へ影響できるから

DMA対応deviceは、設定されたaddressへCPUを介さずアクセスできます。driverがmapping範囲、転送方向、lifetime、cache同期を誤れば、別データの破壊や漏えいにつながります。MMIO registerの誤操作も、device停止、誤転送、interrupt storm等を起こし得ます。

互換性はdevice IDだけでは決まらない

確認軸 合わないと起きること
device/compatible ID driver候補にならない、誤った機能前提で初期化に失敗する
OS、kernel、driver framework、ABI load失敗、symbol不一致、callback contract不一致
CPU architecture x64 binaryをArm64でloadできない等
driverとfirmwareのversion/feature commandやpower stateの解釈が合わずtimeout・機能欠落
署名policyとboot security OSがloadを拒否する
他のfilter/class/bus driver stack内の順序・interface・resource競合

とくにLinuxのkernel内部interfaceは、userspace ABIとは異なり、すべてのversionで安定したbinary driver ABIを提供する設計ではありません。配布kernel外で作られたbinary moduleは、kernel更新に合わせた再buildや提供元の対応が必要な場合があります。

不明な配布元のdriverや、署名確認を回避する手順を安易に使わないでください。 device名が似ているだけでは適合しません。hardware ID、OS build/kernel、architecture、release note、復旧方法を確認し、OSや機器メーカーの正規経路を優先します。

driver更新で必ず速くなるわけではない

driver更新の目的は、性能向上だけではありません。脆弱性修正、crash修正、新しいOSへの対応、新device IDの追加、power management改善、既知の回避策、telemetry改善などがあります。

性能が変わるのは、driverのqueueing、interrupt coalescing、DMA、offload、error recovery等が実際のbottleneckだった場合です。CPU、bus帯域、controller、媒体、filesystem、applicationが律速なら、driver更新だけで速くなるとは限りません。新versionが特定環境でregressionを起こす可能性もあります。

更新前 更新後
変更理由と対象不具合をrelease noteで確認 device認識、error log、sleep復帰、I/O timeoutを確認
hardware ID、OS、architecture、firmware条件を確認 必要なworkloadでlatency・throughput・CPU使用率を比較
正規packageと署名を確認 新しいwarning、drop、retry、resetが増えていないか確認
旧版、復元点、rescue手段を確保 問題時はrollbackし、firmwareやhardwareも切り分ける

機器が動かないときは、往路と復路を分けて見る

「driverの問題」と一括りにせず、要求がどこまで進み、completionがどこで止まったかを確認します。

観測地点 典型的な症状 確認するもの
列挙・matching device自体が一覧に出ない、unknown device 電源、接続、bus、device ID、INF/ID table
probe・初期化 認識するがdriver bind失敗 MMIO resource、DMA mask、firmware load、interrupt割当
request queue I/O開始後に待ちが増える queue depth、resource不足、timeout、backpressure
DMA・MMIO data corruption、IOMMU fault、commandが始まらない mapping方向・範囲・lifetime、doorbell、memory ordering
controller/media completionにdevice error、resetが続く SMART/health、firmware、温度、媒体、電源
interrupt/polling deviceは処理したのにOSがtimeout MSI-X vector、interrupt mask、completion queue、poll path
error mapping・上位層 原因が曖昧なI/O errorとして見える driver log、kernel event、block/filesystem log

WindowsではDevice Managerのhardware ID、driver provider/version、status code、Event Viewerが入口です。Linuxではlspci -klsusbでdeviceと使用中driverを確認し、dmesgやjournalでprobe、IOMMU、timeout、reset、I/O errorを探します。管理者権限や追加toolが必要な場合があります。

よくある誤解を仕組みから直す

誤解 正しい捉え方
driverがdataを必ずCPUでdeviceへcopyする driverはDMA mappingとdescriptorを準備し、controllerがRAMとの転送を行う場合が多い。PIOやbounce buffer等の例外もある
すべてのdriverがkernel modeで動く 低水準driverはkernel modeが多いが、UMDF等のuser-mode driverや分割構成もある
driverとfirmwareは同じもの driverは主にhost OS側、firmwareは主にdevice内部。公開protocolを境界に協調する
driver更新は新しいほど必ず速い 目的はsecurity、bug、compatibility、power等もある。bottleneckがdriverでなければ性能は変わらず、regressionもあり得る
doorbellを書けばdata保存完了 doorbellは新しいcommandをcontrollerへ知らせるだけ。その後にDMA、実行、media処理、completionがある
1 requestごとに必ずinterruptが来る MSI-X等を使えるが、interrupt coalescingやpollingもある。completion queueの確認が本体
OSは最もversion番号が大きいdriverを選ぶ まずdevice IDの一致度、署名、機能等で候補をrank付けし、同rank等の条件で日付・versionを比較する
署名済みならbugも脆弱性もない 署名は出所・改ざん・load policyの材料。code品質や対象環境での正しさを保証しない

まとめ:driverは要求と完了の対応表を実機へつなぐ

  • driverはOSの共通requestを、機器固有command、descriptor、queue、register操作へ変換する
  • memo.txtの保存では、block requestからNVMe commandを作り、DMA addressを準備し、Submission Queueとdoorbellでcontrollerへ渡す
  • data本体はcontrollerがDMAでRAMと転送でき、driverがCPUで毎回copyするとは限らない
  • controller/firmwareがcommandを実行し、Completion Queueとinterrupt/pollingでstatusを返す
  • driverはtagで元requestを特定し、device固有errorをOS共通statusへ戻す
  • OS subsystem、driver、bus/protocol、controller、firmwareは別の責任境界
  • device ID matchingとprobeでbindし、kernel/user mode、署名、ABI、firmware compatibilityを確認する

デバイスドライバの本質は、OSと機器の間に存在することではなく、両側の「要求の表し方」と「完了の表し方」を対応付けることです。memo.txtAについて、共通requestをcommandへ変え、RAMをDMA可能にし、doorbellで開始を知らせ、completionを元requestへ戻せれば、「橋渡し」の中身を説明できます。

関連する基礎用語

タイトルとURLをコピーしました