コンピュータの知識を得ようぜ 第002-003回
探したんだけど第002回のエントリがないや。書き忘れかな。
ということでまとめて。
第001回で、MITのOpenCourceWareの6.828 Operating System Engineeringのテキストをダラダラ読むという形式でスタート。
Lecture 1. OS Overviews
OS概論というふれこみなんだけど、なぜかシステムコールを延々列挙してみたり、唐突にシェルスクリプトの実装をはじめてみたりという謎な構成。
でも案外標準入出力とかリダイレクションとかパイプの実装ってどうなってるのって話を思い出すのは新鮮だった。
Lecture 2. x86 and PC architecture
PC のアーキテクチャの話はおおざっぱに飛ばして 86 のアーキテクチャの話をしていたような気がする。
- x86 はレジスタの直交性が低い(たとえばDIVとかはAXレジスタにしかできない)のがめんどくさいよねとか
- もう死語になっちゃったセグメントの話とか far / huge といったポインタの種類とか
- メモリマップトI/OとI/OマップトI/Oの話とか
- メモリ空間と物理メモリは必ずしも同じじゃないよって話とか
- gcc の calling convention の話から、C call と Pascal call の話とか
- それから唐突にCPUエミュレータを書く話で終わり。
ここまで第002回。ぜんぜんOSの話になりませんな、といいつつおしまい。
さて第003回は4/9に行われました。
Lecture 3: Operating system organizaton (途中まで)
やっとOS論らしい話になってきました。
Virtualization (仮想化)
- 第001回の私のしょぼしょぼ資料でも書いたけど、OSの重要な役割は物理的に一個しかない物を複数に見せること (multiplexing)
- 言い換えればコンピュータの仮想化
なぜだったか忘れたけどここでファイルシステムの話になって、ZFS のセクタ割り当て戦略はメモリのアロケーション戦略とすごく似てるんだよ、みたいな話をしたような気がする。
プロセッサの仮想化
メモリ分割
方法は二つ
- 高水準で型安全な言語でプログラムを書くように強制する
- ハードウェアでサポートする
もちろん両方を組み合わせることもできるけど、実際はハードウェアサポートだよねということでこれを考えましょう。
ここで簡単のために「物理メモリは無限にある」と仮定しましょう。
- メモリ管理ユニット (Memory Management Unit; MMU) というデバイスをプロセッサとメモリの間に突っ込む*3
- MMU はメモリアクセスをドメインレジスタというものを使って監視する
- ドメインレジスタはそのときにプロセッサがアクセスできるアドレスの範囲を決める
- アプリケーションがスイッチしたら、ドメインレジスタが切り替わる
これでメモリ分割が可能になりました。
もし一部のメモリをアプリケーション間で共有したいとか、そこに格納されたプログラムをみんなで実行したいとかある場合、読み込み(R)/書き込み(W)/実行(X)といったフラグをドメインレジスタに持たせればいい。
んで、ドメインレジスタが破壊されないようにするにはどうすればいいかというと、「カーネルモード」という概念をプロセッサに導入して、「カーネルモード」でしかドメインレジスタはさわれないようにする。この概念については後述。
メモリ管理
ここでも物理メモリは無限にあって、あとアドレス空間は十分にあるという仮定をおきます。
んで、ドメイン(=アプリケーションごとに割り当てられるメモリ)を作ったり、拡張したり、逆に縮小したりといった機能を考えてみましょうと。ただし、ここでドメインは連続性を持つことを保証したいとします。
となると、ドメインを作成するときに、単純に続いてポンポン作っていくのはとてもイケてないことがすぐわかります。というのはあるドメインを拡張しようとしたら、もう上も下も他のドメインに押さえられているので、連続性を保証したいと思ったらガバッとコピーするしかない。
ということで、物理アドレスとアドレス空間を仮想化しようというアイディアが生まれます。
アドレス空間というのはアプリから見るとただのメモリに見えるんですが、物理的にどう割り当てられるかはOSやハードウェア次第ですよと、そーゆーアイディアです。
それぞれのアプリにアドレス空間を割り当て、そこのアドレス(仮想アドレス)をそれを物理アドレスに変換する方法はもちろんMMUを用いて変換テーブルを使ってマッピングするわけですが、その方法は三つ。
- 全部の仮想アドレスと物理アドレスの表を作る。もちろん、こんなばかげたまねはしません。アドレスの分だけ巨大な表だなんて!
- x86 のセグメントの考えを応用し、連続的な仮想アドレスを (セグメント#, 開始(物理)アドレス, 長さ) に変換する表を持つ
- 物理メモリを固定長の「ページ」に分割し、ページマップ (ページ# をブロック# に変換する) を使う。ページマップとしては配列、木構造、スーパーページ、などがある
ちょっと最後のがわかりにくいけど、まあ追々説明があるのかもしれません。
あるいはビデオ見るかするとちゃんと説明されてるのかなあ。
なお CPU アーキテクチャによってこれらのうち複数をサポートしている物があり、たとえば x86 は 2 と 3 の両方をサポートしているそうです。
あとここで唐突にOSブートシーケンスの話がちょっとだけ出てきます。
- コンピュータ起動時にはMMUは無効化されている
- コンピュータはカーネルモードで起動するが、MMU は無効なのでまだメモリ変換は行われない(カーネルモードのアドレス0は物理アドレス0になる)
- カーネル内のプログラムで MMU の変換テーブルをカーネル用に初期化するが、たいていのカーネルでは先と同じように、カーネルモードのアドレス0は物理アドレス0になるようにするのが普通。
- 最後に MMU を有効にする
ちなみに MMU 有効化前にうっかり MMU が必要なメモリ割り当てとかやるといろいろ悲しいので注意。おぼろげな記憶では Windows の WDM だと同じエントリポイントでページング有効なモードと無効なモードとで呼ばれることがあって、たいていは前者なんだけどまれに後者で呼び出されて、メモリ割り当てしようとして青画面、というのはよくあるハマリパターンだった気がする。
オペレーティングシステムの構成
テキスト丸写しは飽きてきた。
まずは言葉の定義で、カーネルとかライブラリとかアプリケーションとかオペレーティングシステムといった言葉をあらためて定義しなおしてます。
シェルとかどうなの? というところに疑問はありますが、そこはひとまず起きます。
んで、OSの設計にはざっくりと次の四つがありますよと。この講座のレクチャーノート、唐突に話が始まったりするわりにはこういう説明は丁寧なんだよな。まあ、割とありがちなんで引き写しはやめて
- モノリシックカーネル
- マイクロカーネル
- 仮想マシン
- Exokernel
最後のが、???という感じなんですが、次からちゃんと説明するよ、ということで、この回は終了。