khabaを設計しながら気づいたIA-32のダメなところ
(1) ページング
- PDEとかPTEはダメ。TLBがOSから見えて読み書きできればそれでよかった。つまりTLBにヒットしなければページフォールト。そういうCPUはRISC系では普通にあるらしい。
- TLBは、カバーするアドレスの範囲と対応する物理アドレスを格納するのがいい。これなら32bit*3でいい。この仕組みならページの大きさは自由だし(統一する必要もない)、連続するページは一つのTLBでカバーさせることも可能になる。TLBに0-4GBを0-4GBへ対応付ける設定をTLBに書き込んでおけば、これはページングをoffにしたのと同じ効果がある。
- さらに8bitくらいつけてアクセス権を書けたらもっといいな。CPL=0〜1はアクセスできるとか。読み込めるけど書けないとか。実行はできるとか。
- PDEとかPTEの何がダメって、まずページの大きさを自由にできない。PDEやPTEをもっと小さく保つ工夫を
思いついてもそれを生かせない。ある意味CPUがメモリを食っているといえる。
- この方式の場合、TLBが32個で足りるのか(=速度がそれほど落ちずに済むのか)、もしくはTLBはもう少し減らしてもいいのかなどについては、よくわからない。
- この方式でよければ、デバッグレジスタも要らないよなあ。TLBに十分な余裕があれば代用できるから。
(2) セグメンテーション
- IA-32のセグメンテーションもダメ。何がダメって、GDTやLDTがダメだ。セグメントレジスタという仕組みもいまいちだ。アドレス指定可能な全てのベースレジスタに対し、アクセスを許可する範囲(32bit*2)とそれをリニアアドレスに写像するためのbaseがあればいいだけなのに。そしてこれらのシステムレジスタはOSのみによって書き換えられるようにする、と。
- つまりイメージとしては、セグメントオーバーライドができなくなって、ESIにはDS、EDIにはES、ESPにはSS、EBXにはFS、EBPにはGS、EIPにはCS、みたいにベースレジスタごとにデフォルトのセグメントレジスタを固定する。EAXやECXやEDXについては対応するセグメントレジスタを新設する。そして書くセグメントレジスタのbaseやlimitやアクセス権を保持している内部レジスタをOSからアクセス可能にする。そしてセグメントレジスタそのものは廃止してしまう。つまりDSやESへセレクタ値を代入することはできない。セレクタ値を入れるのではなく、アプリはOSに頼んで、baseやlimitへ直接代入してもらう形である。
- これならグローバルセグメントが最大で8191個とかいうくだらない制限はなくなる。ローカルセグメントについても同様。そしてセグメントーバーライドプリフィクスなんていう命令コードも必要なくなる。そしてGDTやLDTもいらないのでメモリが節約できる。
- 欲を言えば、baseやlimitがまったく見えないままでも、ESI用のbaseやlimitやアクセス権をEDI用のbaseやlimitやアクセス権へコピーできる命令があるとうれしいかもしれない。ESIに入っていたということはどうせアクセス可能な領域ということだし、それをOSを呼ばずに代入できたら高速っぽい気がする。
- この方式だとセグメント情報をスタックやメモリに格納するのが簡単ではなくなる。PUSH(DS);や[EBX+8]=ES;みたいなことはできないから。読み込みも同じくらい問題だ。baseやlimitを直接メモリに書いたり読んだりするわけにも行かない。だってそんなことをしたらアプリから見えてしまうし、アプリから改変することもできてしまうかもしれないから。だからこれもOS経由になる。OSはセレクタに相当するセグメントIDをアプリに返すだろう。アプリはそれをPUSHしたりメモリに書いたりすればいい。逆にセグメントIDを指定してESIのbaseやlimitやアクセス権を設定するAPIも用意できるだろう。
(3) 割り込み
- 割り込みの仕組みもなんだかなあと思う。ベクタテーブルはあんなに必要なのか。INTは番号によらず一つの入り口から入って、スタックのトップにでも割り込み番号をPUSHしておいてくれればそれでいいと思う(例外のエラーコードみたいな感じ。エラーコードのさらに上に積む)。これならベクタはメモリ上に置かなくていい。システムのレジスタに入れておける。