借り初めのひみつきち

仮ブログです。

EFER.LME と EFER.LMA

EFER.LME と EFER.LMA をご存知ですか? これらのフラグは x64 CPU でロングモードの遷移に関わるフラグです。

では、2つのフラグの役割の違いをご存知ですか?

ロングモードの遷移

ロングモードの遷移についておさらいしてみましょう。 *1

まずは、 CR0 レジスタの PE フラグをセットします。 リアルモードからプロテクトモードに遷移します。

次に、 CR4 レジスタの PAE フラグをセットします。 PAE と呼ばれるページング拡張機能を有効にすることを宣言します。(しかし実際にはこの機能は使われません!)

次に、 MSR 内の EFER レジスタの LME フラグをセットします。 ロングモードを有効にすることを宣言します。しかし、この段階はまだプロテクトモードです。まだロングモードではありません。

最後に CR0 レジスタの PG フラグをセットします。 通常この操作はページングを有効にしますが、上記のフラグが全てセットされてる場合に限りロングモードに遷移します。 そしてこの時 EFER レジスタの LMA フラグが自動的にセットされます。

なお、ロングモードからプロテクトモードに戻る場合は、 CR0 レジスタの PG フラグをクリアすれば LMA フラグが自動的にクリアされてプロテクトモードに戻ることができます。

PG フラグの ON/OFF でロングモードに遷移しちゃうなら通常のページングはどうやって使えばいいのかというと、 EFER レジスタの LME フラグをクリアすれば PG フラグを再びセットした時にロングモードへの遷移が行われず通常のページングモードになります。

モード遷移するだけで何個のシステムレジスタ操作すればいいんや!!!

というのは置いておいて、以上の手順でプロテクトモードとロングモードを切り替えることができます。

さて、 LME は上記のように初期化時にシステムプログラムが書き込むわけですが、 LMA に直接書き込んでモード遷移したりできないのでしょうか?

ここで分厚いマニュアルを見てみます。

AMD の場合

f:id:neriring16:20200805235750p:plain

LME/LMA とも R/W になっているので LMA を直接書き換えることができるような感じがします。 しかし、各フラグの詳細を見てみると以下のようにあります。

f:id:neriring16:20200805235803p:plain

LMA は現在の設定値から直接書き換えると GP (一般保護例外) と明記されています。 R/W だけど勝手に書き換えはできません。

Intel の場合

f:id:neriring16:20200806000948p:plain

なんということでしょう、 LMA はリードオンリーです。 経験上書き込んでも無視されます。

けつろん

LME はロングモードを有効にするかどうか宣言するフラグ、 LMA は実際にロングモードが有効になっていることを示すフラグです。

また、 LMA は自由に書き換えることができませんが、 IntelAMD で仕様が違います。

AMD64 と Intel64 はこのように細かい違いがあります。

*1:このほかにページテーブル等の準備が必要ですが、順番が厳密に定まっているわけではないのでここでは既に準備済みとします。