21日目

アプリ用ということでアクセス権に0x60を足したりセグメント番号に3をORしたりしているが、どうもOS自作本ではここらへんは"おまじない"として解説はしてない様子。
この2つの"おまじない"は両方とも特権レベルに関係している。
アクセス権に0x60を足すのはディスクリプタ中の属性フィールド内5,6ビット目を1にするためにおこなわれている。属性フィールドの5,6ビット目は2ビットでディスクリプタ特権レベル(DPL)を表わしており、ここでは特権レベル3(アプリ用)に設定していることになる。
なおx86ではCALL/JMPは同一特権レベルでしか許されておらず、高い特権レベル(レベル0)から低い特権レベル(レベル3)を呼ぶにはRETF(gasではlret)を使うしかない。


現在どの特権レベルで動作しているかを表すのが動作レベル(CPL)でこれはCSレジスタの下位2ビットをみればわかる。
つまりOS自作本p.438でセグメント番号に3をORしていたのは、RETした際動作レベルを3に引き下げるため。


以下IA32命令セットリファレンスマニュアルのRETより

far リターンを実行すると、プロセッサは、リターン命令ポインタをスタックのトップからEIP レジスタにポップし、次にセグメント・セレクタをスタックのトップからCSレジスタにポップする。プロセッサは、その後、新しい命令ポインタにある新しいコード・セグメントでのプログラム実行を開始する。 特権レベル間far リターンのメカニズムは、セグメント間リターンと同様であるが、プロセッサが戻されるコード・セグメントとスタック・セグメントの特権レベルとアクセス権を調べて、制御の転送を行うことができるかどうかを判断する点が異なる。DS、ES、FS、GS セグメント・レジスタは、新しい特権レベルではアクセスすることができないセグメントをそれらが参照している場合は、特権レベル間リターン中にRET 命令によってクリアされる。特権レベル間リターンではスタックスイッチも行われるので、ESP レジスタおよびSS レジスタがスタックからロードされる。