Was enthält die physikalische Adresse 0 in x86 Linux?

12

Ich bin mir nicht sicher, ob diese Frage hier oder unter reverseengineering.stackexchange.com gestellt werden soll

Zitat aus Wikipedia :

Im 8086-Prozessor heißt die Interrupt-Tabelle IVT (Interrupt-Vektortabelle). Der IVT befindet sich immer an der gleichen Stelle im Speicher, von 0x0000 bis 0x03ff, und besteht aus 256 4-Byte-Real-Mode-Fernzeigern (256 × 4 = 1024 Byte Speicher).

Das finde ich in qemu monitor:

(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

Ich bin nicht sicher, was ich von diesen Werten halten soll. Es sieht nicht wie eine Interrupt-Deskriptor-Tabelle aus (die Dereferenzierung dieser Werte ergibt alle Nullen). Was schaue ich hier eigentlich an?

Rhodeo
quelle

Antworten:

9

Was auch immer Ihre Firmware enthält.

Auf einem idealen modernen System wechselt der Prozessor überhaupt nicht in den Real-Modus, wie in dieser SU-Frage und Antwort erläutert: In welchem ​​Modus werden moderne 64-Bit-Intel-Chip-PCs im Bootsektor ausgeführt? , das erste KiB an physischem Gedächtnis ist so irrelevant, wie Johan Myréen es hier in einer anderen Antwort ausgedrückt hat. Aber viele moderne Firmwares haben (noch) Kompatibilitätsunterstützung , was bedeutet, dass

  • Sie können vom geschützten in den realen Modus zurückkehren (ja, zurück , vorausgesetzt, sie sind direkt vom unrealen in den geschützten Modus gewechselt), um Systemsoftware auszuführen, die für den realen Modus geschrieben wurde, z. B. PC / AT-Startprogramme im alten Stil MBRs und VBRs; und
  • Sie stellen die alten Real-Mode-Firmware-APIs bereit und richten alle Datenstrukturen für die APIs ein, auf die sich die oben genannten Systemsoftwareprogramme stützen.

Eine dieser Datenstrukturen ist der Real-Mode-IVT. Die alten Real-Mode-Firmware-APIs basieren auf intAnweisungen, und das Real-Mode-IVT wird von der Firmware als Teil seiner Initialisierung mit Zeigern auf die verschiedenen Firmware-Verarbeitungsroutinen für diese Anweisungen gefüllt.

Protected-Mode-Systemsoftware benötigt keine alten Real-Mode-Firmware-APIs und führt den Prozessor niemals im Real-Mode aus, sodass der Real-Mode-IVT in den ersten 1 KB physischem Speicher nicht verwendet wird. (Der v8086-geschützte Modus adressiert nicht die physische Adresse 00000000 und höher, denken Sie daran. Er adressiert die logischen Adressen 00000000 und höher, die durch Seitentabellen übersetzt werden.) In modernen EFI-Systemen übergibt die Firmware eine Speicherkarte des physischen Speichers an das Betriebssystem Bootstrap, in dem angegeben wird, welche Teile für die Firmware für die Zwecke der eigenen API für den geschützten Modus reserviert sind und welche Teile das Betriebssystem für den Pool des physischen Speichers verwenden kann. Theoretisch kann die erste Seite des physischen Gedächtnisses in die letztere Kategorie fallen.

In der Praxis wird die erste Seite des physischen Speichers häufig von Firmwares als "Boot-Service-Code" gekennzeichnet. Dies bedeutet, dass ein Betriebssystem darauf Anspruch erheben und sie nur als Teil seines physischen Speicherpools verwenden kann, jedoch erst nach dem Booten. Zeitdienste der EFI-Firmware wurden vom Betriebssystem heruntergefahren, und die Firmware wurde auf die Bereitstellung nur ihrer Laufzeitdienste reduziert. Ein Beispiel hierfür ist im Linux-Kernel-Protokoll (mit der add_efi_memmapOption) von Finnbarr P. Murphy zu sehen:

[0.000000] efi: mem00: type = 3, attr = 0xf, range = [0x00000000000000-0x0000000000001000] (0 MB)
welche xe mit einem anderen Programm in einer besser lesbaren Form dekodiert als:

[# 00] Typ: EfiBootServicesCode Attr: 0xF
      Phys: 0000000000000000-0000000000001000
      Virt: 0000000000000000-0000000000001000

In der Praxis ignoriert Linux diesen Bereich des physischen Arbeitsspeichers zweitens explizit, auch wenn die Firmware angibt, dass er verwendet werden kann. Sie werden feststellen, dass sowohl auf EFI- als auch auf Nicht-EFI-Firmwares, sobald Linux über die physische Speicherzuordnung verfügt, diese gepatcht wird ( in einer Funktion mit dem Namentrim_bios_range ), was zu Kernel-Protokollmeldungen führt, wie z.

[0.000000] e820: update [mem 0x00000000-0x00000fff] verwendbar ==> reserviert

Dies ist nicht so sehr mit modernen EFI-Firmwares zu tun, bei denen der Real-Mode-IVT nicht Teil der Firmware-API ist, sondern mit alten PC98-Firmwares, bei denen er Teil der Firmware-API ist, die Firmwares dies jedoch melden (über dass sich selbst gleiche API) als physischer Speicher zur Verfügung, der vom Betriebssystem problemlos überschrieben werden kann.

Während also in der Theorie , dass Bereich des physikalischen Speichers könnte , beliebigen Code oder Daten enthält, abhängig von den momentanen Bedürfnissen des Kernel - Speicher Verteilern und Nachfrage ausgelagerten virtueller Speicher; in der Praxis lässt Linux es einfach unberührt, da die Firmware es ursprünglich eingerichtet hat.

Und auf Ihrem System war die Firmware mit IVT-Einträgen im Real-Modus bestückt. IVT-Einträge im Real-Modus sind natürlich nur 16: 16-Zeiger, und wenn Sie Ihren Speicher mit einem 2-Byte-Hexdump betrachten, können Sie dies tatsächlich ziemlich deutlich erkennen. Einige Beispiele:

  • Die meisten Ihrer IVT-Einträge verweisen auf F000: FF53, eine Adresse im Real-Mode-Firmware-ROM-Bereich. Es ist wahrscheinlich eine Dummy-Routine, die nichts weiter als eine iret.
  • Der IVT-Eintrag 1E zeigt auf F000: 6AA4, eine Tabelle in demselben ROM-Bereich.
  • Der IVT-Eintrag 1F zeigt auf C000: 8930, eine Tabelle im Bereich der Real-Mode-Video-ROM-Firmware.
  • Der IVT-Eintrag 43 zeigt auf C000: 6730, eine weitere Tabelle im Bereich der Real-Mode-Video-ROM-Firmware.

Weitere Lektüre

JdeBP
quelle
Nein, ich meine, was ich geschrieben habe. Intel Architecture Software Developers 'Manual Band 3 Kapitel 20 § 2.
JdeBP
Nun hast du es jetzt, denn es ist; wie der erste Satz dieses Abschnitts erklärt. Ich vermute, dass die Nichterkennung der allgemeinen Abkürzung "v8086" eine Art Schibboleth ist. (-:
JdeBP
Sie müssen lernen, wie man attributive Substantive liest. Oder lernen Sie, ohne Pilzsuppe zu leben.
JdeBP
7

Die ursprüngliche 8086-Prozessorarchitektur (in 80286+ -Prozessoren als Real-Modus implementiert) ist für Linux, das im geschützten Modus arbeitet, nicht relevant. Es gibt keine Interrupt-Vektortabelle an der physikalischen Adresse 0, stattdessen wird eine Interrupt-Deskriptor-Tabelle verwendet, die Interrupt-Deskriptoren enthält. Das IDT kann sich an einer beliebigen Stelle im Speicher befinden.

Der Linux-Kernel erhält von der Firmware (BIOS oder EFI) eine physische Speicherkarte, die angibt, welche physischen Speicherseitenrahmen verwendet werden können und welche reserviert oder nicht vorhanden sind. Der Bereich der verwendbaren Seitenrahmen ist nicht zusammenhängend, weist jedoch normalerweise große Löcher auf. Traditionell hat der x86-Linux-Kernel den Start des physischen Speichers übersprungen, auch wenn er als verwendbar markiert ist. Daher wird die physikalische Adresse 0 vom Linux-Kernel nicht verwendet.

Johan Myréen
quelle
Das macht Sinn. Wissen Sie, woher der übrig gebliebene Inhalt dieser nicht verwendeten Seite stammt?
Rhodeo
Das Durchsuchen nach 53 ffzeigt, dass es sich höchstwahrscheinlich tatsächlich um eine von der Firmware oder einem Bootloader erstellte 8086-Real-Mode-Interrupt- Vektortabelle handelt .
Johan Myréen
4

Speicher sichern

Hier ist eine alternative Möglichkeit, den Inhalt des Speichers im System zu sichern, anstatt ihn extern ausführen zu müssen:

$ head /dev/mem | hexdump -C
00000000  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
00000010  53 ff 00 f0 53 ff 00 f0  cc e9 00 f0 53 ff 00 f0  |S...S.......S...|
00000020  a5 fe 00 f0 87 e9 00 f0  53 ff 00 f0 46 e7 00 f0  |........S...F...|
00000030  46 e7 00 f0 46 e7 00 f0  57 ef 00 f0 53 ff 00 f0  |F...F...W...S...|
00000040  22 00 00 c0 4d f8 00 f0  41 f8 00 f0 fe e3 00 f0  |"...M...A.......|
00000050  39 e7 00 f0 59 f8 00 f0  2e e8 00 f0 d4 ef 00 f0  |9...Y...........|
00000060  a4 f0 00 f0 f2 e6 00 f0  6e fe 00 f0 53 ff 00 f0  |........n...S...|
00000070  ed ef 00 f0 53 ff 00 f0  c7 ef 00 f0 ed 57 00 c0  |....S........W..|
00000080  53 ff 00 f0 53 ff 00 f0  53 ff 00 f0 53 ff 00 f0  |S...S...S...S...|
...
...
000afea0  00 00 00 00 00 00 00 00  aa aa aa 00 aa aa aa 00  |................|
000afeb0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000b0000  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
000c0000  55 aa 40 e9 62 0a 00 00  00 00 00 00 00 00 00 00  |[email protected]...........|
000c0010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 49 42  |..............IB|

Analyse

Der obere Teil oberhalb von 000c0000 könnte mit dem Bootloader zusammenhängen. Warum sollte ich das vermuten? Der Code 55aah vor Ort000c0000 kann in der Regel eine Markierung im Speicher sein, z. B. ein Auslöser für das BIOS, einen sekundären Bootloader auszuführen.

Referenz: Boot-Signatur - BIOS

  ss # 1

Da diese 55aah jedoch im Bereich c0000h-effffh auftreten, ist es wahrscheinlicher, dass dieser Teil der PNP-Erweiterungsheader ist:

Referenz: BIOS-Startspezifikation

3.3 Geräte mit PnP-Erweiterungsköpfen

Alle IPL-Geräte mit Options-ROMs müssen einen gültigen Options-ROM-Header enthalten, der sich zwischen den Systemspeicheradressen C0000h und EFFFFh an einer 2-KB-Grenze befindet und mit 55AAh beginnt. Das Booten eines Geräts kann nur gesteuert werden, wenn es über einen PnP-Erweiterungs-Header verfügt. Der Erweiterungs-Header, dessen Adresse sich im Standard-Options-ROM-Header bei Offset + 1Ah befindet, enthält wichtige Informationen zur Konfiguration des Geräts. Es enthält auch Verweise auf den Code im Options-ROM des Geräts (BCV oder BEV), den das BIOS aufruft, um vom Gerät aus zu starten. In Anhang A finden Sie Informationen zum Aufbau des PnP-Erweiterungs-Headers. Es gibt zwei Möglichkeiten, wie ein IPL-Gerät mit einem PnP-Erweiterungsheader gebootet werden kann. Es muss ein BCV oder ein BEV enthalten.

53ff ...

Zu den 53ffh-Daten, die am Anfang stehen. Mir ist nicht klar, was das eigentlich ist. Weitere Nachforschungen darüber sind wahrscheinlich, dass der Linux-Kernel dort geschrieben hat, nachdem das Booten des MBR durch das BIOS an den Linux-Kernel übergeben wurde, um ihn zu booten.

Normalerweise lädt der Bootloader den Kernel in den Speicher und springt dann zum Kernel. Der Kernel kann dann den vom Bootloader verwendeten Speicher zurückfordern (da er seinen Job bereits ausgeführt hat). Es ist jedoch möglich, OS-Code in den Boot-Sektor aufzunehmen und nach dem Start des Betriebssystems resident zu halten

Wenn ich weiter grabe, finde ich diesen Absatz in einem Forschungsbericht mit dem Titel: Malicious Code Injection via / dev / mem :

1 Das mem-Gerät

/ dev / mem ist die Treiberschnittstelle zum physisch adressierbaren Speicher. Die ursprüngliche Absicht von mem und kmem war es, beim Debuggen des Kernels behilflich zu sein. Wir können das Gerät wie ein normales Zeichengerät verwenden und mit lseek () einen Adressoffset auswählen. Das kmem-Gerät ist ähnlich, bietet jedoch ein Image des Kernel-Speichers im Kontext der virtuellen Adressierung. Der Xorg-Server verwendet das mem-Gerät für den Zugriff auf den VESA-Videospeicher sowie die BIOS-ROM-Interrupt-Vektortabelle (IVT) unter der physischen Adresse 0x00000000, um die Videomodi im VM86-Modus zu bearbeiten. DOSEMU verwendet dies auch für den Zugriff auf das BIOS IVT, um BIOS-Interrupts für verschiedene Aufgaben (Lesen von Datenträgern, Drucken auf die Konsole usw.) zu erstellen.

Verweise

slm
quelle