Ja, sie benötigen den Maschinencode und alle Speicheroperanden.
Sollte die CPU nicht nacheinander auf die Speicherseiten zugreifen, dh zuerst die Anweisung lesen und dann auf den Speicheroperanden zugreifen?
Ja, das passiert logischerweise, aber eine Seitenfehlerausnahme unterbricht diesen zweistufigen Prozess und verwirft jeden Fortschritt. Die CPU kann sich nicht merken, welche Anweisung sich in der Mitte eines Seitenfehlers befand.
Wenn ein Seitenfehler-Handler nach der Behandlung eines gültigen Seitenfehlers zurückkehrt, ist RIP = die Adresse des Fehlerbefehls, sodass die CPU erneut versucht, ihn von Grund auf neu auszuführen .
Es wäre für das Betriebssystem legal, den Maschinencode des fehlerhaften Befehls zu ändern und zu erwarten, dass es nach iret
dem Seitenfehler-Handler (oder einem anderen Ausnahme- oder Interrupt-Handler) einen anderen Befehl ausführt . AFAIK ist es architektonisch erforderlich, dass die CPU den Code-Abruf von CS: RIP wiederholt, falls Sie sprechen. (Angenommen, es kehrt sogar zum fehlerhaften CS: RIP zurück, anstatt einen anderen Prozess zu planen, während auf einen Festplattenfehler auf der Festplatte gewartet wird, oder einen SIGSEGV an einen Signalhandler bei einem ungültigen Seitenfehler zu senden.)
Es ist wahrscheinlich auch architektonisch für den Ein- / Ausstieg von Hypervisoren erforderlich. Und selbst wenn dies auf dem Papier nicht ausdrücklich verboten ist, funktionieren CPUs nicht so.
@torek kommentiert, dass einige (CISC) Mikroprozessoren Anweisungen teilweise dekodieren und den Mikroregister-Status bei einem Seitenfehler ausgeben , aber x86 ist nicht so.
Einige Anweisungen sind unterbrechbar und können teilweise Fortschritte machen, z. B. rep movs
(memcpy in a can) und andere Zeichenfolgenanweisungen, oder Lasten / Streuspeicher sammeln. Der einzige Mechanismus besteht jedoch darin, Architekturregister wie RCX / RSI / RDI für String-Ops oder die Ziel- und Maskenregister für Gather zu aktualisieren (z. B. manuell für AVX2vpgatherdd
). Wenn der Opcode / Decod nicht beibehalten wird, führt dies zu einem versteckten internen Register und einem Neustart nach dem Iret von einem Seitenfehler-Handler. Dies sind Anweisungen, die mehrere separate Datenzugriffe ausführen.
Denken Sie auch daran, dass x86 (wie die meisten ISAs) garantiert, dass Anweisungen atomar geschrieben sind. Interrupts / Ausnahmen: Sie treten entweder vollständig oder gar nicht vor einem Interrupt auf. Unterbrechen einer Montageanweisung während des Betriebs . So add [mem], reg
wäre beispielsweise erforderlich, die Last zu verwerfen, wenn das Speicherteil fehlerhaft ist, auch ohne lock
Präfix.
Die ungünstigste Anzahl von Gastbenutzerseiten, die vorhanden sind, um Fortschritte zu erzielen, beträgt möglicherweise 6 (plus separate Gastbaum-Seitentabellen-Teilbäume für jede Seite):
movsq
oder movsw
2-Byte-Befehl, der sich über eine Seitengrenze erstreckt, sodass beide Seiten zum Dekodieren benötigt werden.
- qword source operand
[rsi]
auch ein seitensplit
- qword Zieloperand
[rdi]
auch eine Seitenaufteilung
Wenn eine dieser 6 Seiten fehlerhaft ist, sind wir wieder auf dem ersten Platz.
rep movsd
ist auch eine 2-Byte-Anweisung, und Fortschritte in einem Schritt zu machen, hätte die gleiche Anforderung. Ähnliche Fälle wie push [mem]
oder pop [mem]
könnten mit einem falsch ausgerichteten Stapel konstruiert werden.
Einer der Gründe (oder Nebeneffekte) dafür, Sammellasten / Streuspeicher "unterbrechbar" zu machen (Aktualisieren des Maskenvektors mit ihrem Fortschritt), besteht darin, zu vermeiden, dass dieser minimale Platzbedarf erhöht wird, um einen einzelnen Befehl auszuführen. Auch zur Verbesserung der Effizienz bei der Behandlung mehrerer Fehler während einer Erfassung oder Streuung.
@Brandon weist in Kommentaren darauf hin, dass ein Gast seine Seitentabellen im Speicher benötigt und die Seitenaufteilungen für den Benutzerbereich auch 1-GB-Aufteilungen sein können, sodass sich die beiden Seiten in unterschiedlichen Unterbäumen der PML4 der obersten Ebene befinden. HW Page Walk muss alle diese Seiten mit Gastseitentabellen berühren, um Fortschritte zu erzielen. Es ist unwahrscheinlich, dass eine solche pathologische Situation zufällig eintritt.
Der TLB (und die Page-Walker-Interna) dürfen einige der Seitentabellendaten zwischenspeichern und müssen den Page-Walk nicht von Grund auf neu starten, es sei denn, das Betriebssystem hat invlpg
ein neues CR3-Seitenverzeichnis der obersten Ebene erstellt oder festgelegt. Beides ist nicht erforderlich, wenn eine Seite von nicht vorhanden in vorhanden geändert wird. x86 auf Papier garantiert, dass es nicht benötigt wird (daher ist "negatives Caching" nicht vorhandener PTEs nicht zulässig, zumindest für Software nicht sichtbar). Daher kann es sein, dass die CPU nicht VMexit wird, selbst wenn einige der physischen Seiten mit Gast-Seitentabellen nicht vorhanden sind.
PMU-Leistungsindikatoren können so aktiviert und konfiguriert werden, dass der Befehl auch ein Perf-Ereignis zum Schreiben in einen PEBS-Puffer für diesen Befehl erfordert . Wenn die Maske eines Zählers so konfiguriert ist, dass nur Anweisungen für den Benutzerbereich und nicht der Kernel gezählt werden, kann es durchaus sein, dass bei jeder Rückkehr in den Benutzerbereich immer wieder versucht wird, den Zähler zu überlaufen und ein Sample im Puffer zu speichern, was zu einem Seitenfehler führt.