Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Der virtuelle sichere Modus (Virtual Secure Mode, VSM) ist eine Reihe von Hypervisorfunktionen und Erleuchtungen für Host- und Gastpartitionen, die die Erstellung und Verwaltung neuer Sicherheitsgrenzen innerhalb der Betriebssystemsoftware ermöglichen. VSM ist die Hypervisor-Einrichtung, auf der Windows-Sicherheitsfeatures wie Device Guard, Credential Guard, virtuelle TPMs und abgeschirmte VMs basieren. Diese Sicherheitsfeatures wurden in Windows 10 und Windows Server 2016 eingeführt.
VSM ermöglicht Betriebssystemsoftware in den Stamm- und Gastpartitionen, isolierte Speicherbereiche für die Speicherung und Verarbeitung von Systemsicherheitsressourcen zu erstellen. Der Zugriff auf diese isolierten Regionen wird gesteuert und ausschließlich über den Hypervisor gewährt, bei dem es sich um einen hochgradig privilegierten, hochgradig vertrauenswürdigen Teil der Trusted Compute Base (TCB) des Systems handelt. Da der Hypervisor auf einer höheren Berechtigungsstufe als Betriebssystemsoftware ausgeführt wird und exklusive Kontrolle über wichtige Systemhardwareressourcen wie Speicherzugriffsberechtigungssteuerungen in der CPU-MMU und IOMMU zu Beginn der Systeminitialisierung hat, kann der Hypervisor diese isolierten Regionen vor unbefugtem Zugriff schützen, auch vor Betriebssystemsoftware (z. B. Betriebssystem-Kernel- und Gerätetreibern) mit Aufsichtsmoduszugriff (z. B. CPL0, oder "Ring 0").
Mit dieser Architektur können die Ressourcen in isolierten Regionen, die durch den Hypervisor geschützt sind, auch wenn normale Software auf Systemebene, die im Aufsichtsmodus ausgeführt wird (z. B. Kernel, Treiber usw.), durch schadhafte Software kompromittiert wird.
Virtual Trust Level (VTL)
VSM erreicht und verwaltet isolationsbasierte Vertrauensebenen (Virtual Trust Levels, VTLs). VTLs werden sowohl pro Partition als auch pro virtueller Prozessor aktiviert und verwaltet.
Virtuelle Vertrauensstufen sind hierarchisch, wobei höhere Ebenen höher als niedrigere Ebenen sind. VTL0 ist die am wenigsten privilegierte Ebene, wobei VTL1 privilegierter ist als VTL0, VTL2 höher als VTL1 usw.
Architektonisch werden bis zu 16 Ebenen von VTLs unterstützt; Ein Hypervisor kann sich jedoch entscheiden, weniger als 16 VTL-Dateien zu implementieren. Derzeit werden nur zwei VTLs implementiert.
typedef UINT8 HV_VTL, *PHV_VTL;
#define HV_NUM_VTLS 2
#define HV_INVALID_VTL ((HV_VTL) -1)
#define HV_VTL_ALL 0xF
Jede VTL verfügt über einen eigenen Satz von Speicherzugriffsschutz. Diese Zugriffsschutzmechanismen werden vom Hypervisor im physischen Adressraum einer Partition verwaltet und können daher nicht von Software auf Systemebene geändert werden, die in der Partition ausgeführt wird.
Da privilegiertere VTLs ihre eigenen Speicherschutzfunktionen erzwingen können, können höhere VTLs bereiche des Arbeitsspeichers effektiv vor niedrigeren VTLs schützen. In der Praxis ermöglicht dies eine niedrigere VTL, isolierte Speicherbereiche zu schützen, indem sie mit einer höheren VTL gesichert werden. Beispielsweise könnte VTL0 einen geheimen Schlüssel in VTL1 speichern, an dem nur VTL1 darauf zugreifen konnte. Auch wenn VTL0 kompromittiert wird, wäre das Geheimnis sicher.
VTL-Schutz
Es gibt mehrere Facets zum Erreichen der Isolation zwischen VTLs:
- Speicherzugriffsschutz: Jede VTL verwaltet einen Satz von Schutzfunktionen für den physischen Gastspeicher. Software, die bei einer bestimmten VTL ausgeführt wird, kann nur in Übereinstimmung mit diesen Schutzmaßnahmen auf den Arbeitsspeicher zugreifen.
- Virtueller Prozessorstatus: Virtuelle Prozessoren verwalten einen separaten VTL-Zustand. Beispielsweise definiert jede VTL einen Satz privater VP-Register. Software, die bei einer niedrigeren VTL ausgeführt wird, kann nicht auf den Registerstatus des privaten virtuellen Prozessors des virtuellen Prozessors des höheren VTL zugreifen.
- Interrupts: Zusammen mit einem separaten Prozessorzustand verfügt jede VTL auch über ein eigenes Interrupt-Subsystem (lokale APIC auf x64, GIC CPU-Schnittstelle auf ARM64). Dies ermöglicht es höheren VTLs, Unterbrechungen zu verarbeiten, ohne störungen von einer niedrigeren VTL zu riskieren.
- Überlagerungsseiten: Bestimmte Überlagerungsseiten werden pro VTL beibehalten, sodass höhere VTLs einen zuverlässigen Zugriff haben. Es gibt z. B. eine separate Hypercall-Überlagerungsseite pro VTL.
VSM-Erkennung und -Status
Die VSM-Funktion wird für Partitionen über das AccessVsm-Partitionsberechtigungskennzeichnung angekündigt. Nur Partitionen mit allen folgenden Berechtigungen können VSM verwenden: AccessVsm, AccessVpRegisters und AccessSynicRegs.
VSM-Funktionserkennung
Gäste können über ein synthetisches Register auf einen Bericht zu VSM-Funktionen zugreifen.
Auf x64-Plattformen
Auf x64-Plattformen wird über ein MSR auf dieses Register zugegriffen:
| MSR-Adresse | Registername | Description |
|---|---|---|
| 0x000D0006 | HV_X64_REGISTER_VSM_CAPABILITIES | Bericht zu VSM-Funktionen. |
Auf ARM64-Plattformen
Auf ARM64-Plattformen wird über HvRegisterVsmCapabilities mithilfe des Hypercalls HvCallGetVpRegisters auf dieses Register zugegriffen.
Registerformat
Auf x64-Plattformen
| Binäre Ziffern | Description | Attribute |
|---|---|---|
| 63 | Dr6Shared | Lesen Sie |
| 62:47 | MbecVtlMask | Lesen Sie |
| 46 | DenyLowerVtlStartup | Lesen Sie |
| 45:0 | RsvdZ | Lesen Sie |
Auf ARM64-Plattformen
| Binäre Ziffern | Description | Attribute |
|---|---|---|
| 63 | RsvdZ | Lesen Sie |
| 62:47 | MbecVtlMask | Lesen Sie |
| 46 | DenyLowerVtlStartup | Lesen Sie |
| 45:0 | RsvdZ | Lesen Sie |
Feldbeschreibungen
Dr6Shared (nur x64): Gibt an, ob Dr6 ein gemeinsames Register zwischen den VTLs ist.
MbecVtlMask: Gibt dem Gast die VTLs an, für die MBEC aktiviert werden kann.
DenyLowerVtlStartup: Gibt an, ob ein VTL eine VP-Zurücksetzung durch eine niedrigere VTL verweigern kann.
VSM-Statusregister
Zusätzlich zu einer Partitionsberechtigungskennzeichnung können zwei virtuelle Register verwendet werden, um zusätzliche Informationen zum VSM-Status zu erfahren: HvRegisterVsmPartitionStatus und HvRegisterVsmVpStatus.
HvRegisterVsmPartitionStatus
HvRegisterVsmPartitionStatus ist ein schreibgeschütztes Register pro Partition, das für alle VTLs freigegeben wird. Dieses Register enthält Informationen dazu, welche VTLs für die Partition aktiviert wurden, welche VTLs modusbasierte Ausführungssteuerelemente aktiviert haben, sowie die maximal zulässige VTL.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 EnabledVtlSet : 16;
UINT64 MaximumVtl : 4;
UINT64 MbecEnabledVtlSet: 16;
UINT64 ReservedZ : 28;
};
} HV_REGISTER_VSM_PARTITION_STATUS;
HvRegisterVsmVpStatus
HvRegisterVsmVpStatus ist ein schreibgeschütztes Register und wird für alle VTLs freigegeben. Es handelt sich um ein pro VP-Register, was bedeutet, dass jeder virtuelle Prozessor seine eigene Instanz verwaltet. Dieses Register enthält Informationen darüber, welche VTLs aktiviert wurden, was aktiv ist, sowie den MBEC-Modus, der auf einem VP aktiv ist.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 ActiveVtl : 4;
UINT64 ActiveMbecEnabled : 1;
UINT64 ReservedZ0 : 11;
UINT64 EnabledVtlSet : 16;
UINT64 ReservedZ1 : 32;
};
} HV_REGISTER_VSM_VP_STATUS;
ActiveVtl ist die ID des VTL-Kontexts, der derzeit auf dem virtuellen Prozessor aktiv ist.
ActiveMbecEnabled gibt an, dass MBEC derzeit auf dem virtuellen Prozessor aktiv ist.
EnabledVtlSet ist eine Bitmap der VTL,die auf dem virtuellen Prozessor aktiviert sind.
Partition VTL Initial state
Wenn eine Partition gestartet oder zurückgesetzt wird, wird sie in VTL0 ausgeführt. Alle anderen VTLs sind bei der Partitionserstellung deaktiviert.
VTL-Aktivierung
Um mit der Verwendung einer VTL zu beginnen, muss eine niedrigere VTL Folgendes initiieren:
- Aktivieren Sie die Ziel-VTL für die Partition. Dadurch wird die VTL allgemein für die Partition verfügbar.
- Aktivieren Sie die Ziel-VTL auf einem oder mehreren virtuellen Prozessoren. Dadurch wird die VTL für einen VP verfügbar und legt den ursprünglichen Kontext fest. Es wird empfohlen, dass alle VPs über dieselben aktivierten VTLs verfügen. Wenn eine VTL für einige VPs (aber nicht alle) aktiviert ist, kann zu unerwartetem Verhalten führen.
- Sobald die VTL für eine Partition und VP aktiviert ist, kann sie mit dem Festlegen von Zugriffsschutzfunktionen beginnen, nachdem das EnableVtlProtection-Flag festgelegt wurde.
Beachten Sie, dass VTLs nicht aufeinander folgen müssen.
Aktivieren einer Ziel-VTL für eine Partition
Der HvCallEnablePartitionVtl Hypercall wird verwendet, um eine VTL für eine bestimmte Partition zu aktivieren. Beachten Sie, dass vor der Ausführung von Software in einer bestimmten VTL die VTL auf virtuellen Prozessoren in der Partition aktiviert sein muss.
Aktivieren einer Ziel-VTL für virtuelle Prozessoren
Sobald eine VTL für eine Partition aktiviert ist, kann sie auf den virtuellen Prozessoren der Partition aktiviert werden. Der HvCallEnableVpVtl-Hypercall kann verwendet werden, um VTLs für einen virtuellen Prozessor zu aktivieren, der seinen anfänglichen Kontext festlegt.
Virtuelle Prozessoren haben einen "Kontext" pro VTL. Wenn eine VTL gewechselt ist, wird auch der private Zustand der VTL gewechselt.
VTL-Konfiguration
Nachdem eine VTL aktiviert wurde, kann die Konfiguration von einem VP geändert werden, der auf einer gleich oder höheren VTL ausgeführt wird.
Partitionskonfiguration
Partitionsweite Attribute können mithilfe des HvRegisterVsmPartitionConfig-Registers konfiguriert werden. Es gibt eine Instanz dieses Registers für jede VTL (größer als 0) für jede Partition.
Jede VTL kann eine eigene Instanz von HV_REGISTER_VSM_PARTITION_CONFIG sowie Instanzen für niedrigere VTLs ändern. VTLs ändern dieses Register möglicherweise nicht für höhere VTLs.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 EnableVtlProtection : 1;
UINT64 DefaultVtlProtectionMask : 4;
UINT64 ZeroMemoryOnReset : 1;
UINT64 DenyLowerVtlStartup : 1;
UINT64 ReservedZ : 2;
UINT64 InterceptVpStartup : 1;
UINT64 ReservedZ : 54; };
} HV_REGISTER_VSM_PARTITION_CONFIG;
Die Felder dieses Registers werden unten beschrieben.
Aktivieren von VTL-Schutzfunktionen
Nachdem eine VTL aktiviert wurde, muss das EnableVtlProtection-Flag festgelegt werden, bevor es mit der Anwendung von Speicherschutzfunktionen beginnen kann. Dieses Kennzeichen ist einmal schreibgeschützt, was bedeutet, dass es nach dem Festlegen nicht mehr geändert werden kann.
Standardschutzmaske
Standardmäßig wendet das System RWX-Schutz auf alle aktuell zugeordneten Seiten und alle zukünftigen "hot-added"-Seiten an. Hot-added pages verweisen auf alle Speicher, die während eines Größenänderungsvorgangs zu einer Partition hinzugefügt werden.
Eine höhere VTL kann eine andere Standardspeicherschutzrichtlinie festlegen, indem DefaultVtlProtectionMask in HV_REGISTER_VSM_PARTITION_CONFIG angegeben wird. Diese Maske muss festgelegt werden, wenn die VTL aktiviert ist. Sie kann nicht mehr geändert werden, nachdem sie festgelegt wurde, und wird nur durch eine Partitionszurücksetzung gelöscht.
| Bit | Description |
|---|---|
| 0 | Lesen Sie |
| 1 | Schreiben |
| 2 | Kernelmodus wird ausgeführt (KMX) |
| 3 | Benutzermodusausführung (UMX) |
Null Arbeitsspeicher beim Zurücksetzen
ZeroMemOnReset ist ein Bit, das steuert, ob Der Arbeitsspeicher vor dem Zurücksetzen einer Partition null ist. Diese Konfiguration ist standardmäßig aktiviert. Wenn das Bit festgelegt ist, wird der Speicher der Partition beim Zurücksetzen nulliert, sodass der Speicher eines höheren VTL-Speichers nicht durch eine niedrigere VTL kompromittiert werden kann. Wenn dieses Bit gelöscht wird, wird der Speicher der Partition beim Zurücksetzen nicht auf null gesetzt.
DenyLowerVtlStartup
Das Flag "DenyLowerVtlStartup" steuert, ob ein virtueller Prozessor durch niedrigere VTLs gestartet oder zurückgesetzt werden kann. Dazu gehören architekturbezogene Methoden zum Zurücksetzen eines virtuellen Prozessors (z. B. SIPI auf X64) sowie des Hypercalls von HvCallStartVirtualProcessor .
InterceptVpStartup
Wenn das InterceptVpStartup-Flag festgelegt ist, generiert das Starten oder Zurücksetzen eines virtuellen Prozessors einen Abfangen auf die höhere VTL.
Konfigurieren niedrigerer VTLs
Das folgende Register kann von höheren VTLs verwendet werden, um das Verhalten niedrigerer VTLs zu konfigurieren:
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 MbecEnabled : 1;
UINT64 TlbLocked : 1;
UINT64 ReservedZ : 62;
};
} HV_REGISTER_VSM_VP_SECURE_VTL_CONFIG;
Jede VTL (höher als 0) verfügt über eine Instanz dieses Registers für jede VTL, die niedriger als sich selbst ist. Beispielsweise hätte VTL2 zwei Instanzen dieses Registers – eine für VTL1 und eine zweite für VTL0.
Die Felder dieses Registers werden unten beschrieben.
MbecEnabled
Dieses Feld konfiguriert, ob MBEC für die niedrigere VTL aktiviert ist.
TlbLocked
Dieses Feld sperrt die TLB der unteren VTL. Diese Funktion kann verwendet werden, um zu verhindern, dass niedrigere VTLs TLB-Ungültigmachungen verursachen, die eine höhere VTL beeinträchtigen können. Wenn dieses Bit festgelegt ist, werden alle Leeranforderungen des Adressraums von der unteren VTL blockiert, bis die Sperre aufgehoben wird.
Um die TLB zu entsperren, kann die höhere VTL dieses Bit löschen. Sobald ein VP zu einer niedrigeren VTL zurückkehrt, gibt er auch alle TLB-Sperren frei, die er zur Zeit enthält.
VTL-Eintrag
Eine VTL wird "eingegeben", wenn ein VP von einer niedrigeren VTL zu einer höheren wechselt. Dies kann aus folgenden Gründen geschehen:
- VTL-Aufruf: Dies ist der Fall, wenn software explizit Code in einer höheren VTL aufrufen möchte.
- Sicherer Interrupt: Wenn ein Interrupt für eine höhere VTL empfangen wird, wechselt der VP in die höhere VTL.
- Sicherer Abfangen: Bestimmte Aktionen lösen einen sicheren Interrupt aus (z. B. zugriff auf bestimmte MSRs).
Sobald eine VTL eingegeben wurde, muss sie freiwillig verlassen. Eine höhere VTL kann von einer niedrigeren VTL nicht vorgebeutet werden.
Identifizieren des VTL-Eintragsgrunds
Um angemessen auf einen Eintrag zu reagieren, muss eine höhere VTL möglicherweise den Grund für die Eingabe kennen. Um zwischen Einstiegsgründen zu unterscheiden, ist der VTL-Eintrag in der HV_VP_VTL_CONTROL-Struktur enthalten.
VTL-Anruf
Ein "VTL-Aufruf" erfolgt, wenn eine niedrigere VTL einen Eintrag in eine höhere VTL initiiert (z. B. um einen Speicherbereich mit höherer VTL) über den HvCallVtlCall-Hypercall zu schützen.
VTL-Aufrufe behalten den Status von freigegebenen Registern über VTL-Switches hinweg bei. Private Register werden auf einer Ebene pro VTL beibehalten. Die Ausnahme dieser Einschränkungen sind die Register/Anweisungen, die von der VTL-Aufrufsequenz benötigt werden.
Auf x64-Plattformen
Für einen VTL-Anruf auf x64 sind die folgenden Register erforderlich:
| x64 | x86 | Description |
|---|---|---|
| RCX | EDX:EAX | Gibt eine VTL-Aufrufsteuerungseingabe an den Hypervisor an. |
| RAX | ECX | Reserviert |
Alle Bits in der VTL-Anrufsteuerungseingabe sind derzeit reserviert.
Auf ARM64-Plattformen
Auf ARM64-Plattformen wird ein VTL-Aufruf mithilfe der HVC-Anweisung mit sofortigem Wert 2 initiiert. Der Hypervisor decodiert diesen spezifischen unmittelbaren Wert und verarbeitet ihn als HvCallVtlCall Hypercall. Für die Steuerungseingabe auf ARM64 ist kein spezifischer Registerzustand erforderlich.
Einschränkungen für VTL-Anrufe
VTL-Aufrufe können nur aus dem privilegiertesten Prozessormodus initiiert werden. Beispielsweise kann ein VTL-Aufruf auf x64-Systemen nur von CPL0 und auf ARM64-Systemen von EL1 stammen. Ein von einem Prozessormodus initiierter VTL-Aufruf, der alles andere als die privilegiertesten Elemente des Systems ist, führt dazu, dass der Hypervisor eine Ausnahme in den virtuellen Prozessor eingibt (#UD auf x64, undefinierte Anweisungs ausnahme auf ARM64).
Ein VTL-Aufruf kann nur in die nächste höchste VTL wechseln. Anders ausgedrückt: Wenn mehrere VTLs aktiviert sind, kann ein Aufruf eine VTL nicht "überspringen". Die folgenden Aktionen führen zu einer Ausnahme (#UD auf x64, undefinierte Anweisung auf ARM64):
- Ein VTL-Aufruf, der von einem Prozessormodus initiiert wurde, der nur die privilegiertesten Elemente des Systems (architekturspezifisch) ist.
- Ein VTL-Anruf aus dem realen Modus (nur x86/x64)
- Ein VTL-Aufruf auf einem virtuellen Prozessor, bei dem die Ziel-VTL deaktiviert ist (oder noch nicht aktiviert wurde).
- Ein VTL-Aufruf mit einem ungültigen Steuerelementeingabewert
VTL-Beendigung
Ein Wechsel zu einer niedrigeren VTL wird als "Return" bezeichnet. Nachdem eine VTL die Verarbeitung abgeschlossen hat, kann sie eine VTL-Rückgabe initiieren, um zu einer niedrigeren VTL zu wechseln. Die einzige Möglichkeit, wie eine VTL-Rückgabe auftreten kann, ist, wenn ein höherer VTL freiwillig einen initiiert. Eine niedrigere VTL kann niemals ein höheres VTL voraussetzen.
VTL-Rückgabe
Eine "VTL-Rückgabe" ist, wenn eine höhere VTL einen Schalter in eine niedrigere VTL über den HvCallVtlReturn Hypercall initiiert. Ähnlich wie bei einem VTL-Anruf wird der Zustand des privaten Prozessors ausgeschaltet, und der freigegebene Zustand bleibt vorhanden. Wenn die niedrigere VTL explizit in die höhere VTL aufgerufen wurde, erhöht der Hypervisor den Anweisungspunkt höherer VTL, bevor die Rückgabe abgeschlossen ist, damit er nach einem VTL-Aufruf fortgesetzt werden kann.
Auf x64-Plattformen
Für eine VTL-Rückgabecodesequenz auf x64 ist die Verwendung der folgenden Register erforderlich:
| x64 | x86 | Description |
|---|---|---|
| RCX | EDX:EAX | Gibt eine VTL-Rückgabesteuerelementeingabe an den Hypervisor an. |
| RAX | ECX | Reserviert |
Auf ARM64-Plattformen
Auf ARM64-Plattformen wird eine VTL-Rückgabe mithilfe der HVC-Anweisung mit sofortigem Wert 3 initiiert. Der Hypervisor decodiert diesen spezifischen unmittelbaren Wert und verarbeitet ihn als HvCallVtlReturn Hypercall.
Eingabe des VTL-Rückgabesteuerelements
Die Eingabe des VTL-Rückgabesteuerelements weist das folgende Format auf:
| Binäre Ziffern | Feld | Description |
|---|---|---|
| 63:1 | RsvdZ | |
| 0 | Schnelle Rückgabe | Register werden nicht wiederhergestellt. |
Die folgenden Aktionen generieren eine #UD Ausnahme:
- Versuch einer VTL-Rückgabe, wenn die niedrigste VTL derzeit aktiv ist
- Versuch einer VTL-Rückgabe mit einem ungültigen Steuerelementeingabewert
- Versuch einer VTL-Rückgabe aus einem Prozessormodus, der alles andere als die privilegiertesten Auf dem System ist (architekturspezifisch)
Schnelle Rückgabe
Als Teil der Verarbeitung einer Rückgabe kann der Hypervisor den Registerstatus der niedrigeren VTL aus der HV_VP_VTL_CONTROL-Struktur wiederherstellen. Beispielsweise kann eine höhere VTL nach der Verarbeitung eines sicheren Interrupts zurückkehren, ohne den Zustand der niedrigeren VTL zu unterbrechen. Daher stellt der Hypervisor einen Mechanismus bereit, mit dem die Register der niedrigeren VTL einfach in ihrem in der VTL-Steuerelementstruktur gespeicherten Voraufrufwert wiederhergestellt werden können.
Wenn dieses Verhalten nicht erforderlich ist, kann eine höhere VTL eine "schnelle Rückgabe" verwenden. Eine schnelle Rückgabe ist, wenn der Hypervisor den Registerstatus nicht aus der Steuerelementstruktur wiederherstellen kann. Dies sollte nach Möglichkeit genutzt werden, um unnötige Verarbeitungen zu vermeiden.
Dieses Feld kann mit Bit 0 der VTL-Rückgabeeingabe festgelegt werden. Wenn sie auf 0 festgelegt ist, werden die Register aus der HV_VP_VTL_CONTROL Struktur wiederhergestellt. Wenn dieses Bit auf 1 festgelegt ist, werden die Register nicht wiederhergestellt (eine schnelle Rückgabe).
Hypercall Page Assist (nur x64)
Auf x64-Plattformen bietet der Hypervisor Mechanismen zur Unterstützung von VTL-Aufrufen und -Rückgaben über die Hypercall-Seite. Diese Seite abstrahiert die spezifische Codesequenz, die zum Wechseln von VTLs erforderlich ist.
Auf die Codesequenzen zum Ausführen von VTL-Aufrufen und -Rückgaben kann durch Ausführen bestimmter Anweisungen auf der Hypercall-Seite zugegriffen werden. Die Aufruf-/Rückgabeblöcke befinden sich in einem Offset auf der Hypercall-Seite, die durch das virtuelle Register HvRegisterVsmCodePageOffsets bestimmt wird. Dies ist ein schreibgeschütztes und partitionsweites Register mit einer separaten Instanz pro VTL.
Eine VTL kann einen VTL-Aufruf/eine Rückgabe mithilfe der CALL-Anweisung ausführen. Ein ANRUF an den richtigen Ort auf der Hypercall-Seite initiiert einen VTL-Anruf/eine Rückgabe.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 VtlCallOffset : 12;
UINT64 VtlReturnOffset : 12;
UINT64 ReservedZ : 40;
};
} HV_REGISTER_VSM_CODE_PAGE_OFFSETS;
Zusammenfassend sind die Schritte zum Aufrufen einer Codesequenz mithilfe der Hypercall-Seite auf x64 wie folgt:
- Zuordnen der Hypercall-Seite in den GPA-Bereich eines VTL
- Ermitteln Sie den richtigen Offset für die Codesequenz (VTL-Aufruf oder Rückgabe).
- Führen Sie die Codesequenz mit CALL aus.
Hinweis: Auf ARM64-Plattformen werden VTL-Aufrufe und -Rückgaben direkt mithilfe der HVC-Anweisung mit bestimmten Unmittelbarwerten (2 für VTL-Aufruf, 3 für VTL-Rückgabe) ausgeführt, wie in den Abschnitten VTL-Aufruf und VTL-Rückgabe beschrieben. Das HvRegisterVsmCodePageOffsets-Register ist auf ARM64 nicht verfügbar.
Speicherzugriffsschutz
Ein erforderlicher Schutz, der von VSM bereitgestellt wird, ist die Möglichkeit, Speicherzugriffe zu isolieren.
Höhere VTLs haben einen hohen Grad an Kontrolle über den Typ des Speicherzugriffs, der durch niedrigere VTLs zulässig ist. Es gibt drei grundlegende Schutztypen, die von einer höheren VTL für eine bestimmte GPA-Seite angegeben werden können: Lesen, Schreiben und eXecute. Diese sind in der folgenden Tabelle definiert:
| Name | Description |
|---|---|
| Lesen Sie | Steuert, ob lesezugriff auf eine Speicherseite zulässig ist. |
| Schreiben | Steuert, ob schreibzugriff auf eine Speicherseite zulässig ist. |
| Ausführen | Steuert, ob Anweisungsabrufe für eine Speicherseite zulässig sind. |
Diese drei kombinieren für die folgenden Speicherschutztypen:
- Kein Zugriff
- Schreibgeschützt, keine Ausführung
- Schreibgeschützt, ausführen
- Lese-/Schreibzugriff, keine Ausführung
- Lese-/Schreibzugriff, ausführen
Wenn "modusbasiertes Ausführungssteuerelement (MBEC)" aktiviert ist, können Benutzer- und Kernelmodusschutz separat festgelegt werden.
Höhere VTLs können den Speicherschutz für eine GPA über den Hypercall HvCallModifyVtlProtectionMask festlegen.
Speicherschutzhierarchie
Speicherzugriffsberechtigungen können von einer Reihe von Quellen für eine bestimmte VTL festgelegt werden. Die Berechtigungen jeder VTL können möglicherweise durch eine Reihe anderer VTLs sowie durch die Hostpartition eingeschränkt werden. Die Reihenfolge, in der Schutzmaßnahmen angewendet werden, ist folgendes:
- Vom Host festgelegte Speicherschutz
- Speicherschutz, der von höheren VTLs festgelegt wird
Mit anderen Worten, VTL-Schutz ersetzt Hostschutz. VTLs auf höherer Ebene ersetzen VTLs auf niedrigerer Ebene. Beachten Sie, dass eine VTL möglicherweise keine Speicherzugriffsberechtigungen für sich selbst festgelegt hat.
Es wird erwartet, dass eine konforme Schnittstelle keinen Nicht-RAM-Typ über RAM überlagert.
Speicherzugriffsverletzungen
Wenn ein VP, der bei einer niedrigeren VTL ausgeführt wird, versucht, einen Speicherschutz zu verletzen, der durch eine höhere VTL festgelegt wurde, wird ein Abfangen generiert. Dieser Abfangabschnitt wird von der höheren VTL empfangen, die den Schutz festlegt. Dies ermöglicht es höheren VTLs, die Verletzung auf Fall-für-Fall-Basis zu behandeln. Beispielsweise kann die höhere VTL einen Fehler zurückgeben oder den Zugriff emulieren.
Modusbasiertes Execute-Steuerelement (MBEC)
Wenn eine VTL eine Speichereinschränkung auf eine niedrigere VTL platziert, kann es sinnvoll sein, beim Erteilen eines "Execute"-Privilegs zwischen Benutzer und Kernelmodus zu unterscheiden. Wenn z. B. Codeintegritätsprüfungen in einer höheren VTL stattfinden würden, würde die Möglichkeit, zwischen Benutzermodus und Kernelmodus zu unterscheiden, bedeuten, dass eine VTL codeintegrität nur für Kernelmodusanwendungen erzwingen könnte.
Neben den herkömmlichen drei Speicherschutzfunktionen (Lesen, Schreiben, Ausführen) führt MBEC eine Unterscheidung zwischen Benutzermodus und Kernelmodus für Ausführungsschutz ein. Wenn MBEC aktiviert ist, hat eine VTL die Möglichkeit, vier Speicherschutztypen festzulegen:
| Name | Description |
|---|---|
| Lesen Sie | Steuert, ob lesezugriff auf eine Speicherseite zulässig ist. |
| Schreiben | Steuert, ob schreibzugriff auf eine Speicherseite zulässig ist. |
| Benutzermodusausführung (UMX) | Steuert, ob Anweisungsabrufe, die im Benutzermodus generiert wurden, für eine Speicherseite zulässig sind. HINWEIS: Wenn MBEC deaktiviert ist, wird diese Einstellung ignoriert. |
| Kernelmodus wird ausgeführt (KMX) | Steuert, ob Anweisungsabrufe, die im Kernelmodus generiert werden, für eine Speicherseite zulässig sind. HINWEIS: Wenn MBEC deaktiviert ist, steuert diese Einstellung sowohl den Benutzermodus als auch den Kernelmodus, um Zugriffe auszuführen. |
Speicher, der mit den Schutzmechanismen "User-Mode Ausführen" gekennzeichnet ist, wäre nur ausführbar, wenn der virtuelle Prozessor im Benutzermodus ausgeführt wird. Ebenso wäre "Kernel-Mode Execute"-Speicher nur ausführbar, wenn der virtuelle Prozessor im Kernelmodus ausgeführt wird.
KMX und UMX können unabhängig festgelegt werden, sodass Ausführungsberechtigungen zwischen Benutzer und Kernelmodus unterschiedlich erzwungen werden. Alle Kombinationen von UMX und KMX werden unterstützt, mit Ausnahme von KMX=1, UMX=0. Das Verhalten dieser Kombination ist nicht definiert.
MBEC ist standardmäßig für alle VTLs und virtuellen Prozessoren deaktiviert. Wenn MBEC deaktiviert ist, bestimmt das Kernelmodus-Execute-Bit die Speicherzugriffseinschränkung. Wenn MBEC deaktiviert ist, ist KMX=1-Code sowohl im Kernel- als auch im Benutzermodus ausführbare Datei.
Beschreibungstabellen (nur x64)
Auf x64-Plattformen muss sich jeder Benutzermoduscode, der auf Beschreibungstabellen zugreift, in GPA-Seiten befinden, die als KMX=UMX=1 gekennzeichnet sind. Benutzermodussoftware, die auf Deskriptortabellen von einer GPA-Seite mit der Kennzeichnung KMX=0 zugreift, wird nicht unterstützt und führt zu einem allgemeinen Schutzfehler.
ARM64 verwendet keine x86-Stildeskriptortabellen; Speicherzugriffsberechtigungen werden durch Übersetzungstabelleneinträge und das EL-basierte Berechtigungsmodell gesteuert.
MBEC-Konfiguration
Um die modusbasierte Ausführungskontrolle zu verwenden, muss sie auf zwei Ebenen aktiviert sein:
- Wenn die VTL für eine Partition aktiviert ist, muss MBEC mit HvCallEnablePartitionVtl aktiviert werden.
- MBEC muss pro VP und pro VTL mit HvRegisterVsmVpSecureConfigVtlX konfiguriert werden.
MBEC-Interaktion mit Supervisor Mode Execution Prevention (SMEP) (nur x64)
Supervisor-Mode Execution Prevention (SMEP) ist ein Prozessorfeature, das auf x64-Plattformen unterstützt wird. SMEP kann sich auf den Betrieb von MBEC aufgrund seiner Einschränkung des Aufsichtszugriffs auf Speicherseiten auswirken. Der Hypervisor hält die folgenden Richtlinien im Zusammenhang mit SMEP ein:
- Wenn SMEP für das Gastbetriebssystem nicht verfügbar ist (sei es aufgrund von Hardwarefunktionen oder Prozessorkompatibilitätsmodus), funktioniert MBEC nicht betroffen.
- Wenn SMEP verfügbar ist und aktiviert ist, funktioniert MBEC nicht betroffen.
- Wenn SMEP verfügbar ist und deaktiviert ist, unterliegen alle Ausführungseinschränkungen dem KMX-Steuerelement. Daher dürfen nur codemarkierten KMX=1 ausgeführt werden.
Isolation des virtuellen Prozessorzustands
Virtuelle Prozessoren verwalten separate Zustände für jede aktive VTL. Einige dieser Zustände sind jedoch privat für eine bestimmte VTL, und der verbleibende Zustand wird von allen VTLs geteilt.
Der Hypervisor verwaltet einen pro-VTL-Kontext für jeden virtuellen Prozessor und speichert alle sichtbaren Gastprozessorzustände, die zwischen VTLs isoliert werden müssen. Jede VTL verfügt über eine eigene Instanz des privaten Zustands, einschließlich Steuerelementregistern, Ausnahmevektoren, Systemkonfigurationsregistern und synthetische Hypervisorregistern. Dieser pro VTL-Speicher stellt beim Wechseln zwischen Vertrauensstufen eine vollständige Isolation des Ausführungskontexts sicher.
Der Zustand, der pro VTL (a.k.a. privater Zustand) beibehalten wird, wird vom Hypervisor über VTL-Übergänge hinweg gespeichert. Wenn ein VTL-Switch initiiert wird, speichert der Hypervisor den aktuellen privaten Zustand für die aktive VTL und wechselt dann zum privaten Zustand der Ziel-VTL. Der freigegebene Zustand bleibt unabhängig von VTL-Switches aktiv.
Privater Zustand
Jeder VTL verwaltet einen eigenen vollständigen Ausführungskontext, der aus:
- Ausführungszustand: Anweisungszeiger (PC/RIP), Stapelzeiger (SP/RSP), Prozessorflags (PSTATE/RFLAGS)
- Steuerelementregister: Speicherverwaltungskonfiguration (Seitentabellen, Übersetzungssteuerelemente, Speicherattribute)
- Ausnahmebehandlung: Ausnahme-/Interruptvektoren, Ausnahmesyndromregister, Fehleradressenregister
- Systemkonfiguration: Prozessorfeaturesteuerelemente, Debugsteuerelemente, Zeitgeberkonfiguration
- Synthetische Register: Hypervisorschnittstelle registriert spezifisch für jede VTL (Hypercall-Seite, Gastbetriebssystem-ID, Referenz-TSC, synthetischer Interruptcontroller)
Diese Isolation stellt sicher, dass jede VTL eine unabhängige Kontrolle über ihre Ausführungsumgebung hat und den privaten Zustand anderer VTLs nicht beobachten oder beeinträchtigen kann.
Auf x64-Plattformen
Auf x64-Plattformen verwaltet jede VTL ihren eigenen Ausführungskontext über architekturspezifische MSRs und Register. Der Hypervisor behält diese über VTL-Switches hinweg bei und stellt eine vollständige Isolation der Ausführungsumgebung sicher.
Private MSRs steuern Systemaufrufmechanismen, Speicherattribute, Prozessorfeatures und die Hypervisorschnittstelle.
Architektur-MSRs:
- SYSENTER_CS, SYSENTER_ESP, SYSENTER_EIP, STAR, LSTAR, CSTAR, SFMASK, EFER, PAT, KERNEL_GSBASE, FS. BASE, GS. BASE, TSC_AUX
- Lokale APIC-Register (einschließlich CR8/TPR)
Synthetische MSRs:
- HV_X64_MSR_HYPERCALL
- HV_X64_MSR_GUEST_OS_ID
- HV_X64_MSR_REFERENCE_TSC
- HV_X64_MSR_APIC_FREQUENCY
- HV_X64_MSR_EOI
- HV_X64_MSR_ICR
- HV_X64_MSR_TPR
- HV_X64_MSR_VP_ASSIST_PAGE
- HV_X64_MSR_NPIEP_CONFIG
- HV_X64_MSR_SIRBP
- HV_X64_MSR_SCONTROL
- HV_X64_MSR_SVERSION
- HV_X64_MSR_SIEFP
- HV_X64_MSR_SIMP
- HV_X64_MSR_EOM
- HV_X64_MSR_SINT0 – HV_X64_MSR_SINT15
- HV_X64_MSR_STIMER0_CONFIG – HV_X64_MSR_STIMER3_CONFIG
- HV_X64_MSR_STIMER0_COUNT – HV_X64_MSR_STIMER3_COUNT
Private Register steuern die Ausführungsumgebung , die Speicherverwaltung und die Ausnahmebehandlung:
- Ausführungszustand: RIP (Anweisungszeiger), RSP (Stapelzeiger), RFLAGS (Prozessorflags)
- Speicherverwaltung: CR0 (Prozessorsteuerung), CR3 (Seitentabellenbasis), CR4 (Prozessorfunktionen)
- Beschreibungstabellen: IDTR (Interruptdeskriptortabelle), GDTR (globale Beschreibungstabelle)
- Segmentregister: CS, DS, ES, FS, GS, SS, TR, LDTR
- Debugsteuerelement: DR7 (Debugsteuerelementregister)
- Zeitstempel: TSC (Zeitstempelzähler, bereitstellen unabhängiger Zeitverweis pro VTL)
- Debugstatus: DR6 (Debugstatusregister – abhängig vom Prozessortyp; lesen Sie HvRegisterVsmCapabilities, um zu bestimmen, ob freigegeben oder privat)
Auf ARM64-Plattformen
Auf ARM64-Plattformen verwaltet jede VTL ihren eigenen vollständigen Systemregisterkontext. Der Hypervisor behält diese Register über VTL-Switches hinweg bei und stellt eine vollständige Isolation der Ausführungs- und Ausnahmeumgebung sicher.
Der Ausführungsstatus registriert die Steuerung des Programmflusses und des Prozessormodus:
- PC (Programmzähler), SP_EL0, SP_EL1 (Stapelzeiger)
- PSTATE (Prozessorstatuskennzeichnungen), FPCR/FPSR (Gleitkommasteuerung/Status)
- ELR_EL1, SPSR_EL1 (Ausnahmelinkregister, Gespeicherter Programmstatus)
Speicherverwaltung und Übersetzungskontrolle registriert virtuelle Arbeitsspeicher konfigurieren:
- TTBR0_EL1, TTBR1_EL1 (Übersetzungstabellenbasisregister)
- TCR_EL1 (Übersetzungskontrollregister)
- MAIR_EL1 (Speicherattribute-Dereferenzierungsregister)
- SCTLR_EL1 (Systemsteuerungsregister)
- CONTEXTIDR_EL1 (Kontextbezeichner)
Ausnahme- und Interruptbehandlung registriert das Verhalten der Steuerelement-Ausnahme:
- VBAR_EL1 (Vektorbasisadressregister - Ausnahmevektortabellenposition)
- ESR_EL1 (Ausnahmesyndromregister)
- FAR_EL1 (Fehleradressenregister)
- AFSR0_EL1, AFSR1_EL1 (Zusatzfehlerstatusregister)
Die Systemkonfiguration registriert die Steuerungsprozessorfunktionen:
- CPACR_EL1 (Coprocessor-Zugriffssteuerung)
- ACTLR_EL1 (Hilfssteuerungsregister)
- AMAIR_EL1 (Zusätzliches Speicherattribute-Dereferenzierungsregister)
- ZCR_EL1, SMCR_EL1 (SVE/SME-Konfiguration, sofern unterstützt)
Debug- und Leistungsüberwachungsregister sind VTL-privat. Dazu gehören alle Debugsystemregister (MDSCR_EL1, DBGBCR_EL1[], DBGBVR_EL1[], DBGWCR_EL1[], DBGWVR_EL1[], etc.) und alle Leistungsüberwachungsregister (PMCR_EL0 und zugehörige PMU-Register)
Zeitgeberkonfigurationsregister :
- CNTKCTL_EL1 (Kerneltimersteuerelement)
- CNTV_CTL_EL0, CNTV_CVAL_EL0 (virtuelles Timersteuerelement und Vergleichswert)
Threadidentifikationsregister :
- TPIDR_EL0, TPIDR_EL1, TPIDRRO_EL0 (Thread-ID-Register)
Synthetische Hypervisor-Register (zugriff über Hypercalls, nicht direkt als Systemregister):
- HvRegisterGuestOsId (Gastbetriebssystem-Identifikation)
- HvRegisterHypercallMsrValue (Hypercall Interface Enablement)
- HvRegisterReferenceTsc (Referenzzeitstempelzählerseite)
- HvRegisterVpAssistPage (VP Assist-Seite für diese VTL)
- Register des synthetischen Interruptcontrollers (SynIC)
- Synthetische Zeitgeberregister (Stimer0-3)
- Schnittstelle des lokalen Interruptcontrollers (GIC CPU-Schnittstelle)
Diese umfassende Isolation pro VTL-Register stellt sicher, dass jede VTL die vollständige Kontrolle über die Ausführungsumgebung, die Speicherverwaltung, die Ausnahmebehandlung und die Hypervisorschnittstelle ohne Störungen anderer VTLs hat.
Gemeinsamer Zustand
VTLs teilen bestimmten Prozessorstatus, um den Mehraufwand von VTL-Übergängen zu reduzieren und eine effiziente Kommunikation zwischen Vertrauensebenen zu ermöglichen. Der freigegebene Zustand umfasst allgemeine Register, die für Berechnung und Datenübergabe, Gleitkommastatus und bestimmte Systemstatusregister verwendet werden, die sich nicht auf Sicherheitsgrenzen auswirken.
Durch die Freigabe von allgemeinen Registern über VTLs hinweg kann ein VTL-Aufruf Parameter direkt in Registern übergeben, und eine VTL-Rückgabe kann Ergebnisse zurückgeben, ohne dass speicherbasierte Kommunikation erforderlich ist. Dieses Design verbessert die Leistung von VTL-Aufrufen erheblich, während die vom privaten Zustand bereitgestellte Sicherheitsisolation beibehalten wird.
Auf x64-Plattformen
Auf x64-Plattformen umfasst der gemeinsame Zustand allgemeine Register für Berechnungen, Systeminformationsregister und bestimmte Statusregister, die sich nicht auf die Sicherheitsisolation auswirken.
Gemeinsam genutzte MSRs bieten Systeminformationen und -konfigurationen, die über VTLs hinweg verwendet werden:
- HV_X64_MSR_TSC_FREQUENCY
- HV_X64_MSR_VP_INDEX
- HV_X64_MSR_VP_RUNTIME
- HV_X64_MSR_RESET
- HV_X64_MSR_TIME_REF_COUNT
- HV_X64_MSR_GUEST_IDLE
- HV_X64_MSR_DEBUG_DEVICE_OPTIONS
- MTRRs
- MCG_CAP
- MCG_STATUS
Freigegebene Register ermöglichen eine effiziente Datenübergabe und Berechnung über VTLs:
- General-Purpose Register: Rax, Rbx, Rcx, Rdx, Rsi, Rdi, Rbp, R8-R15 (verwendet für Berechnung und Parameterübergabe während VTL-Aufrufen)
- Ausnahmeinformationen: CR2 (lineare Seitenfehleradresse – freigegeben für Ausnahmebehandlungskontext)
- Debugdaten: DR0-DR3 (Debugadressenregister – für Haltepunktadressen verwendet)
-
Floating-Point und Vektorstatus:
- X87-Gleitkommazustand (Legacy-Gleitkommaberechnung)
- XMM-Zustand (128-Bit-SSE-Vektoren)
- AVX-Zustand (256-Bit-Vektoren)
- XCR0/XFEM (erweitertes Feature aktivieren Mask)
- Debugstatus: DR6 (Debugstatusregister – abhängig vom Prozessortyp; lesen Sie HvRegisterVsmCapabilities, um zu bestimmen, ob freigegeben oder privat)
Auf ARM64-Plattformen
Auf ARM64-Plattformen umfasst der gemeinsam genutzte Zustand Register, die für Berechnungen, Datenübergaben und Gleitkommavorgänge verwendet werden. Diese Freigabe ermöglicht effiziente VTL-Aufrufe, indem Parameter und Ergebnisse direkt in Registern übergeben werden können.
Freigegebene Register ermöglichen Die Berechnung und Kommunikation über VTLs hinweg:
-
General-Purpose Register: X0-X17, X19-X28 (für Berechnung und Parameterübergabe verwendet)
- X0-X7 in der Regel für Funktionsparameter und Rückgabewerte bei VTL-Aufrufen verwendet
- X8-X17, X19-X28 für die allgemeine Berechnung verfügbar
- Hinweis: X18 (Plattformregister) und PC sind aus Sicherheitsgründen privat pro VTL
- Hinweis: X29 (FP/Frame pointer), X30 (LR/link register) und SP sind privat pro VTL
-
Floating-Point und Vektorstatus:
- Q0-Q31 (128-Bit NEON/Gleitkommaregister für die Vektorberechnung)
- Erweiterter SIMD-Zustand (NEON) für Vektorvorgänge
- Hinweis: SVE-Zustand (Z0-Z31, P0-P15, FFR) und SME-Status sind VTL-privat. Der untere 128-Bit-Teil (Q-Register) wird freigegeben, aber die oberen Bits von Z-Registern können bei VTL-Übergängen beschädigt sein. Software sollte sich nicht darauf verlassen, dass Z-Registerinhalte über VTL-Switches beibehalten werden.
- Hinweis: SPE (Statistische Profilerstellungserweiterung) wird für VTLs freigegeben, mit Ausnahme von PMBSR_EL1, die VTL-privat ist
-
Systeminformationsregister (schreibgeschützt oder nicht sicherheitskritisch):
- Systemidentifikations- und Featureregister
- Cache- und TLB-Typinformationen
ARM64 folgt demselben Prinzip wie x64: Der allgemeine Berechnungszustand wird für die Effizienz freigegeben, während der Kontroll- und Konfigurationszustand, der sich auf Sicherheitsgrenzen auswirkt, für jede VTL privat bleibt.
Real-Modus (nur x64)
Der reale Modus wird für jede VTL, die größer als 0 ist, auf x64-Plattformen nicht unterstützt. VTLs, die größer als 0 sind, können im 32-Bit- oder 64-Bit-Modus auf x64 ausgeführt werden.
VTL Interrupt Management
Um eine hohe Isolation zwischen virtuellen Vertrauensstufen zu erzielen, stellt der virtuelle sichere Modus ein separates Interrupt-Subsystem für jede auf einem virtuellen Prozessor aktivierte VTL bereit. Dadurch wird sichergestellt, dass eine VTL sowohl Unterbrechungen senden als auch empfangen kann, ohne Störungen von einer weniger sicheren VTL zu stören.
Jede VTL verfügt über einen eigenen Interruptcontroller, der nur aktiv ist, wenn der virtuelle Prozessor in diesem speziellen VTL ausgeführt wird. Wenn ein virtueller Prozessor VTL-Zustände wechselt, wird der auf dem Prozessor aktive Interruptcontroller ebenfalls umgeschaltet.
Auf x64-Plattformen verfügt jede VTL über eine separate lokale APIC-Instanz. Auf ARM64-Plattformen verfügt jede VTL über einen separaten GIC.
Eine Unterbrechung, die auf eine VTL ausgerichtet ist, die höher als die aktive VTL ist, führt zu einem sofortigen VTL-Schalter. Die höhere VTL kann dann den Interrupt empfangen. Wenn der höhere VTL-Wert aufgrund seiner Prioritätsmaske (TPR/CR8 auf x64, GIC-Prioritätsmaske auf ARM64) nicht empfangen kann, wird der Interrupt als "ausstehend" gehalten, und die VTL wechselt nicht. Wenn mehrere VTLs mit ausstehenden Unterbrechungen vorhanden sind, hat die höchste VTL Vorrang (ohne Vorherige Ankündigung an die niedrigere VTL).
Wenn ein Interrupt auf eine niedrigere VTL ausgerichtet ist, wird der Interrupt erst übermittelt, wenn der virtuelle Prozessor das nächste Mal in die zielorientierte VTL wechselt.
Auf x64-Plattformen werden INIT- und Start-IPIs, die auf eine niedrigere VTL abzielen, auf einem virtuellen Prozessor verworfen, wobei eine höhere VTL aktiviert ist. Da Architekturprozessorstartmechanismen blockiert werden können, sollte der Hypercall von HvCallStartVirtualProcessor verwendet werden, um Prozessoren zu starten.
Auf ARM64-Plattformen werden PSCI-Schnittstellenmethoden (z. B. CPU_ON) für die Online-Bereitstellung von Prozessoren ähnlich blockiert, wenn eine höhere VTL aktiviert ist. Der HvCallStartVirtualProcessor Hypercall bietet einen konsistenten plattformübergreifenden Mechanismus zum Starten von Prozessoren.
Interruptmasken und VTL-Schalter
Auf x64-Plattformen
Für den Zweck des Wechsels von VTLs, RFLAGS. WENN wirkt sich nicht darauf aus, ob ein sicherer Interrupt einen VTL-Switch auslöst. Wenn RFLAGS. WENN zu Maskieren von Unterbrechungen gelöscht wird, verursachen Unterbrechungen in höhere VTLs weiterhin einen VTL-Wechsel zu einer höheren VTL. Nur der höhere TPR/CR8-Wert der VTL wird bei der Entscheidung berücksichtigt, ob sofort unterbrochen werden soll.
Dieses Verhalten wirkt sich auch auf ausstehende Unterbrechungen bei einer VTL-Rückgabe aus. Wenn der RFLAGS. WENN Bit gelöscht wird, um Unterbrechungen in einer bestimmten VTL zu maskieren, und die VTL gibt (zu einer niedrigeren VTL) zurück, bewertet der Hypervisor alle ausstehenden Unterbrechungen erneut. Dies führt zu einem sofortigen Rückruf an die höhere VTL.
Auf ARM64-Plattformen
Ebenso wirken sich die PSTATE-Interruptmaskenbits (DAIF) nicht darauf aus, ob ein sicherer Interrupt einen VTL-Schalter auslöst. Wenn Unterbrechungen über PSTATE maskiert werden, verursachen Unterbrechungen, die auf höhere VTLs ausgerichtet sind, weiterhin einen VTL-Switch. Nur die GIC-Prioritätsmaske der höheren VTL wird bei der Entscheidung berücksichtigt, ob der Interrupt sofort geliefert werden soll.
Assistent für virtuelle Unterbrechungsbenachrichtigungen
Höhere VTLs können sich registrieren, um eine Benachrichtigung zu erhalten, wenn sie die sofortige Übermittlung eines Interrupts an eine niedrigere VTL desselben virtuellen Prozessors blockieren. Höhere VTLs können virtual Interrupt Notification Assist (VINA) über ein virtuelles Register HvRegisterVsmVina aktivieren:
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 Vector : 8;
UINT64 Enabled : 1;
UINT64 AutoReset : 1;
UINT64 AutoEoi : 1;
UINT64 ReservedP : 53;
};
} HV_REGISTER_VSM_VINA;
Jede VTL auf jedem VP verfügt über eine eigene VINA-Instanz sowie über eine eigene Version von HvRegisterVsmVina. Die VINA-Einrichtung generiert einen ausgelösten Edge-Interrupt an die aktuell aktive höhere VTL, wenn ein Interrupt für die niedrigere VTL sofort zur Auslieferung bereit ist.
Um zu verhindern, dass eine Flut von Unterbrechungen auftritt, wenn diese Anlage aktiviert ist, umfasst die VINA-Anlage einen begrenzten Zustand. Wenn ein VINA-Interrupt generiert wird, wird der Zustand der VINA-Einrichtung in "Asserted" geändert. Durch das Senden eines End-of-Interrupts an den SINT, der der VINA-Einrichtung zugeordnet ist, wird der Status "Asserted" nicht gelöscht. Der behauptete Zustand kann nur auf eine von zwei Arten gelöscht werden:
- Der Zustand kann manuell gelöscht werden, indem er in das Feld "VinaAsserted" der HV_VP_VTL_CONTROL Struktur schreibt.
- Der Status wird beim nächsten Eintrag der VTL automatisch gelöscht, wenn die Option "Bei VTL-Eintrag automatisch zurücksetzen" im HvRegisterVsmVina-Register aktiviert ist.
Dadurch kann Code, der bei einer sicheren VTL ausgeführt wird, nur über den ersten Interrupt benachrichtigt werden, der für eine niedrigere VTL empfangen wird. Wenn ein sicherer VTL über zusätzliche Unterbrechungen benachrichtigt werden möchte, kann es das Feld "VinaAsserted" der Seite "VP Assist" löschen und über den nächsten neuen Interrupt benachrichtigt werden.
Sichere Abschnitte
Der Hypervisor ermöglicht es einem höheren VTL, Abfangen für Ereignisse zu installieren, die im Kontext einer niedrigeren VTL stattfinden. Dadurch erhalten höhere VTLs eine erhöhte Kontrolle über VTL-Ressourcen mit niedrigeren VTL-Ressourcen. Sichere Abfangen können verwendet werden, um systemkritische Ressourcen zu schützen und Angriffe von niedrigeren VTLs zu verhindern.
Ein sicherer Abfangen wird an die höhere VTL in die Warteschlange gestellt, und die VTL kann auf dem VP ausgeführt werden.
Sichere Abfangentypen
| Intercept Type | Abfangen gilt für |
|---|---|
| Speicherzugriff | Der Versuch, auf GPA-Schutzmaßnahmen zuzugreifen, die von einer höheren VTL eingerichtet wurden. |
| Steuern des Registerzugriffs | Der Versuch, auf eine Reihe von Steuerelementregistern zuzugreifen, die von einer höheren VTL angegeben werden. |
Geschachtelte Abschnitte
Mehrere VTLs können sichere Abfangen für dasselbe Ereignis in einer niedrigeren VTL installieren. Daher wird eine Hierarchie eingerichtet, um zu entscheiden, wo geschachtelte Abschnitte benachrichtigt werden. Die folgende Liste ist die Reihenfolge, in der Der Schnittpunkt benachrichtigt wird:
- Lower VTL
- Höhere VTL
Behandeln sicherer Abfangen
Sobald ein VTL über einen sicheren Abfangen benachrichtigt wurde, muss er Maßnahmen ergreifen, damit die niedrigere VTL fortgesetzt werden kann. Die höhere VTL kann den Abfangen auf verschiedene Arten verarbeiten, darunter: Einfügen einer Ausnahme, Emulieren des Zugriffs oder Bereitstellen eines Proxys für den Zugriff. Wenn der private Zustand des niedrigeren VTL VP geändert werden muss, sollte HvCallSetVpRegisters verwendet werden.
Secure Register Intercepts (nur x64)
Auf x64-Plattformen kann ein höherer VTL zugriff auf bestimmte Kontrollregister und MSRs abfangen. Dies wird durch Festlegen von HvX64RegisterCrInterceptControl mithilfe des Hypercalls HvCallSetVpRegisters erreicht. Durch Festlegen des Steuerelementbits in HvX64RegisterCrInterceptControl wird ein Abfangen für jeden Zugriff des entsprechenden Steuerelementregisters ausgelöst.
Dieses Feature ist spezifisch für x64, da es x64-Steuerregister (CR0, CR4, XCR0) und x64 MSRs (EFER, LSTAR, STAR usw.) abfangen kann. ARM64-Plattformen können ähnliche Abfangenfunktionen über verschiedene Mechanismen unterstützen.
typedef union
{
UINT64 AsUINT64;
struct
{
UINT64 Cr0Write : 1;
UINT64 Cr4Write : 1;
UINT64 XCr0Write : 1;
UINT64 IA32MiscEnableRead : 1;
UINT64 IA32MiscEnableWrite : 1;
UINT64 MsrLstarRead : 1;
UINT64 MsrLstarWrite : 1;
UINT64 MsrStarRead : 1;
UINT64 MsrStarWrite : 1;
UINT64 MsrCstarRead : 1;
UINT64 MsrCstarWrite : 1;
UINT64 ApicBaseMsrRead : 1;
UINT64 ApicBaseMsrWrite : 1;
UINT64 MsrEferRead : 1;
UINT64 MsrEferWrite : 1;
UINT64 GdtrWrite : 1;
UINT64 IdtrWrite : 1;
UINT64 LdtrWrite : 1;
UINT64 TrWrite : 1;
UINT64 MsrSysenterCsWrite : 1;
UINT64 MsrSysenterEipWrite : 1;
UINT64 MsrSysenterEspWrite : 1;
UINT64 MsrSfmaskWrite : 1;
UINT64 MsrTscAuxWrite : 1;
UINT64 MsrSgxLaunchControlWrite : 1;
UINT64 RsvdZ : 39;
};
} HV_REGISTER_CR_INTERCEPT_CONTROL;
Maskenregister
Um eine feinere Steuerung zu ermöglichen, verfügen auch eine Teilmenge von Steuerelementregistern über entsprechende Maskenregister. Maskenregister können verwendet werden, um Abschnitte in einer Teilmenge der entsprechenden Steuerelementregister zu installieren. Wenn kein Maskenregister definiert ist, löst jeder Zugriff (wie durch HvX64RegisterCrInterceptControl definiert) einen Abfangen aus.
Der Hypervisor unterstützt die folgenden Maskenregister: HvX64RegisterCrInterceptCr0Mask, HvX64RegisterCrInterceptCr4Mask und HvX64RegisterCrInterceptIa32MiscEnableMask.
DMA und Geräte
Geräte verfügen effektiv über die gleiche Berechtigungsstufe wie VTL0. Wenn VSM aktiviert ist, wird der gesamte vom Gerät zugewiesene Speicher als VTL0 markiert. Alle DMA-Zugriffe haben dieselben Berechtigungen wie VTL0.