web-dev-qa-db-ja.com

x86 Linuxの物理アドレス0には何が含まれていますか?

この質問がここに行くべきか、それとも reverseengineering.stackexchange.com に行くべきかわかりません

wikipedia からの引用:

8086プロセッサでは、割り込みテーブルはIVT(割り込みベクトルテーブル)と呼ばれます。 IVTは常にメモリ内の同じ場所(0x0000〜0x03ffの範囲)にあり、256個の4バイトリアルモードfarポインター(256×4 = 1024バイトのメモリ)で構成されています。

これは私がqemuモニターで見つけるものです:

(qemu) xp/128xw 0
0000000000000000: 0xf000ff53 0xf000ff53 0xf000e2c3 0xf000ff53
0000000000000010: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000020: 0xf000fea5 0xf000e987 0xf000d62c 0xf000d62c
0000000000000030: 0xf000d62c 0xf000d62c 0xf000ef57 0xf000d62c
0000000000000040: 0xc0005526 0xf000f84d 0xf000f841 0xf000e3fe
0000000000000050: 0xf000e739 0xf000f859 0xf000e82e 0xf000efd2
0000000000000060: 0xf000d648 0xf000e6f2 0xf000fe6e 0xf000ff53
0000000000000070: 0xf000ff53 0xf000ff53 0xf0006aa4 0xc0008930
0000000000000080: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000090: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000c0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000d0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000e0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000000f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000100: 0xf000ec59 0xf000ff53 0xf000ff53 0xc0006730
0000000000000110: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000120: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000130: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000140: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000150: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000160: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000170: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
0000000000000180: 0x00000000 0x00000000 0x00000000 0x00000000
0000000000000190: 0x00000000 0x00000000 0x00000000 0xf000ff53
00000000000001a0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001b0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53
00000000000001c0: 0xf000d611 0xf000ec4e 0xf000ec4e 0xf000ec4e
00000000000001d0: 0xf000d61a 0xf000d623 0xf000d608 0xf000ec4e
00000000000001e0: 0xf000ff53 0x00000000 0xf000ff53 0xf000ff53
00000000000001f0: 0xf000ff53 0xf000ff53 0xf000ff53 0xf000ff53

これらの値をどうするかわかりません。これは、割り込み記述子テーブルのようには見えません(これらの値を逆参照すると、すべてヌルが与えられます)。それで、私は実際にここで何を見ていますか?

12
rhodeo

ファームウェアに含まれているものは何でも。

理想的な最新システムでは、このSU Q&Aのタイトルで説明したように、プロセッサがリアルモードに移行することはありません。 最新の64ビットインテルチップPCはどのモードでブートセクターを実行しますか? 物理記憶のKiBは、ヨハン・ミリーンがここで別の答えを出すためにそれを作成したのと同じくらい重要ではありません。しかし、多くの最近のファームウェアには(まだ)互換性サポートがあり、

  • 古いなどのリアルモード用に作成されたシステムソフトウェアを実行するために、プロテクトモードからリアルモードにドロップすることができます(はい、バック、非リアルモードからプロテクトモードに直接移行した場合)。 MBRおよびVBRのスタイルPC/ATブートプログラム。そして
  • これらは、古いリアルモードファームウェアAPIを提供し、前述のシステムソフトウェアが依存するAPIのすべてのデータ構造を設定します。

これらのデータ構造の1つは、リアルモードIVTです。古いリアルモードファームウェアAPIはint命令に基づいており、リアルモードIVTは、それらの命令のさまざまなファームウェア処理ルーチンへのポインタを備えた初期化の一部としてファームウェアによって入力されます。

プロテクトモードのシステムソフトウェアは、古いリアルモードファームウェアAPIを必要とせず、プロセッサをリアルモードで実行しないので、物理メモリの最初の1KiBのリアルモードIVTは使用されません。 (v8086プロテクトモードはphysicalアドレス00000000以上に対応していません。覚えてください。これはlogicalアドレス00000000以上に対応し、ページテーブルによって変換されます。)最新のEFIシステムでは、ファームウェアは、物理メモリのメモリマップをオペレーティングシステムのブートストラップに渡し、どの部分が独自のプロテクトモードAPIの目的でファームウェアに予約されているか、どの部分がオペレーティングシステムが自由に先に進んでそのプールに使用できるかを伝えます。物理メモリの。理論的には、物理​​メモリの最初のページは後者のカテゴリに入る可能性があります。

実際には、最初に、ファームウェアは物理メモリの最初のページを「ブートサービスコード」としてマークすることがよくあります。つまり、オペレーティングシステムcanが要求し、物理メモリプールの一部として使用します。 、ただし後にのみ EFIファームウェアの起動時サービスはオペレーティングシステムによってシャットダウンされ、ファームウェアは実行時サービスのみを提供するように縮小されました。この例は、Linuxカーネルログ(add_efi_memmapオプション)はフィンバーP.マーフィーが示したものです。

[0.000000] efi:mem00:type = 3、attr = 0xf、range = [0x0000000000000000-0x0000000000001000)(0MB)
[#00]タイプ:EfiBootServicesCode Attr:0xF 
 Phys:0000000000000000-0000000000001000 
 Virt:0000000000000000-0000000000001000

実際には、次に、Linuxはこの範囲の物理メモリを明示的に無視しますたとえあったとしてもファームウェアはそれを先に進めて使用できると言っています。 EFIファームウェアと非EFIファームウェアの両方で、Linuxが物理メモリマップを取得すると、パッチが適用されます( trim_bios_range )、次のようなカーネルログメッセージが表示されます。

[0.000000] e820:更新[メモリ0x00000000-0x00000fff]使用可能==>予約済み

これは、リアルモードIVTがファームウェアAPIの一部ではない最新のEFIファームウェアに対処することはそれほど多くありません。ファームウェアAPIの一部である古いPC98ファームウェアに対処するためですが、ファームウェアはそれを報告します(オペレーティングシステムによって簡単に上書きできる物理メモリと同じAPI)。

したがって、理論上は、物理メモリの範囲couldには、カーネルメモリアロケータとデマンドページング仮想メモリの瞬間的なニーズに応じて、任意のコードまたはデータが含まれます。実際には、Linuxはファームウェアが最初にセットアップしたのでそのままにしておきます。

そして、あなたのシステムでは、ファームウェアがリアルモードIVTエントリをそこに投入しました。リアルモードのIVTエントリはもちろん16:16ファーポインターです。2バイトの16進ダンプを使用してメモリを見ると、これをかなりはっきりと見ることができます。いくつかの例:

  • ほとんどのIVTエントリは、リアルモードファームウェアのアドレスF000:FF53をポイントしていますROMエリア。これは、iret以外の何もしないダミールーチンである可能性があります。
  • IVTエントリ1E は、同じテーブルのF000:6AA4を指しますROMエリア。
  • IVTエントリ1F は、リアルモードビデオのテーブルC000:8930を指しますROMファームウェア領域。
  • IVTエントリ4 は、リアルモードビデオの別のテーブルC000:6730を指しますROMファームウェア領域。

参考文献

9
JdeBP

元の8086プロセッサアーキテクチャ(80286+プロセッサでリアルモードとして実装)は、保護モードで動作するLinuxには関係ありません。物理アドレス0には割り込みベクタテーブルはありません。代わりに、割り込み記述子を含む割り込み記述子テーブルが使用されます。 IDTはメモリ内のどこにでも配置できます。

Linuxカーネルは、ファームウェア(BIOSまたはEFI)から物理メモリマップを取得し、使用可能な物理メモリページフレームと、予約されているか存在しない物理メモリページフレームを通知します。使用可能なページフレームの範囲は連続していませんが、通常、そこには大きな穴があります。従来、x86 Linuxカーネルは、使用可能としてマークされていても、物理メモリの開始をスキップしていました。したがって、物理アドレス0はLinuxカーネルでは使用されません。

7
Johan Myréen