blob: 2911def3ec62232134a63bfb473130c91ab8f03f [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
#ifndef ZIRCON_KERNEL_ARCH_X86_HYPERVISOR_VCPU_PRIV_H_
#define ZIRCON_KERNEL_ARCH_X86_HYPERVISOR_VCPU_PRIV_H_
#include <hypervisor/state_invalidator.h>
// clang-format off
#define X86_MSR_IA32_VMX_PINBASED_CTLS 0x0481
#define X86_MSR_IA32_VMX_PROCBASED_CTLS 0x0482
#define X86_MSR_IA32_VMX_EXIT_CTLS 0x0483
#define X86_MSR_IA32_VMX_ENTRY_CTLS 0x0484
#define X86_MSR_IA32_VMX_PROCBASED_CTLS2 0x048b
#define X86_MSR_IA32_VMX_TRUE_PINBASED_CTLS 0x048d
#define X86_MSR_IA32_VMX_TRUE_PROCBASED_CTLS 0x048e
#define X86_MSR_IA32_VMX_TRUE_EXIT_CTLS 0x048f
#define X86_MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x0490
// PROCBASED_CTLS2 flags.
static const uint32_t kProcbasedCtls2Ept = 1u << 1;
static const uint32_t kProcbasedCtls2Rdtscp = 1u << 3;
static const uint32_t kProcbasedCtls2x2Apic = 1u << 4;
static const uint32_t kProcbasedCtls2Vpid = 1u << 5;
static const uint32_t kProcbasedCtls2UnrestrictedGuest = 1u << 7;
static const uint32_t kProcbasedCtls2PauseLoopExiting = 1u << 10;
static const uint32_t kProcbasedCtls2Invpcid = 1u << 12;
// PROCBASED_CTLS flags.
static const uint32_t kProcbasedCtlsIntWindowExiting = 1u << 2;
static const uint32_t kProcbasedCtlsHltExiting = 1u << 7;
static const uint32_t kProcbasedCtlsCr3LoadExiting = 1u << 15;
static const uint32_t kProcbasedCtlsCr3StoreExiting = 1u << 16;
static const uint32_t kProcbasedCtlsCr8LoadExiting = 1u << 19;
static const uint32_t kProcbasedCtlsCr8StoreExiting = 1u << 20;
static const uint32_t kProcbasedCtlsTprShadow = 1u << 21;
static const uint32_t kProcbasedCtlsIoExiting = 1u << 24;
static const uint32_t kProcbasedCtlsMsrBitmaps = 1u << 28;
static const uint32_t kProcbasedCtlsProcbasedCtls2 = 1u << 31;
// PINBASED_CTLS flags.
static const uint32_t kPinbasedCtlsExtIntExiting = 1u << 0;
static const uint32_t kPinbasedCtlsNmiExiting = 1u << 3;
// EXIT_CTLS flags.
static const uint32_t kExitCtls64bitMode = 1u << 9;
static const uint32_t kExitCtlsAckIntOnExit = 1u << 15;
static const uint32_t kExitCtlsSaveIa32Pat = 1u << 18;
static const uint32_t kExitCtlsLoadIa32Pat = 1u << 19;
static const uint32_t kExitCtlsSaveIa32Efer = 1u << 20;
static const uint32_t kExitCtlsLoadIa32Efer = 1u << 21;
// ENTRY_CTLS flags.
static const uint32_t kEntryCtls64bitMode = 1u << 9;
static const uint32_t kEntryCtlsLoadIa32Pat = 1u << 14;
static const uint32_t kEntryCtlsLoadIa32Efer = 1u << 15;
// LINK_POINTER values.
static const uint64_t kLinkPointerInvalidate = UINT64_MAX;
// GUEST_XX_ACCESS_RIGHTS flags.
static const uint32_t kGuestXxAccessRightsUnusable = 1u << 16;
// See Volume 3, Section 24.4.1 for access rights format.
static const uint32_t kGuestXxAccessRightsTypeA = 1u << 0;
static const uint32_t kGuestXxAccessRightsTypeW = 1u << 1;
static const uint32_t kGuestXxAccessRightsTypeE = 1u << 2;
static const uint32_t kGuestXxAccessRightsTypeCode = 1u << 3;
// See Volume 3, Section 3.4.5.1 for valid non-system selector types.
static const uint32_t kGuestXxAccessRightsS = 1u << 4;
static const uint32_t kGuestXxAccessRightsDplUser = 3u << 5;
static const uint32_t kGuestXxAccessRightsP = 1u << 7;
static const uint32_t kGuestXxAccessRightsL = 1u << 13;
static const uint32_t kGuestXxAccessRightsD = 1u << 14;
// See Volume 3, Section 3.5 for valid system selectors types.
static const uint32_t kGuestTrAccessRightsTssBusy16Bit = 3u << 0;
static const uint32_t kGuestTrAccessRightsTssBusy = 11u << 0;
static const uint32_t kGuestXxAccessRightsDefault = kGuestXxAccessRightsTypeA |
kGuestXxAccessRightsTypeW |
kGuestXxAccessRightsS |
kGuestXxAccessRightsP;
// GUEST_INTERRUPTIBILITY_STATE flags.
static const uint32_t kInterruptibilityStiBlocking = 1u << 0;
static const uint32_t kInterruptibilityMovSsBlocking = 1u << 1;
static const uint32_t kInterruptibilityNmiBlocking = 1u << 3;
// VMCS fields.
enum class VmcsField16 : uint64_t {
VPID = 0x0000,
GUEST_CS_SELECTOR = 0x0802,
GUEST_TR_SELECTOR = 0x080e,
HOST_ES_SELECTOR = 0x0c00,
HOST_CS_SELECTOR = 0x0c02,
HOST_SS_SELECTOR = 0x0c04,
HOST_DS_SELECTOR = 0x0c06,
HOST_FS_SELECTOR = 0x0c08,
HOST_GS_SELECTOR = 0x0c0a,
HOST_TR_SELECTOR = 0x0c0c,
};
enum class VmcsField64 : uint64_t {
MSR_BITMAPS_ADDRESS = 0x2004,
EXIT_MSR_STORE_ADDRESS = 0x2006,
EXIT_MSR_LOAD_ADDRESS = 0x2008,
ENTRY_MSR_LOAD_ADDRESS = 0x200a,
EPT_POINTER = 0x201a,
GUEST_PHYSICAL_ADDRESS = 0x2400,
LINK_POINTER = 0x2800,
GUEST_IA32_PAT = 0x2804,
GUEST_IA32_EFER = 0x2806,
HOST_IA32_PAT = 0x2c00,
HOST_IA32_EFER = 0x2c02,
};
enum class VmcsField32 : uint64_t {
PINBASED_CTLS = 0x4000,
PROCBASED_CTLS = 0x4002,
EXCEPTION_BITMAP = 0x4004,
PAGEFAULT_ERRORCODE_MASK = 0x4006,
PAGEFAULT_ERRORCODE_MATCH = 0x4008,
EXIT_CTLS = 0x400c,
EXIT_MSR_STORE_COUNT = 0x400e,
EXIT_MSR_LOAD_COUNT = 0x4010,
ENTRY_CTLS = 0x4012,
ENTRY_MSR_LOAD_COUNT = 0x4014,
ENTRY_INTERRUPTION_INFORMATION = 0x4016,
ENTRY_EXCEPTION_ERROR_CODE = 0x4018,
PROCBASED_CTLS2 = 0x401e,
PLE_GAP = 0x4020,
PLE_WINDOW = 0x4022,
INSTRUCTION_ERROR = 0x4400,
EXIT_REASON = 0x4402,
EXIT_INTERRUPTION_INFORMATION = 0x4404,
EXIT_INTERRUPTION_ERROR_CODE = 0x4406,
EXIT_INSTRUCTION_LENGTH = 0x440c,
EXIT_INSTRUCTION_INFORMATION = 0x440e,
HOST_IA32_SYSENTER_CS = 0x4c00,
GUEST_ES_LIMIT = 0x4800,
GUEST_CS_LIMIT = 0x4802,
GUEST_SS_LIMIT = 0x4804,
GUEST_DS_LIMIT = 0x4806,
GUEST_FS_LIMIT = 0x4808,
GUEST_GS_LIMIT = 0x480a,
GUEST_LDTR_LIMIT = 0x480c,
GUEST_TR_LIMIT = 0x480e,
GUEST_GDTR_LIMIT = 0x4810,
GUEST_IDTR_LIMIT = 0x4812,
GUEST_CS_ACCESS_RIGHTS = 0x4816,
GUEST_ES_ACCESS_RIGHTS = 0x4814,
GUEST_SS_ACCESS_RIGHTS = 0x4818,
GUEST_DS_ACCESS_RIGHTS = 0x481a,
GUEST_FS_ACCESS_RIGHTS = 0x481c,
GUEST_GS_ACCESS_RIGHTS = 0x481e,
GUEST_LDTR_ACCESS_RIGHTS = 0x4820,
GUEST_TR_ACCESS_RIGHTS = 0x4822,
GUEST_INTERRUPTIBILITY_STATE = 0x4824,
GUEST_ACTIVITY_STATE = 0x4826,
GUEST_IA32_SYSENTER_CS = 0x482a,
};
enum class VmcsFieldXX : uint64_t {
CR0_GUEST_HOST_MASK = 0x6000,
CR4_GUEST_HOST_MASK = 0x6002,
CR0_READ_SHADOW = 0x6004,
CR4_READ_SHADOW = 0x6006,
EXIT_QUALIFICATION = 0x6400,
GUEST_LINEAR_ADDRESS = 0x640a,
GUEST_CR0 = 0x6800,
GUEST_CR3 = 0x6802,
GUEST_CR4 = 0x6804,
GUEST_ES_BASE = 0x6806,
GUEST_CS_BASE = 0x6808,
GUEST_SS_BASE = 0x680A,
GUEST_DS_BASE = 0x680C,
GUEST_FS_BASE = 0x680E,
GUEST_GS_BASE = 0x6810,
GUEST_TR_BASE = 0x6814,
GUEST_GDTR_BASE = 0x6816,
GUEST_IDTR_BASE = 0x6818,
GUEST_RSP = 0x681c,
GUEST_RIP = 0x681e,
GUEST_RFLAGS = 0x6820,
GUEST_PENDING_DEBUG_EXCEPTIONS = 0x6822,
GUEST_IA32_SYSENTER_ESP = 0x6824,
GUEST_IA32_SYSENTER_EIP = 0x6826,
HOST_CR0 = 0x6c00,
HOST_CR3 = 0x6c02,
HOST_CR4 = 0x6c04,
HOST_FS_BASE = 0x6c06,
HOST_GS_BASE = 0x6c08,
HOST_TR_BASE = 0x6c0a,
HOST_GDTR_BASE = 0x6c0c,
HOST_IDTR_BASE = 0x6c0e,
HOST_IA32_SYSENTER_ESP = 0x6c10,
HOST_IA32_SYSENTER_EIP = 0x6c12,
HOST_RSP = 0x6c14,
HOST_RIP = 0x6c16,
};
// clang-format on
// Loads a VMCS within a given scope.
class AutoVmcs : public hypervisor::StateInvalidator {
public:
explicit AutoVmcs(paddr_t vmcs_address_, bool clear = false);
~AutoVmcs();
void Invalidate() override;
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);
zx::result<> SetControl(VmcsField32 controls, uint64_t true_msr, uint64_t old_msr, uint32_t set,
uint32_t clear);
private:
paddr_t vmcs_address_;
interrupt_saved_state_t int_state_;
};
bool cr0_is_invalid(AutoVmcs& vmcs, uint64_t cr0_value);
#endif // ZIRCON_KERNEL_ARCH_X86_HYPERVISOR_VCPU_PRIV_H_