80286 - プロテクト・モードの特権と例外処理
80286のプロテクト・モードでは、タスクごとにアドレス空間が分離され、他のタスクのメモリは原則として読み書きすることが出来ません。とはいえOSに対してもデータをやり取りすることが必要になりますし、他のプログラム(タスク)とデータを共有したいこともあります。
そこでタスクの間で同じメモリを共有する方法が提供されているのですが、タスクはどれも平等ではありません。OSを実行しているタスクがもっとも強く、一般のプログラムが走るタスクはもっとも弱い権限で動作しています。このようにしないと自由にOSが使っているメモリを書き換えるなどしてOSを破壊することが出来てしまうので、わざわざメモリを保護する機構を使うことに意味がなくなってしまいます。
タスクとメモリにはそれぞれ権限が割り当てられており、タスクから見えるメモリについても、より強い権限を持つアドレスについては自動的にチェックを受ける仕組みが用意されています。
まずメモリについてですが、セレクタ(セグメント)の下位3ビットに権限が書かれていて、このセレクタ経由でアクセスされるメモリについては、この権限「以上」のタスクである必要があります。
80286のプロテクトモード - 仮想アドレスから実アドレスに変換する仕組み
またタスクについてはTR(タスクレジスタ)にタスクの権限が設定されます。
80286のプロテクトモード - タスクって何?
権限は2ビットで表されており、最も高い権限が0、低い権限が3になります。一般的にOSが0を使い、一般のプログラムは3です。1と2をどう使うかはOSの実装次第なのですが、デバイスドライバに割り当てられることもあるようです。またメモリの権限はセレクタ単位なので、64Kを超えるメモリを共有するには複数のセレクタが必要です。
そして、この権限を跨いで処理をさせる場合にいろいろなゲートという仕組みがあって、それを経由してアクセスしたり呼び出したりすることで、そこでいろいろなチェックを受けた後に他のタスクのメモリを読み書きしたり、コードを実行する仕組みも備えています。
具体的にどのようにタスクを跨ぐのかに関しては、OSが動作している状態では自分の書いたプログラムは低い権限しか持たないので、コードを書いても実行させてもらえませんし、デバッガなどでメモリの内容を覗き見ることもママなりません。
実際にこの仕組みの影響がわかるのが、自分の書いたコードが割り当てられていない、権限のない不正なメモリを読み書きしようとしたり、CALL や JMP で実行しようとした時に、例外が発生してプログラムが停止する場合です。
割り込みや例外についても、プロテクト・モードではタスクをまたぐゲートを活用した形で処理されます。
IDT(Interrupt Discpritor Table)に割り込み番号あたり8バイトのテーブルを並べ、このテーブルの先頭アドレスを IDTR に設定しておきます。テーブルに設定されるアドレスはプロテクト・モードなので、単なるアドレスではなく処理するコードが存在するセレクタやアクセス権なども必要です。ここで使われる割り込み番号はリアルモード時代と同じ除算エラー(0)や無効命令コード(6)もありますが、プロテクト・モード固有の無効TSS(10)や、そして皆さんおなじみの一般保護違反(13)などが追加されています。
こうして割り込みや例外が発生すると、その時に実行していたタスクは中断されてこれらのテーブルに登録されたコードに制御が移ります。この時にタスクの権限が変更されるか、割り込みや例外の種類によて微妙にスタックに何が積まれるかが異なるのですが、ここで必要な処理を行い IRET 命令で元のコードに戻り、可能であれば処理が継続されるようになっています。もちろん処理が継続できない場合には割り込み処理のコードによって元のタスクを終了させたり再起動したりするようにします。継続する場合には元のプログラムは割り込みがあったことなどそしらぬ顔で処理を続けることができるわけです。
このようなプロテクト・モードの実装はある意味で UNIX が誕生するキッカケとなった MULTICS の影響を受けているようでなかなか複雑なものですが、マイコンであっても仮想アドレスを持ち仮想メモリを扱えタスクという処理の単位を持ち、マルチタスクをサポートしバグのあるプログラムがあってもシステム全体に影響を与えない信頼性のあるシステムを構築するようになったのです。
Multics
もっとも、この代償はそれなりにあって、当時のCPUの能力に於いてはハードウェアで実行するにしてもやや時間のかかるもので、さらに64Kまでしか扱えないセグメントベースのメモリ管理は煩雑なものでした。そして、この機能をサポートしたOSがあってこそなのですが、今までに蓄積したリアルモードで動作するコードと決別する必要があり、いろいろな挑戦があったものの普及することはありませんでした。これらの問題を解決するにはさらに高性能で32ビットアドレスを扱える80386の登場を待つ必要がありました。
【補足】
自作のCPU基板でプロテクト・モードのプログラミングにトライされている方がいらっしゃいました。凄い!
80286 protected mode assembly programming
ヘッダ画像は、AIに頑張ってもらいました。
#CPU #16ビット #インテル #80286 #プロテクト・モード #割り込み #例外 #一般保護違反 #タスク #セグメント #特権