x86-Virtualisierung bezeichnet hardware- und softwarebasierte Mechanismen zur Unterstützung der Virtualisierung für Prozessoren, die auf der x86-Architektur basieren. Sie erlaubt es unter Verwendung eines Hypervisors, mehrere Betriebssysteme parallel auf einem x86-Prozessor auszuführen und die Ressourcen isoliert und effizient zwischen den parallel ausgeführten Betriebssystemen aufzuteilen. Die (Gast-)Betriebssysteme sollten bei der vollständigen Virtualisierung keinen Unterschied zwischen virtualisiertem (Parallel-)Betrieb und (exklusivem) Betrieb direkt auf der Hardware erkennen können.

Entwicklung der x86-Virtualisierung Seit Ende der 1990er Jahre wurde Virtualisierung für x86-Prozessoren durch komplexe Softwareimplementierungen erreicht, die notwendig waren, da es den damaligen Prozessormodellen an hardwareseitiger Unterstützung für die Virtualisierung fehlte. Erst 2006 kündigten AMD (AMD-V), gefolgt von Intel (VT-x) die Einführung von hardwareseitiger Unterstützung für die Virtualisierung an. Allerdings boten die ersten Versionen der Implementierung nur sehr geringe Geschwindigkeitsvorteile gegenüber den rein softwareseitig implementierten Virtualisierungslösungen.Keith Adams, Ole Agesen: A Comparison of Software and Hardware Techniques for x86 Virtualization. (PDF; 153 kB) VMware. ASPLOS’06 October 21–25, 2006, San Jose, California. „Surprisingly, we find that the first-generation hardware support rarely offers performance advantages over existing software techniques. We ascribe this situation to high VMM/guest transition costs and a rigid programming model that leaves little room for software flexibility in managing either the frequency or cost of these transitions.“ Bessere hardwareseitige Virtualisierungsunterstützung wurde erst später mit der Entwicklung neuerer Prozessormodelle erreicht.

Softwarebasierte Virtualisierung Um Ressourcen exklusiv den parallel laufenden Gastsystemen zuteilen zu können, darf nur dem Hostbetriebssystem bzw. dem Hypervisor direkter Zugriff auf die Prozessor-Hardware gewährt werden, während die Gastsysteme wie alle anderen Applikationen nur eingeschränkte Zugriffsrechte auf die Hardware haben dürfen. So kann insbesondere verhindert werden, dass die Gastsysteme Speicherbereiche sehen bzw. ändern können, die der Hypervisor zur Verwaltung benötigt.

Mit dem 80286-Prozessor wurde in der x86-Welt der sogenannte Protected Mode eingeführt. Mit ihm wurden vier verschiedene als Ringe bezeichnete Schutzebenen bzw. Befugnisstufen (englisch privilege levels) eingeführt, die den darauf ablaufenden Codesegmenten unterschiedliche Rechte gewähren. Erst mit der Einführung dieses Konzeptes war es möglich, Virtualisierung auf Basis der x86-Architektur zu implementieren: Im Protected Mode läuft der Betriebssystem-Kernel in einem höher privilegierten Modus, der als Ring 0 bezeichnet wird, und Applikationen in einem weniger privilegierten Modus, in der Regel entweder Ring 1 oder Ring 3.

Der Hypervisor bzw. das Hostbetriebssystem werden aufgrund ihrer privilegierten Stellung bei der Ressourcenverwaltung mit Ring-0-Berechtigung ausgeführt. Gastsysteme müssen, um den Schutz der Hypervisor-Ressourcen zu gewährleisten, folglich entweder auf Berechtigungslevel Ring 1 (im sogenannten 0/1/3 Modell) oder Ring 3 (im sogenannten 0/3/3 Modell) ausgeführt werden.

Deprivilegierung Da Betriebssysteme für die x86-Architektur (die als Gastsystem keinen Unterschied zwischen virtualisiertem Betrieb und Betrieb direkt auf der Hardware sehen dürfen) so implementiert sind, dass sie von der Ring-0-Berechtigung ausgehen und auch nur dann korrekt funktionieren, muss die Virtualisierungslösung zwei Features implementieren, nämlich Ring-Deprivilegierung und Ring Aliasing: Die Ring-Deprivilegierung sorgt dafür, dass das Gastsystem alle Befehle so ausführen kann, als hätte es Ring-0-Berechtigungen auf der Hardware, obwohl es durch die Virtualisierung weniger privilegierte Berechtigungen hat. Das Ring Aliasing sorgt dafür, dass das Gastsystem, wenn es eine Aktion ausführt, immer die Antwort erhält, die es erhalten würde, wenn der Befehl mit Ring-0-Berechtigungen ausgeführt worden wäre. Beispielsweise existiert ein Befehl zur Abfrage des Privilegierungslevels, der mit allen Berechtigungsleveln aufgerufen werden darf. Würde ein Gastsystem diesen Befehl ohne Ring Aliasing aufrufen, würde es Ring 1 oder 3 als Antwort erhalten, mit Ring Aliasing erhält es Ring 0.

Primär- und Shadowstrukturen Der Hypervisor benötigt außerdem eigene Speicherbereiche, in denen Verwaltungsdaten z. B. zu den Zuständen der verschiedenen VMs gespeichert werden. Dabei muss sichergestellt werden, dass die zur VM gehörigen Speicherbereiche für diese zwar sichtbar und ggf. auch änderbar sind, jedoch dürfen die abgelegten Verwaltungsdaten des Hypervisors nicht sichtbar sein oder gar verändert werden. Der Speicher muss vielmehr so erscheinen, als würde er exklusiv durch die jeweilige VM benutzt. Um das zu gewährleisten, werden die entsprechenden Speicherbereiche mehrfach vorgehalten: In der Primärstruktur werden die Hypervisor-Daten in den für jede VM vorhandenen Sekundär- oder auch Shadowstrukturen genannten Bereichen der VMs gespeichert. Für Prozessorregister werden die Zugriffe durch den Hypervisor normalerweise abgefangen (trapped) und der Zustand des Prozessors über die Shadowstruktur emuliert. Bei jedem Speicherzugriff der VMs muss der Hypervisor kontrollieren, ob es sich um einen solchen besonders geschützten Speicherbereich handelt, und ggf. die Daten aus der Shadowstruktur der jeweiligen VM statt aus der Primärstruktur zur Verfügung stellen, jedoch ohne dass die VM aus ihrer Sicht dies feststellen kann. Diese Technik wird auch als Tracing bezeichnet.

Softwarebasierte Vollvirtualisierung für die x86-Architektur Um diese Funktionen zu implementieren, wird normalerweise ein nach der Trap-and-Emulate-Methode funktionierendes Verfahren bereits hardwareseitig im Prozessor bereitgestellt. Es stand in der x86-Architektur bis 2006 (danach siehe hier), aber keine Hardwareunterstützung für die Virtualisierung zur Verfügung, so dass o. g. Funktionen softwareseitig implementiert werden mussten. Allerdings lässt sich das Trap-and-Emulate-Verfahren nicht softwareseitig ohne Hardwaresupport im Prozessor umsetzen, sodass man für die softwarebasierte Virtualisierung einen anderen Weg gehen musste: Die sogenannte Binärcode-Übersetzung wird eingesetzt, um Anweisungen des Gastsystems auf Prozessorinstruktionslevel von Ring-3-/Ring-1-Anweisungen in entsprechende Ring-0-Anweisungen des Host-Systems zu übersetzen – und zwar in geeigneter Art und Weise, um Ring-Deprivilegierung und Ring Aliasing umzusetzen. Eine Reihe von wichtigen Datenstrukturen, die durch den Prozessor benutzt werden, müssen geshadowed werden. Da die meisten Gastbetriebssysteme benutzen und direkter Zugriff auf die Speicherbereiche ggf. zum Überschreiben von Daten des Hypervisors bzw. anderer VMs führen würde, muss einiges, was normalerweise durch die Memory Management Unit des Prozessors geleistet wird, softwareseitig im Hypervisor nochmals implementiert werden, um dies zu verhindern. Insbesondere ist es eben erforderlich, den direkten Zugriff der Gastsysteme auf die primären Seitentabellen zu verhindern, indem alle Zugriffe darauf abgefangen und softwareseitig emuliert werden. Die x86-Architektur setzt außerdem ein (das sind Prozessorzustandsdaten, die nicht in Prozessorregistern, sondern außerhalb des Prozessors im Speicher abgelegt sind), um Segment-Deskriptoren des Prozessors zwischenzuspeichern und ggf. wiederherzustellen. Sobald die Speicherbereiche in den Prozessor geladen wurden, um die Segmentdeskriptoren wiederherzustellen, wird der für den ursprünglich verwendete Speicherbereich freigegeben und kann sofort, z. B. durch Anwendungsprozesse, überschrieben werden. Deswegen müssen auch implementiert werden, um Änderungen an diesen Speicherbereichen durch die VMs nachvollziehen zu können. I/O-Geräte der Gastsysteme, die im Hostbetriebssystem nicht unterstützt werden, müssen durch entsprechende Softwareemulatoren auf dem Hostbetriebssystem emuliert werden.

Um diese komplexen Aufgaben softwareseitig zu implementieren, wurden die ersten Virtualisierungsprodukte als Typ-2-Hypervisoren zum Einsatz auf Workstation-Computern konzipiert. Der Hypervisor wurde auf dem Hostbetriebssystem in einem Kernelmodul ausgeführt. Dadurch mussten zumindest keine Treiber für die Hosthardware entwickelt werden, da ohnehin schon sehr viel Aufwand zur Implementierung der oben beschriebenen Verfahren notwendig war.

Diese Art der Implementierung des Hypervisors führte zu geringerer relativer Performance der VMs (im Relation zur Performance des Hostprozessors), insbesondere aufgrund der softwareseitig reimplementierten Teile der MMU im Vergleich zur Performance von VMs auf CPU-Architekturen, die bereits hardwareseitig eine Virtualisierung der MMU vorsehen wie z. B. die IBM-System/370-Architektur

Es gab außerdem eine kontroverse wissenschaftliche Diskussion darüber, ob die x86-Architektur ohne hardwaregestützte Virtualisierungsfeatures wie hier beschrieben überhaupt die Voraussetzungen zur Virtualisierung gemäß den von Popek and Goldberg aufgestellten Kriterien erfüllt. VMware-Forscher zeigten 2006 in einem ASPLOS-Aufsatz, dass die oben dargestellten Techniken die x86-Plattform virtualisierbar im Sinne der drei von Popek und Goldberg aufgestellten Kriterien macht, jedoch nicht mit Hilfe der ebenfalls von Popek und Goldberg beschriebenen klassischen „trap-and-emulate“-Technik.

Softwarebasierte Paravirtualisierung für die x86-Architektur Ein anderer Ansatz zur Implementierung der Virtualisierung wurde von Hypervisoren wie Denali, L4 und Xen verfolgt. Um die Implementierung zu vereinfachen, wurde eine grundsätzliche Forderung nicht umgesetzt, nämlich die, dass das Gastbetriebssystem unverändert sowohl auf einem virtualisierten wie auf einem nicht virtualisierten System lauffähig sein solle. Es wurden spezielle Versionen der Gastbetriebssysteme entwickelt, die für den Betrieb mit dem jeweiligen Hypervisor abgestimmt waren. Diese Hypervisoren virtualisierten dabei besonders schwierig zu implementierende und performancehemmende Aspekte der x86-Architektur nicht, z. B. die I/O-Virtualisierung. Dieser als Paravirtualisierung bezeichnete Ansatz kann signifikante Performancegewinne bringen, wie im SOSP-Xen-Aufsatz von 2003 nachgewiesen wird. Die Paravirtualisierung spielt heute vor allem im Embedded Umfeld noch eine wichtige Rolle.

Softwarebasierte Vollvirtualisierung für die x86-64-Architektur Die erste Version von x86-64 von AMD (AMD64) erlaubte keine ausschließlich softwarebasierte Virtualisierung mehr, da es keinen Support für Segmentierung im (also für die 64-Bit-Adressierung) mehr bot und damit den Schutz des Speichers des rein softwarebasierten Hypervisors nicht erlaubte. Die Revisionen D und alle folgenden 64-Bit-AMD-Prozessoren (grob gesagt alle in 90-nm-Technologie und darunter entworfenen Chips) wurde mit grundlegendem Support für Segmentation im Long Mode ausgestattet, womit 64-Bit-Gastsysteme auf 64-Bit-Hostsystemenen über Binärcode-Übersetzung virtualisiert werden konnten.

Intel bot ebenfalls keinen Support für Segmentierung im Long Mode für seine x86-64-Prozessoren an, wodurch wie auch bei AMDs ersten Chips keine softwarebasierte 64-Bit-Virtualisierung möglich war. Im Unterschied zu AMD bot Intel allerdings mit VT-x zu diesem Zeitpunkt bereits hardwareunterstützte Virtualisierung für seine 64-Bit-Prozessoren an.

Hardwareunterstützte Virtualisierung