4GBメモリ時代にあった天使の取り分とは何だったのか


結論

Memory Mapped I/O の分

(今ので理解できた人はおそらくこの記事を見ても何も得られません)
(この記事は、ただのメモ書きという側面が大きいので、間違っている可能性があります)

はじめに

これは木更津高専アドベントカレンダー16日目の記事です。よろしければ他の人の記事もご覧ください。

CPUからみた周辺機器

突然ですが、例えばx86でCPUから周辺機器へアクセスにはどうすれば良いのでしょうか。
一番最初に思いつくのはin命令out命令を使う方法です。
in命令out命令では、I/Oデバイスの番号をレジスタで指定して、それに対して入力と出力ができるという代物で、現在でもLinuxのブートやベアメタル開発で使われています。
自作OSをしたことがある人は、A20線を始めとする割り込みコントローラーの制御が馴染み深いと思います。現在のLinuxのブートシステムでも普通に使われており、現役です。

問題点を見ていきましょう。
まず、I/Oポートは非常に少ないです。256個しかありません。
画面の制御をしたいときは、これらのポートを使い回さないと行けないわけです。事実、上で挙げた割り込みコントローラーは、チップ内のどの情報を書き換えるか指定した上で別の命令で値を操作する、という感じで制御をしています。
この方法で画面の制御をしていたら実用に耐えうるレベルの速度は出ないので、当然別の方法を取る必要があります。

Memory Mapped I/O です。

Memory Mapped I/O

I/Oポートを使う方法では、使えるポートが非常に少ないのが問題でした。しかし、ポートは物理的なピンであり、増やすのは容易でありません。
そこで、メモリアクセスによってデバイスを操作できるようにしようとと考えた人がいます。それがMemory Mapped I/Oです。
私達が普段使うメモリの一部をVRAMという領域に設定し、そこにアクセスが合った時にデバイスがそれを認識して特有の処理を行うというものです。

VGAコントローラーを例に取って話します(正確にはVGAもポートを使いますが、ここでは目をつむってください)。VGAコントローラーのVRAMは 0xA0000 から始まり、画面左上から右下にかけて、1pixelあたり1byteの領域が設定されます。
その領域にアクセスがあったら対応したピクセスの表示を変えるみたいな感じで実装されていて、この仕組みによってポートの使用頻度を大幅に下げることができるようになります。

以上が Memory Mapped I/O の主な概要ですが、ここで内部の実装について確認してみます。
各デバイスは自身へのメモリアクセスがあったとどのように検知しているのでしょうか。色々候補が考えられますが、回路が複雑にならず、かつ高速に動作させるのであれば、メモリのアドレスバスを共有するのが一番簡単でしょう。
つまり、CPUから伸びているメモリのアクセス線に、RAMだけではなくVGAやその他デバイスを直接接続し、それぞれが自分の担当する領域を自覚させ、自身へのアクセスかを見分ける方法です。

実際にこれは成功し、Memory Mapped I/Oが広く使われるようになりました。しかしこれには問題点があります。

Memory Hole

それは、他のデバイスが使っている領域を使えない ことです。何を当たり前のことを言っているんだ。と思うかもしれませんが、よく考えるとRAMもデバイスの一つでした。つまり、VGAなどが使っている領域へのRAMアクセスが不可能となってしまったわけです。
初期の頃はこれらに対してなんの対策もなかったため、0xA0000へのメモリアクセスができない!といった状態になりました。
そこで取られた対策が Memory Remapping です。

Memory Remapping

まぁ単純な話、VGAとかが使ってるならRAMの領域をずらそうよ。というだけです。
BIOSの設定画面で見たことがある人もいると思います。

もう少し詳細に説明します。
まずリアルモードなどの関係で、RAMの先頭は0x0からアクセスできなければなりません。その次にI/Oデバイスが存在するので、ここで穴ができます。Remappingではこの穴の部分をずらし、RAMの分割して一つの線形アドレス上に配置します。
単純な変換なので無駄に時間がかかったりとかしません(多分)。

でも、よく考えたら32bitなのは変わらないし、4GBのメモリを積んだら結局目減りしてしまいます。これが天使の取り分の正体です。
そこ取られた次の対策が Physical Address Extension です。

Physical Address Extension(PAE)

これもすごい単純な話で、32bitで足りないなら増やそうぜ!って感じです。
ただ、いきなり64bitアーキテクチャになるのではなく、32bitのままにどうにかして拡張しよう!というコンセプトを持っています。
そのため、仮想メモリは4GBまでしか使えないが、ページングの際にもう一段増やしたエントリーをCR0が指すことで36bit空間へのアクセスを可能にしました。
この技術によって、ユーザーが用意したRAMの最大限使えるように配置し、かつI/O用の空間を容易することができるようになったわけです。

まとめ

天使の取り分は、アクセスできるメモリ空間が小さかった時にI/O用に割り当てていた領域があったからだよ。
Remapping と PAE で空間を拡張してRAMがすべて使えるようになったよ。

ちなみに、64bitが主流の今はどうなっているのかというと、全く問題になっていません。じゃあなんで記事なんて書いたんだ
まぁ人類が18EB(2^64)のメモリを使うってなったときにまた問題になるんじゃないですかね(その頃には全く別のアーキテクチャが使われてそう)。

一応自分なりに調べて書いたつもりですが、おそらく普通に間違っているでしょう。
なにかありましたらTwitter:いわんこか、コメントしていただけると泣いて喜びます。