CPU Exception
Writing OS in Rust を最近やっているんだけど、CPU Exception の章に入って少し話が込み入ってきたので、読みながらメモをまとめようと思ってはじめる!
今ちょうど Double Fault のあたりをやっておわったくらい。
Global Descriptor Table についてまとめる。
Global Descriptor Table は、ページングがデファクトスタンダードになる前にメモリセグメンテーションのために使用されていた遺物のようなもので、プログラムのセグメントを含む構造になっている。カーネル/ユーザーモードの構成や TSS (Task State Segment) の読み込みなどのさまざまな目的で64ビットモードでも必要になる。
Double Fault と Triple Fault については、
- CPU がたとえば不正なメモリアクセスを行ったとする。
- そうすると仮想アドレスはページテーブル内の物理アドレスにマッピングができないので、ページフォルトが起こる。
- ページフォルトハンドラを設定していない場合、さらにダブルフォルト (Double Fault) が発生する。
- ダブルフォルトハンドラも設定していない場合、そこからトリプルフォルト (Triple Fault) が発生する。
- これが発生すると、QEMU ではそれを検知してシステムリセットを発行する。
ということで、この章ではダブルフォルトハンドラを実装するというのがモチベーションだった。
x86_64 アーキテクチャは例外が発生した際に定義済みの正常なスタックに切り替えを行うことができる。この切替はハードウェアレベルで行われるので、CPU が例外スタックフレームをプッシュする前に実行できる。
スイッチングのメカニズムは InterruptStackTable
に実装されている。が、これは Task State Segment
という構造の古いバージョンになっている。
TSS を作って、そのあと GDT に読み込ませることで CPU にその TSS を使うべきだ、ということを通知できる。
次の会ではキーボードなどの外部デバイスからの割り込みを扱えるようにするらしい!ということで、クローズ :)
わたしは普段、こうしたメモは Notion にとっているけど、Notion にまとめる前の頭の整理をするといったようなときに便利だと思いました。