2016-10-27 2 views
2

Für ein Nebenprojekt versuche ich eine halb-programmierbare x86 virtuelle Maschine zu schreiben.Wie handhaben (x86) virtuelle Maschinen im Allgemeinen Flags?

Ich verstehe die Formate, so dass die meisten der Entwurf ist relativ einfach, aber nach der Ausführung einer Anweisung mit seinen Operanden, Flags werden oft geändert. Es wäre sehr ineffizient, jedes mögliche Bit zu prüfen, also dachte ich daran, das Flag-Register in die VM zu stecken, es UND zu verknüpfen und dann das Flag-Register der VM zu setzen. Dies ist jedoch noch ein Los Overhead.

Das ist grenzwertig, aber gibt es etwas, das mir fehlt?

+2

Es ist unklar, was Sie tun. – Jester

+2

Uhm, normalerweise hypervisors emulieren nicht einen Instruktions-Pipe-Schritt, aber lassen den Gast-Code (größtenteils) unverändert laufen, fangen im Hypervisor-Kernel ein, wenn die Hardware einen privilegierten Befehl entdeckt. Natürlich ist es in der Praxis viel komplizierter als das, aber der Punkt ist, dass man sich im Allgemeinen nur dann um den Zustand der Flags kümmern muss, wenn man den Hypervisor einsperrt, nicht nach jeder Anweisung. –

+0

@Jester Ich denke, er baut einen Emulator. – fuz

Antwort

6

Wenn Sie wollen, dass Ihr Emulator den Prozessor so simuliert, wie er ist, dann müssen Sie die Flags genau emulieren.

Dies bedeutet Löschen von Bits, die gelöscht werden müssen (mit UND), Setzen von Bits, die gesetzt werden müssen (mit ODER), und Kopieren/Berechnen von Bits, wenn erforderlich (dh das Z-Flag erfordert testen, ob das Ergebnis Null ist, der Übertrag erfordert, um zu wissen, ob Sie einen Überlauf haben, etc.)

Es gibt keinen Weg um ihn herum.

Dies ist genau wie das Decodieren des R/M mod Bytes. Sie müssen dieses Byte nicht laden, überprüfen Sie den Modus, um festzustellen, ob dies ein Register oder ein Speicherzugriff ist, und wenden Sie diese entsprechend an ...

Und in der Tat bedeutet das, dass Ihr Emulator wird "viel langsamer (Es sei denn, Sie emulieren einen alten 10Mhz-Prozessor mit einem modernen Prozessor 3Ghz, wenn Sie trotzdem Zeit haben, 300 Zyklen von Anweisungen auszuführen ... so sollten Sie in Ordnung sein.)

Wenn Sie interessiert sind, schrieb ich a 6502 emulator und habe es mit einem Apple 2 ROM getestet. Ich musste Schlaf hinzufügen, um es nicht mit 100 MHz oder mehr laufen zu lassen ... (dieser Prozessor lief ursprünglich 1Mhz ...)

+2

Es gibt einen Weg herum, es heißt faule Auswertung: speichere genug Informationen zum Kalkulieren Flags, aber tue es noch nicht x86 schreibt Flags öfter als es liest –

+0

@PeterCordes Ja, ich könnte mir vorstellen, dass du das letzte Ergebnis in einer Variablen behalten und es verwenden kannst, wenn du das Z, C, V und möglicherweise auch einige andere Flags.Es kann schneller sein als die Flags jedes Mal zu bewerten.Es kann jedoch in einigen Situationen kompliziert sein, wie zum Beispiel _conflicts_ bei der Berechnung von C zwischen einem "ADC" und einem "ROL" Befehl. –

5

Sie scheinen zu fragen, emulieren x86, nicht virtualisieren. Seit modern x86 hardware supports virtualization, wo die CPU Gast-Code nativ ausführt und nur für einige privilegierte Anweisungen an den Hypervisor abfängt, das ist, was der Begriff "Virtualisierung" normalerweise bedeutet.


Faul flag evalution ist typisch. Anstatt alle Flags tatsächlich zu berechnen, speichern Sie einfach die Operanden aus dem letzten Befehl, der Flags setzt. Wenn dann tatsächlich die Flags gelesen werden, müssen Sie herausfinden, was die Flag-Werte sein müssen.

Das bedeutet, dass PF und AF nicht jedesmal neu berechnet werden müssen (fast jede Anweisung), nur jedes Mal wenn sie gelesen werden (meistens nur PUSHF oder Interrupts, kaum Code liest jemals PF (außer für FP-Zweige, wo es NaN bedeutet)). Das Berechnen von PF nach jeder Integer-Anweisung ist in reinem C teuer, da es einen Popcount auf den niedrigen 8 Bits der Ergebnisse erfordert. (Und ich denke, dass C-Compiler im Allgemeinen dieses Muster nicht erkennen und setp selbst verwenden, geschweige denn pushf oder lahf, um mehrere Flags zu speichern, wenn sie einen x86-Emulator kompilieren, um auf einem x86-Host zu laufen Muster und emittieren popcnt Anweisungen, wenn Ziel Host-CPUs, die diese Funktion haben (z. B. -march=nehalem)).

BOCHS verwendet diese Technik und beschreibt die Implementierung in einigen Details im Abschnitt Lazy Flags dieser kurzen PDF: How Bochs Works Under the Hood 2nd edition.Sie speichern das Ergebnis, so dass sie ZF, SF und PF und den Übertrag von den hohen 2 Bits für CF und OF und von Bit 3 für AF ableiten können. Damit müssen sie nie eine Anweisung wiederholen, um ihre Flag-Ergebnisse zu berechnen.

Es gibt zusätzliche Komplikationen von einigen Anweisungen nicht alle Flaggen zu schreiben (das heißt partial-Flag-Updates) und vermutlich von Anweisungen wie BSF, die ZF auf der Grundlage der Eingang nicht die Ausgabe.


Weiterführende Literatur:

This paper on emulators.com gibt viele Details, wie Flaggen, um effizient genug Zustand zu speichern zu rekonstruieren. Es hat eine "2.1 Lazy Arithmetic Flags für CPU-Emulation".

Einer der Autoren ist Darek Mihocka (lange Emulator Schriftsteller, arbeitet jetzt offensichtlich bei Intel). Er hat viel interessantes darüber geschrieben, wie man Nicht-JIT-Emulatoren schnell laufen lässt, und CPU-Performance-Sachen im Allgemeinen, vieles davon steht auf seiner Seite, http://www.emulators.com/. Z.B. this article über die Vermeidung von Branch-Misprediction in einem Interpreter-Loop des Emulators, die zu Funktionen, die jeden Opcode implementieren, löst, ist sehr interessant. Darek ist auch der Co-Autor des Artikels über die Interna von BOCHS, die ich vorher verlinkt habe.

Eine Google für faule Flagge eval traf auch relevant sein können: https://silviocesare.wordpress.com/2009/03/08/lazy-eflags-evaluation-and-other-emulator-optimisations/

Zuletzt Emulation von x86-wie Flaggen aufkam, beantworten Sie die discussion in comments auf meinen faulen Fahnen einige interessante Sachen hatte: z @ Raymond Chen vorgeschlagen, dass Link zu der Mihocka & Troeger Papier, und @amdn wies darauf hin, dass JIT dynamische Übersetzung schneller Emulation als Interpretation produzieren kann.

Verwandte Themen