SSブログ

OS/2第4回仮想記憶(その2)編集部のページ(月刊ASCII 1988年5月号7) [月刊アスキー廃棄(スクラップ)]

連載「OS/2がやってきた」第4回「仮想記憶」のスクラップの続き。

プロテクトモードでのセグメントレジスタの扱い
 図2からもわかるように,プロテクトモードでのセグメントレジスタは,8086やリアルモードのように,セグメントの主記憶アドレスを直接指し示していない.そのため,その扱い方が従来の方法とは大きく異なることになる.
 すなわち,セグメントレジスタには,ディスクリプタテーブル内のセグメントディスクリプタを指し示すセグメントセレクタが格納されているのである.
 このため,プログラムからセグメントレジスタを直接操作して,セグメントの異なるメモリをアクセスするようなことはできなくなる.
 プロテクトモードで,リアルモードと同様なセグメントレジスタの操作を実現するには,そのセグメントを定義するセグメントディスクリプタの内容を操作しなければならないことになる.
 したがって,プロテクトモードで走行するアプリケーションプログラムが,直接セグメントレジスタの値に対して,加減乗除などの操作を加えた場合,その値は意味のないものになる危険性が非常に高い.もし,操作した場合,80286の保護機能が働き,結果としてOS/2によりそのプロセスは異常終了させられることになる可能性が高い(操作した段階では何も起こらないが,そのセグメントレジスタを使用して,何らかのメモリアクセスを行ったときにエラーとして検出される).

ASCII1988(05)c04OS/2_図2_W702.jpg
思い出せばリアルモードのプログラムしか作ってなかった。それは、プロテクトモードでは遅くなるからで、シングルユーザでシングルタスクのプログラムではプロテクトモードはいらなかった。「いいから、だまって俺にリニアな1Mのメモリを寄こせ」が望みだった。
セグメントのスワッピング
 仮想記憶システムにおいて,主記憶よりも大きな仮想アドレス(仮想空間)を持つプログラムを実行すると,当然,主記憶に入りきらないセグメントが発生する.また,同時に実行されているプログラム(タスク:OS/2ではプロセス)の数が多いときには,サイズの小さいプログラムさえも主記憶に読み込めない場合があり得る.プロテクトモードで実行されるプログラムは,実行時にすべてのセグメントが,主記憶に存在するとは限らず,主記憶に入りきらないセグメントは,コピーが二次記憶装置に置かれる.しかし,二次記憶装置上のセグメントがコードセグメントであれば,そのプログラムは実行できないという問題が発生する.
 仮想記憶システムは,この問題を「セグメントのスワップ」という方法を用いて解決する.2つの記憶装置の間で,必要なセグメントと不必要なセグメントの交換(スワップ)を行うのである.
 セグメントのスワップの基本的な動作は,次のように説明できる.
(1) 実行中のアプリケーションプログラムが,もし主記憶上に存在しない仮想空間上のデータセグメント,あるいは、コードセグメントにアクセスすると,80286のアドレス変換が失敗し,OS/2に対してセグメントが主記憶に存在しないことが(割り込みによって)通知される.
(2) 0S/2は,二次記憶上にある目的のセグメントを主記憶に読み込んだ後(スワップイン:図4-1),再びそのプログラムの実行を再開する.
(3) このとき,二次記憶装置上のセグメントを読み込むだけの大きさの領域が,主記憶にないときは,その時点で一番使用頻度の少ないと思われる主記憶上のセグメントを必要サイズ分だけ二次記憶装置に書き出した後(スワップアウト:図4-2),スワップアウトを行った主記憶領域に二次記憶装置から,目的のセグメントをロードする.
 こうして,主記憶より大きなプログラムの実行が可能になるのである.このような動作を,アプリケーションプログラムの見えないところで,高速に行うことによって,アプリケーションプログラムは,仮想空間と同じサイズの主記憶が,あたかも存在するかのように動作することが可能になる.また,オペレータが,システムのこのようなセグメントのスワップ処理をほとんど意識することはない.
 スワップ処理をOS/2が実現するために必要となる情報のうち,必要なセグメントが主記憶に存在するかどうかは,アプリケーションプログラムがそのセグメントをアクセスしたときに,80286のメモリ管理機能を借りて知ることができる(OS/2が,スワップイン/スワップアウト時に,そのセグメントディスクリプタのPビットをクリアしておけば,アドレス変換時にセグメントが主記憶にないことを知らせる割り込みが起こる).また,使用頻度が高いか低いかは、セグメントディスクリプタのAビットで指定することが可能である(図3参照).

ASCII1988(05)c05OS/2_図3_W737.jpg
ASCII1988(05)c05OS/2_図4-1_4-2_W747.jpg
今32Gのメモリを積んで思うことは、仮想記憶はもはや必要ないのではないかと。メモリが4G,8Gとか積みだしたとき、メモリが余っているのでキャッシュメモリになっていた。ハードウエアが貧弱な時プログラムでそれをカバーしようとしてプログラマは知恵を絞ってきたが、なんか無駄な努力のような気もする。私は、とにかく高速にと無い知恵を絞り趣味のプログラミングをしてきて知人に速いだろうと自慢していたが、数年でその努力は無駄だと思わせるほどCPUは速くなった。もっと違う努力をすべきだったと後悔している。
保護機能(プロテクト)
 仮想記憶装置のほかに,仮想記憶システムには、もうひとつの重要な機能である保護機能がある.
 この保護機能は,特に開発システムなどにおいては有効であると言える.
 開発中のプログラムに,バグが入り込むことは避けがたい問題であり、どんなときでも設計者の意図しない誤動作が発生することを覚悟しなければならない.
 このように開発に使用されるシステムでは,プログラムの誤動作によって、システムが破壊されることを防ぐ必要がある.そのために必要となるのが「保護機能」である。
 具体的には,メモリのアクセスやプログラムの走行モードなどにいくつかの規則を設けて,その規則に違反する動作を検出する機能である.この保護機能も,仮想記憶機能と同様に80286自身の機能とOS/2が密接に結び付いて次のように実現される.
 80286は,メモリアクセスに対する規則や,プログラムの特権レベルの規則などに従って,実行中の命令の動作を検査する.もし規則違反が検出されたとき,プログラムの実行を中断して、OS/2の保護違反(注4)を処理する処理ルーチンに制御を渡す.OS/2の処理ルーチンでは、違反を起こしたプログラムを異常終了させるなどの処理を行い,その原因をシステムから排除する。
注4
「保護違反」

 実際には,80286がOS/2を直接意識しているのではなく,実行中の命令の保護違反を検出したことによる80286の“割り込み動作”の結果として,その保護違反に該当する“割り込み処|理”が起動されることになる.この割り込み処理に,OS/2の保護違反のための処理ルーチンが登録されているのである.
 以上のようにして実現されるOS/2の保護機能には,大きく次の2つがある.
 ・セグメントタイプによる保護
 ・アプリケーションプログラムとシステムプログラムの隔離
 以下,この2つについて解説する.
セグメントタイプによる保護

 アプリケーションプログラムは,起動-時(ローディング時)に,各セグメントに対して、書き込み許可,読み出し許可などのアクセス方法が属性として与えられる.これらの属性は,80286がアドレス変換のときに使用するセグメントディスクリプタ内のタイプフィールドに設定される.このタイプフィールドのセグメント属性を使用して,80286はアドレス変換のたびに,その命令によるメモリアクセスが属性と整合しているかを検査する.検査されるセグメント属性には,
 ・書き込み許可
 ・読み込み許可
 ・実行可能
 ・実行不可
 ・下位伸長
 ・上位伸長
などがあり,それぞれのセグメントに対して,それぞれの規則に違反するような命令を実行した場合には命令の実行が中断され,その旨がOS/2に通知される.
 セグメント属性のうち,上位伸長属性とは,ローカルヒープなどのアドレスが上昇方向に伸びて行くセグメントのことを言い,下位伸長属性とは,スタックなどのアドレスが下降方向に伸びるセグメントの属性のことを言う.
 これらの属性を使用して,読み書きに対する保護のほかに,アクセスに使用したオフセットがセグメントからはみ出していないかの検査がセグメントディスクリプタのリミットフィールドを使用して行われる。
 OS/2において,複数のプロセスから共用されるコードセグメントは、書き込み禁止,読み出し可能属性が与えられ,主記憶に常駐するプログラムの命令コードは、他のプロセスからいつでも再利用することが可能になる.
 したがって,命令コードを変更しながら走行するプログラムは,プロテクトモードでは実行できないことになる.
 データセグメントには,リアルモードと同様,書き込み,読み出しともに許可属性が付与される.
アプリケーションプログラムとシステムプログラムの隔離

 80286には,セグメントタイプによる保護のほかに,システムの信頼性を上げるため,重要なシステムプログラムをアプリケーションプログラムの誤動作などから守る「リングプロテクション機能」がある.
 セグメントの属性による保護が,不正なメモリアクセスを検出するためのものであるのに対して,このリングプロテクションは,さらにシステムの構成を変更する重要な命令の実行や,重要なシステムコード,あるいはデータへのアクセスを制限するために使用される.
 言い換えれば,セグメントタイプの検査によって,メモリアクセスに対する水平方向の保護を実現し,このリングプロテクションでメモリセグメントに特権レベルを付加する階層的な垂直方向の保護を実現していることになる.このリングプロテクション機能によって、OS/2のもとで実行されるアプリケーションプログラムは、MS-DOSにおいて可能だったシステム領域の参照や変更,あるいは,-不正な割り込みベクトルの横取りなどが禁止されることになる.
 しかし,すべてのアクセスが禁止されるわけではなく,システムが許した正当な手段(例えば,コールゲート:後述)を使用することで,システムプログラムに対して,柔軟なアクセスが可能になるのも,リングプロテクションの特徴である.
 
保護リング

 リングプロテクションの基本的な考え方は,主記憶に配置されるセグメントに,それぞれリング番号と呼ばれる番号を与え,同一番号をもつセグメント間でひとつの「保護リング」を形成し,その保護リングに付けられた番号の大小関係によって、アクセスを制御するというものである(図5).
 80286では、0~3の4つのレベルをもつ保護リングが設定され,プロテクトモードで実行されるプログラムは,必ず何れかの保護リングのなかで実行される.リング番号0で実行されるプログラムが一番高い特権レベルを持つ,もっとも信頼性の高いプログラムである.そしてリング番号が大きくなるほど特権レベルが「低くなる。
 すなわち,特権レベルの低いリング番号をもつセグメントで実行されるプログラムは,より高いレベル番号の保護リング内にあるセグメントに対しては,データを読み出すことも書き込むこともできない.
 逆に,高いリング番号を持つセグメントからは,低いリング番号のセグメントに対して自由にアクセスが許される.
 OS/2は,この仕組みを利用して,自分自身をリング0で実行し,アプリケーションプログラムをもっとも低い特権レベル(リング3)で実行することにより,アプリケーションプログラムの不正なアクセスによる破壊から,自分自身を保護している.デバイスドライバは,アプリケーションプログラムよりも少し高い保護リングで実行される.
 各セグメントのリング番号は、やはり,セグメントディスクリプタ内に保持される.
コールゲート

 リングプロテクションの結果,もっと「も特権レベルの低いリング3で実行されるアプリケーションプログラムは通常の場合,自分自身の仮想空間内にある同レベルのメモリセグメントにしかアクセスできない。
 しかし,より高いレベルのリングにあるセグメントに対するアクセスが,まったく不可能なわけではなく,「コールゲート」と呼ばれる特別な方法を使用することによって可能になる.
 コールゲートを使用したプログラム呼び出しの概念を図6に示す.
 コールゲートの実体は,セグメントデニィスクリプタと同じ構造を持つ,プログ・ラムへのエントリアドレスが格納された・ディスクリプタである.
 すなわち,セグメントディスクリプタのリミットとセグメント・ベース・アドレスの各フィールドにプログラムのエントリアドレス(オフセット,セグメント・ベース・アドレス)を格納したものである.コールゲートは、セグメントディスクリプタと同じディスクリプタテー・ブルに配置され,ディスクリプタ内のタイプフィールドで両者の区別を行う.
 このコールゲートに対して,JMP,あるいはCALL命令を実行することにより,異なるリング番号のプログラムを呼び出すことができるようになる.
 図6から,コールゲートを使用したプログラムの呼び出し動作には,おおむね2回(厳密には1.5回)のアドレス変換動作が必要になることがわかる.アドレス変換に成功すると,そのプログラムの実行が開始される.
 すなわち,コールゲートを実現するために重要なことは,JMP,あるいはCALL命令のオペランドである分岐先のセグメントセレクタが,コールゲートのディスクリプタを指し示していなければならないということである.
 このようにコールゲートを作成することで,特権レベルの高いプログラムが,コールゲートに記述されたエントリアドレス以外から呼び出されることが防げる.たとえば、アプリケーションプログラムが,バグによる暴走などでレベルの高い,プログラムの誤ったエントリに制御を移しても,そのプログラムが実行されるということはない。
 OS/2のファンクションコールは,すべてコールゲートを使用して実現されている.そのため,OS/2のアプリケーションプログラムは,ファンクションコニールに際しても,MS-DOSのように特別な命令(ソフトウェア割り込み:INT命令)を使用して区別する必要はなく,通常のCALL命令を使用すればよいことになる.
 このコールゲートの採用により,プログラムのリンク時に,ファンクションコールのライブラリをリンクする必要がなくなるため、実行形式ファイルのサイズが小さくて済む.アプリケーションプログラムが使用するファンクションコールは,そのプログラムのローディング時に,そのプログラムが使用するライブラリル-チンに対するコールゲートを,ディスクリプタテーブルの中に作成するだけで可能になるのである.この機能を実現する機構のことを「動的リンク機構」と言い,動的リンクを行うために,各ライブラリルーチンの情報を納めたファイルのことを「動的リンクライブラリ(ダイナミックリンクライブラリ)」と言う(OS/2の動的リンクライブラリには,".DLL"の拡張子がつけられている).動的リンク機構によって,将来,OS/2のファンクションコールライブラリが変更されたり,コンパイラの仕様が変更された場合でも,プログラムを作り直す(再コンパイルや再リンクする)必要はまったくない.ロ-ディング時にコールゲートを作り直すだけで,そのまま実行することが可能になる.
(以下略)

ASCII1988(05)c07OS/2_図5_W722.jpg
ASCII1988(05)c07OS/2_図5の下_W660.jpg
ASCII1988(05)c08OS/2_図6_W1083.jpg
保護リングとかの機構を見て、今後はこういったOSでユーザのアプリケーションプログラムが暴走してOSを巻き込むことが無くなるのかと思っていたが、そんなことは無かった。OSはよく落ちた。
80286でよくもこんな機能たっぷりのOSを作れたものだと、MSとIBMのプロのプログラマを尊敬していた。

この号のEditor's Note は「日本語OS/2 プレリリース・セミナー」だった。結構面白い内容なのでスクラップする。
ASCII1988(05)h01編集部OS2_W520.jpg
 電源が入るとそこはリアルモードであった.すぐにリング0に移行し,私(OS/2)の本体であるカーネルをロードする.DOSの真似をしてCONFIG.SYSを読みに行くと,カントリーコードからそこが日本であることがわかった.
 おもむろにMS-DOS Ver.3.3でおなじみのコードページをセット.さらにデバイス・ドライバをロードして初期化ルーチンを実行後,カナ漢字デーモンを起動しFEPを待機させる.最後にプログラムセレクタを起動し,コマンドインタープリタに制御を移す.
   今日も私(OS/2ユーザー)の286マシンの調子が悪い.SDK(ソフトウェア開発キット)のOS/2だから、カーネルのリソースを覗けるのはいいが,だからといってデバッグが楽になるわけではない.
 MS-DOS Software Toolsを移植しようと思ったが,MS-DOS互換ボックスを使ってもなかなか一筋縄では動作してくれないのだ。とくにデバイス・ドライバが難しい.
 試しにSDKのMS-Cを使ってプロテクトモードだけで動作するように書き直してみたが,これもすぐスワップされてしまうためか,注意してプログラミングしないと遅いプログラムになってしまう.
 また性懲りもなく互換ボックスで動作するプログラムがやってきた.MS-DOSの隠しシステム・コールが登録されているといって,喜んで使っている.こちらで一所懸命割込みの処理をエミュレートしてやっている苦労もわかって欲しいものだ.
 ひどい奴はBIOSをアクセスするつもりでメモリを荒しにくるが,そういう手合いはとくに丁重に葬ってやる.私(OS/2)は巨大な権限をもつアドミニストレーターなのだ.
 それに,メモリボードも拡張せずにマルチタスクでどんどんプロセスを起動させるものだから,仮想記憶のスケジューリングが忙しくてたまらない。
 せっかくダイナミックリンク・ライブラリをサポートしているのだから,メモリをくれないならくれないなりに,共有できるライブラリはすべてメモリの1箇所に集めてスペース効率を図って欲しいものだ.
 しかたがないから,おかまいなしに実行中のプロセスをどんどんディスクに落としていく私まで動けなくなっては困るからだ.
 それにしても,仮想記憶空間が広いからといって,なぜセグメントの考慮が必要でないと思うのか理解できない.せっかくMS-Cの方でセグメントの属性を指定できるようにしているのだから,スワップされてよい部分と悪い部分を切り分けて作って欲しいものだ.
 個々のプロセスが現在どのセグメントを必要としているかなど,プログラムを作ったわけでもないのに,私にわかるわけがないではないか。
 そうでなくともいっせいにプリンタに出力しようとしたり,他人の迷惑も考えず漢字辞書をメチャクチャにアクセスしようとするスレッドの交通整理で忙しいというのに,そんなことを考えている暇は私にはないのだ。
 OS/2め,また横着なエラーメッセージを出しやがった.気にくわん.人がせっかくMS-DOSとOS/2の両方で動作するプログラムを作ろうとしているのに、やれサイズは大きくなるわ、ファイル管理は大変だわ,システム管理者面したメッセージは出すわ、これではまともなテストをする気が起こらんわい。
 えい,エラーメッセージを書き換えちゃえ「すみませんが,DLLを使うプログラムも作って頂けませんか?」
 よしよし,エラーメッセージがテキストファイルに格納されているというのはいいことだな.これでOS/2専用の大規模プログラミングに専念できるというものだ.
 せっかくだからPM(=ウィンドウシステム)も使ってみよう。なになに,まずMS-Windows Ver.2.0で練習してください?それじゃあイベント・ドリブンなわけね.
私は編集者です:-)
 OS/2は,ことほどさように巨大なシステムですが,システマティックに管理されているので各種のインターフェイスはMS-DOSより見通しがよくなるでしょう.ユーザーにとっては,スピードが速くなるというより,使い勝手やデータ交換が容易になるといったメリットが大きくなります。 (中略)
 OS/2はIBMとMicrosoftの共同開発のOSですから,IBMのOSであるMVSの解説書や,この系統の巨大なOSのもととなったMulticsの解説書なども読んでおくとよいと思われます。
(以下略)
当時はなんのことか分からなかったが、今読み返すと笑ってします。そうだ、こんな感じだったんだ。貧弱なハードウエアで無理して「こうしたい、こうあるべきだ」という理想をソフトウェアで実現しようとすると、「できるが、使い物にならない」となるものだ。

nice!(0)  コメント(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。