blob: 459a08bccbe157142f623dbd2d41671d3e3e6d93 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#pragma once
#include <hypervisor/packet_mux.h>
// clang-format off
#define X86_MSR_IA32_VMX_PINBASED_CTLS 0x0481 // Pin-based controls
#define X86_MSR_IA32_VMX_PROCBASED_CTLS 0x0482 // Primary processor-based controls
#define X86_MSR_IA32_VMX_EXIT_CTLS 0x0483 // VM-exit controls
#define X86_MSR_IA32_VMX_ENTRY_CTLS 0x0484 // VM-entry controls
#define X86_MSR_IA32_VMX_PROCBASED_CTLS2 0x048b // Secondary processor-based controls
#define X86_MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x048d // True pin-based controls
#define X86_MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x048e // True primary processor-based controls
#define X86_MSR_IA32_VMX_TRUE_EXIT_CTLS 0x048f // True VM-exit controls
#define X86_MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x0490 // True VM-entry controls
/* PROCBASED_CTLS2 flags */
#define PROCBASED_CTLS2_APIC_ACCESS (1u << 0)
#define PROCBASED_CTLS2_EPT (1u << 1)
#define PROCBASED_CTLS2_RDTSCP (1u << 3)
#define PROCBASED_CTLS2_VPID (1u << 5)
#define PROCBASED_CTLS2_INVPCID (1u << 12)
/* PROCBASED_CTLS flags */
#define PROCBASED_CTLS_INT_WINDOW_EXITING (1u << 2)
#define PROCBASED_CTLS_HLT_EXITING (1u << 7)
#define PROCBASED_CTLS_CR3_LOAD_EXITING (1u << 15)
#define PROCBASED_CTLS_CR3_STORE_EXITING (1u << 16)
#define PROCBASED_CTLS_CR8_LOAD_EXITING (1u << 19)
#define PROCBASED_CTLS_CR8_STORE_EXITING (1u << 20)
#define PROCBASED_CTLS_TPR_SHADOW (1u << 21)
#define PROCBASED_CTLS_IO_EXITING (1u << 24)
#define PROCBASED_CTLS_MSR_BITMAPS (1u << 28)
#define PROCBASED_CTLS_PROCBASED_CTLS2 (1u << 31)
/* PINBASED_CTLS flags */
#define PINBASED_CTLS_EXT_INT_EXITING (1u << 0)
#define PINBASED_CTLS_NMI_EXITING (1u << 3)
/* EXIT_CTLS flags */
#define EXIT_CTLS_64BIT_MODE (1u << 9)
#define EXIT_CTLS_SAVE_IA32_PAT (1u << 18)
#define EXIT_CTLS_LOAD_IA32_PAT (1u << 19)
#define EXIT_CTLS_SAVE_IA32_EFER (1u << 20)
#define EXIT_CTLS_LOAD_IA32_EFER (1u << 21)
/* ENTRY_CTLS flags */
#define ENTRY_CTLS_IA32E_MODE (1u << 9)
#define ENTRY_CTLS_LOAD_IA32_PAT (1u << 14)
#define ENTRY_CTLS_LOAD_IA32_EFER (1u << 15)
/* LINK_POINTER values */
#define LINK_POINTER_INVALIDATE UINT64_MAX
/* GUEST_XX_ACCESS_RIGHTS flags */
#define GUEST_XX_ACCESS_RIGHTS_UNUSABLE (1u << 16)
// See Volume 3, Section 24.4.1 for access rights format.
#define GUEST_XX_ACCESS_RIGHTS_TYPE_A (1u << 0)
#define GUEST_XX_ACCESS_RIGHTS_TYPE_W (1u << 1)
#define GUEST_XX_ACCESS_RIGHTS_TYPE_E (1u << 2)
#define GUEST_XX_ACCESS_RIGHTS_TYPE_CODE (1u << 3)
// See Volume 3, Section 3.4.5.1 for valid non-system selector types.
#define GUEST_XX_ACCESS_RIGHTS_S (1u << 4)
#define GUEST_XX_ACCESS_RIGHTS_P (1u << 7)
#define GUEST_XX_ACCESS_RIGHTS_L (1u << 13)
// See Volume 3, Section 3.5 for valid system selectors types.
#define GUEST_TR_ACCESS_RIGHTS_TSS_BUSY (11u << 0)
/* VMCS fields */
enum class VmcsField16 : uint64_t {
VPID = 0x0000, // Virtual processor ID
GUEST_CS_SELECTOR = 0x0802, // Guest CS selector
GUEST_TR_SELECTOR = 0x080e, // Guest TR selector
HOST_ES_SELECTOR = 0x0c00, // Host ES selector
HOST_CS_SELECTOR = 0x0c02, // Host CS selector
HOST_SS_SELECTOR = 0x0c04, // Host SS selector
HOST_DS_SELECTOR = 0x0c06, // Host DS selector
HOST_FS_SELECTOR = 0x0c08, // Host FS selector
HOST_GS_SELECTOR = 0x0c0a, // Host GS selector
HOST_TR_SELECTOR = 0x0c0c, // Host TR selector
};
enum class VmcsField64 : uint64_t {
MSR_BITMAPS_ADDRESS = 0x2004, // Address of MSR bitmaps
EXIT_MSR_STORE_ADDRESS = 0x2006, // VM-exit MSR-store address
EXIT_MSR_LOAD_ADDRESS = 0x2008, // VM-exit MSR-load address
ENTRY_MSR_LOAD_ADDRESS = 0x200a, // VM-entry MSR-load address
VIRTUAL_APIC_ADDRESS = 0x2012, // Virtual-APIC address
APIC_ACCESS_ADDRESS = 0x2014, // APIC-access address
EPT_POINTER = 0x201a, // EPT pointer
GUEST_PHYSICAL_ADDRESS = 0x2400, // Guest physical address
LINK_POINTER = 0x2800, // VMCS link pointer
GUEST_IA32_PAT = 0x2804, // Guest PAT
GUEST_IA32_EFER = 0x2806, // Guest EFER
HOST_IA32_PAT = 0x2c00, // Host PAT
HOST_IA32_EFER = 0x2c02, // Host EFER
};
enum class VmcsField32 : uint64_t {
PINBASED_CTLS = 0x4000, // Pin-based controls
PROCBASED_CTLS = 0x4002, // Primary processor-based controls
EXCEPTION_BITMAP = 0x4004, // Exception bitmap
PAGEFAULT_ERRORCODE_MASK = 0x4006, // Page-fault error-code mask
PAGEFAULT_ERRORCODE_MATCH = 0x4008, // Page-fault error-code match
EXIT_CTLS = 0x400c, // VM-exit controls
EXIT_MSR_STORE_COUNT = 0x400e, // VM-exit MSR-store count
EXIT_MSR_LOAD_COUNT = 0x4010, // VM-exit MSR-load count
ENTRY_CTLS = 0x4012, // VM-entry controls
ENTRY_MSR_LOAD_COUNT = 0x4014, // VM-entry MSR-load count
ENTRY_INTERRUPTION_INFORMATION = 0x4016, // VM-entry interruption-information field
ENTRY_EXCEPTION_ERROR_CODE = 0x4018, // VM-entry exception error code
PROCBASED_CTLS2 = 0x401e, // Secondary processor-based controls
INSTRUCTION_ERROR = 0x4400, // VM instruction error
EXIT_REASON = 0x4402, // Exit reason
EXIT_INTERRUPTION_INFORMATION = 0x4404, // VM-exit interruption information
EXIT_INTERRUPTION_ERROR_CODE = 0x4406, // VM-exit interruption error code
EXIT_INSTRUCTION_LENGTH = 0x440c, // VM-exit instruction length
EXIT_INSTRUCTION_INFORMATION = 0x440e, // VM-exit instruction information
HOST_IA32_SYSENTER_CS = 0x4c00, // Host SYSENTER CS
GUEST_GDTR_LIMIT = 0x4810, // Guest GDTR Limit
GUEST_IDTR_LIMIT = 0x4812, // Guest IDTR Limit
GUEST_CS_ACCESS_RIGHTS = 0x4816, // Guest CS Access Rights
GUEST_ES_ACCESS_RIGHTS = 0x4814, // Guest ES Access Rights
GUEST_SS_ACCESS_RIGHTS = 0x4818, // Guest SS Access Rights
GUEST_DS_ACCESS_RIGHTS = 0x481a, // Guest DS Access Rights
GUEST_FS_ACCESS_RIGHTS = 0x481c, // Guest FS Access Rights
GUEST_GS_ACCESS_RIGHTS = 0x481e, // Guest GS Access Rights
GUEST_LDTR_ACCESS_RIGHTS = 0x4820, // Guest LDTR Access Rights
GUEST_TR_ACCESS_RIGHTS = 0x4822, // Guest TR Access Rights
GUEST_INTERRUPTIBILITY_STATE = 0x4824, // Guest interruptibility state
GUEST_ACTIVITY_STATE = 0x4826, // Guest activity state
GUEST_IA32_SYSENTER_CS = 0x482a, // Guest SYSENTER CS
};
enum class VmcsFieldXX : uint64_t {
CR4_GUEST_HOST_MASK = 0x6002, // CR4 guest/host mask
CR4_READ_SHADOW = 0x6006, // CR4 read shadow
EXIT_QUALIFICATION = 0x6400, // Exit qualification
GUEST_LINEAR_ADDRESS = 0x640a, // Guest linear address
GUEST_CR0 = 0x6800, // Guest CR0
GUEST_CR3 = 0x6802, // Guest CR3
GUEST_CR4 = 0x6804, // Guest CR4
GUEST_GDTR_BASE = 0x6816, // Guest GDTR base
GUEST_IDTR_BASE = 0x6818, // Guest IDTR base
GUEST_RSP = 0x681c, // Guest RSP
GUEST_RIP = 0x681e, // Guest RIP
GUEST_RFLAGS = 0x6820, // Guest RFLAGS
GUEST_PENDING_DEBUG_EXCEPTIONS = 0x6822, // Guest pending debug exceptions
GUEST_IA32_SYSENTER_ESP = 0x6824, // Guest SYSENTER ESP
GUEST_IA32_SYSENTER_EIP = 0x6826, // Guest SYSENTER EIP
HOST_CR0 = 0x6c00, // Host CR0
HOST_CR3 = 0x6c02, // Host CR3
HOST_CR4 = 0x6c04, // Host CR4
HOST_FS_BASE = 0x6c06, // Host FS base
HOST_GS_BASE = 0x6c08, // Host GS base
HOST_TR_BASE = 0x6c0a, // Host TR base
HOST_GDTR_BASE = 0x6c0c, // Host GDTR base
HOST_IDTR_BASE = 0x6c0e, // Host IDTR base
HOST_IA32_SYSENTER_ESP = 0x6c10, // Host SYSENTER ESP
HOST_IA32_SYSENTER_EIP = 0x6c12, // Host SYSENTER EIP
HOST_RSP = 0x6c14, // Host RSP
HOST_RIP = 0x6c16, // Host RIP
};
// clang-format on
class Vcpu;
/* Loads a VMCS within a given scope. */
class AutoVmcs : public StateReloader {
public:
AutoVmcs(const paddr_t vmcs_address_);
~AutoVmcs();
void Reload() override;
void InterruptibleReload();
void InterruptWindowExiting(bool enable);
void IssueInterrupt(uint32_t vector);
uint16_t Read(VmcsField16 field) const;
uint32_t Read(VmcsField32 field) const;
uint64_t Read(VmcsField64 field) const;
uint64_t Read(VmcsFieldXX field) const;
void Write(VmcsField16 field, uint16_t val);
void Write(VmcsField32 field, uint32_t val);
void Write(VmcsField64 field, uint64_t val);
void Write(VmcsFieldXX field, uint64_t val);
mx_status_t SetControl(VmcsField32 controls, uint64_t true_msr, uint64_t old_msr, uint32_t set,
uint32_t clear);
private:
const paddr_t vmcs_address_;
};
/* Pins execution to a CPU within a given scope. */
class AutoPin {
public:
AutoPin(const Vcpu* vcpu);
~AutoPin();
private:
thread_t* thread_;
int prev_cpu_;
};