Linux には (他のセグメントのうち) ユーザーデータセグメントとカーネルデータセグメントがあります。
CPUがユーザーモードのとき、LinuxはユーザーデータセグメントのセグメントセレクタをDSレジスタにロードします。 CPUがカーネルモードのとき、LinuxはカーネルデータセグメントのセグメントセレクタをDSレジスタにロードします。
ただし、ユーザーデータセグメントとカーネルデータセグメントは同じ仮想メモリアドレスを指しているため、カーネルデータセグメントはまだユーザーモードでアクセスできます。
それでは、なぜLinuxには2つのデータセグメントがあります。1つはユーザーモード用、もう1つはカーネルモード用ですか?
ベストアンサー1
Linuxは、SS(スタックセグメント)とDS(データセグメント)に同じセグメント記述子を使用します。 SSセグメント記述子は、CPL(つまり現在の権限レベル)とまったく同じDPLフィールドを持つ必要があります。したがって、カーネルモードとユーザーモードには別々のデータセグメント記述子が必要です。
ソース(CPUマニュアルをダウンロードするには怠惰すぎる)
定義の説明gdt_ページ:
また、ロングモードのデータとコードに有効なカーネルセグメントが必要です。 IRET はセグメントタイプを確認します。 ——カイル 2000/10/28
Web検索:iretセグメントタイプの確認
SSにセレクタをロードするコマンドは、書き込み可能なデータセグメントのデータセグメント記述子を参照する必要があります。記述子権限(DPL)とRPLが必要です。同じCPL。他のすべての記述子タイプまたは権限レベル違反は例外 13 をスローします。
Web検索:iretセグメントタイプの確認OR "DPL" OR "CPL" "SS"
...スタックセグメントを除いて、レジスタss、CPL、RPL、およびDPLは一致する必要があります。正確に。
/* stack segment DPL must equal the RPL of the return CS selector,
* else #GP(SS selector) */
if (ss_descriptor.dpl != cs_selector.rpl) {
BX_ERROR(("iret: SS.dpl != CS selector RPL"));
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
}
背景:Linuxにはなぜ別のパスワードユーザーモードとカーネルモードセグメント?
関連、別のコメントカーネルソースコード:
DPLが異なるため、ユーザーモードとカーネルモードでは、Long Planeモードでも同じコードセグメント記述子を使用できません。
このためです現在のコードセグメントのDPLがCPLとして使用されます。。
32ビットコードと64ビットコードには異なるスニペットが必要であることがわかりました。
https://en.wikipedia.org/wiki/Segment_descriptor-
L =長いパターンセグメント
設定されている場合、これは64ビットセグメントであり(Dは0でなければなりません)、このセグメントのコードは64ビット命令を使用してエンコードされます。
少なくともx86-32のユーザ空間からカーネルに入ると、DSセグメントレジスタがリセットされるようです。ただし、これを行うコードを識別できません。
まだ一つあります。最近のLWN.net記事、これはset_fs()の興味深い説明です。
set_fs() の元の機能は x86 プロセッサの FS セグメントレジスタを設定することです。これは、最初に権限のないコードがアクセスできる仮想アドレス範囲を制御するために使用されました。カーネルはこの方法でx86セグメントの使用を中止してから古い。