| // 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_VMEXIT_PRIV_H_ |
| #define ZIRCON_KERNEL_ARCH_X86_HYPERVISOR_VMEXIT_PRIV_H_ |
| |
| #include <zircon/types.h> |
| |
| #include <hypervisor/guest_physical_address_space.h> |
| #include <hypervisor/trap_map.h> |
| |
| // clang-format off |
| |
| // VM exit reasons. |
| enum class ExitReason : uint32_t { |
| EXCEPTION = 0u, // NMI is an exception too |
| EXTERNAL_INTERRUPT = 1u, |
| TRIPLE_FAULT = 2u, |
| INIT_SIGNAL = 3u, |
| STARTUP_IPI = 4u, |
| IO_SMI = 5u, |
| OTHER_SMI = 6u, |
| INTERRUPT_WINDOW = 7u, |
| NMI_WINDOW = 8u, |
| TASK_SWITCH = 9u, |
| CPUID = 10u, |
| GETSEC = 11u, |
| HLT = 12u, |
| INVD = 13u, |
| INVLPG = 14u, |
| RDPMC = 15u, |
| RDTSC = 16u, |
| RSM = 17u, |
| VMCALL = 18u, |
| VMCLEAR = 19u, |
| VMLAUNCH = 20u, |
| VMPTRLD = 21u, |
| VMPTRST = 22u, |
| VMREAD = 23u, |
| VMRESUME = 24u, |
| VMWRITE = 25u, |
| VMXOFF = 26u, |
| VMXON = 27u, |
| CONTROL_REGISTER_ACCESS = 28u, |
| MOV_DR = 29u, |
| IO_INSTRUCTION = 30u, |
| RDMSR = 31u, |
| WRMSR = 32u, |
| ENTRY_FAILURE_GUEST_STATE = 33u, |
| ENTRY_FAILURE_MSR_LOADING = 34u, |
| MWAIT = 36u, |
| MONITOR_TRAP_FLAG = 37u, |
| MONITOR = 39u, |
| PAUSE = 40u, |
| ENTRY_FAILURE_MACHINE_CHECK = 41u, |
| TPR_BELOW_THRESHOLD = 43u, |
| APIC_ACCESS = 44u, |
| VIRTUALIZED_EOI = 45u, |
| ACCESS_GDTR_OR_IDTR = 46u, |
| ACCESS_LDTR_OR_TR = 47u, |
| EPT_VIOLATION = 48u, |
| EPT_MISCONFIGURATION = 49u, |
| INVEPT = 50u, |
| RDTSCP = 51u, |
| VMX_PREEMPT_TIMER_EXPIRED = 52u, |
| INVVPID = 53u, |
| WBINVD = 54u, |
| XSETBV = 55u, |
| APIC_WRITE = 56u, |
| RDRAND = 57u, |
| INVPCID = 58u, |
| VMFUNC = 59u, |
| ENCLS = 60u, |
| RDSEED = 61u, |
| PAGE_MODIFICATION_LOG_FULL = 62u, |
| XSAVES = 63u, |
| XRSTORS = 64u, |
| }; |
| |
| static inline const char* exit_reason_name(ExitReason exit_reason) { |
| #define EXIT_REASON_NAME(name) case ExitReason::name: return #name |
| switch (exit_reason) { |
| EXIT_REASON_NAME(EXCEPTION); |
| EXIT_REASON_NAME(EXTERNAL_INTERRUPT); |
| EXIT_REASON_NAME(TRIPLE_FAULT); |
| EXIT_REASON_NAME(INIT_SIGNAL); |
| EXIT_REASON_NAME(STARTUP_IPI); |
| EXIT_REASON_NAME(IO_SMI); |
| EXIT_REASON_NAME(OTHER_SMI); |
| EXIT_REASON_NAME(INTERRUPT_WINDOW); |
| EXIT_REASON_NAME(NMI_WINDOW); |
| EXIT_REASON_NAME(TASK_SWITCH); |
| EXIT_REASON_NAME(CPUID); |
| EXIT_REASON_NAME(GETSEC); |
| EXIT_REASON_NAME(HLT); |
| EXIT_REASON_NAME(INVD); |
| EXIT_REASON_NAME(INVLPG); |
| EXIT_REASON_NAME(RDPMC); |
| EXIT_REASON_NAME(RDTSC); |
| EXIT_REASON_NAME(RSM); |
| EXIT_REASON_NAME(VMCALL); |
| EXIT_REASON_NAME(VMCLEAR); |
| EXIT_REASON_NAME(VMLAUNCH); |
| EXIT_REASON_NAME(VMPTRLD); |
| EXIT_REASON_NAME(VMPTRST); |
| EXIT_REASON_NAME(VMREAD); |
| EXIT_REASON_NAME(VMRESUME); |
| EXIT_REASON_NAME(VMWRITE); |
| EXIT_REASON_NAME(VMXOFF); |
| EXIT_REASON_NAME(VMXON); |
| EXIT_REASON_NAME(CONTROL_REGISTER_ACCESS); |
| EXIT_REASON_NAME(MOV_DR); |
| EXIT_REASON_NAME(IO_INSTRUCTION); |
| EXIT_REASON_NAME(RDMSR); |
| EXIT_REASON_NAME(WRMSR); |
| EXIT_REASON_NAME(ENTRY_FAILURE_GUEST_STATE); |
| EXIT_REASON_NAME(ENTRY_FAILURE_MSR_LOADING); |
| EXIT_REASON_NAME(MWAIT); |
| EXIT_REASON_NAME(MONITOR_TRAP_FLAG); |
| EXIT_REASON_NAME(MONITOR); |
| EXIT_REASON_NAME(PAUSE); |
| EXIT_REASON_NAME(ENTRY_FAILURE_MACHINE_CHECK); |
| EXIT_REASON_NAME(TPR_BELOW_THRESHOLD); |
| EXIT_REASON_NAME(APIC_ACCESS); |
| EXIT_REASON_NAME(VIRTUALIZED_EOI); |
| EXIT_REASON_NAME(ACCESS_GDTR_OR_IDTR); |
| EXIT_REASON_NAME(ACCESS_LDTR_OR_TR); |
| EXIT_REASON_NAME(EPT_VIOLATION); |
| EXIT_REASON_NAME(EPT_MISCONFIGURATION); |
| EXIT_REASON_NAME(INVEPT); |
| EXIT_REASON_NAME(RDTSCP); |
| EXIT_REASON_NAME(VMX_PREEMPT_TIMER_EXPIRED); |
| EXIT_REASON_NAME(INVVPID); |
| EXIT_REASON_NAME(WBINVD); |
| EXIT_REASON_NAME(XSETBV); |
| EXIT_REASON_NAME(APIC_WRITE); |
| EXIT_REASON_NAME(RDRAND); |
| EXIT_REASON_NAME(INVPCID); |
| EXIT_REASON_NAME(VMFUNC); |
| EXIT_REASON_NAME(ENCLS); |
| EXIT_REASON_NAME(RDSEED); |
| EXIT_REASON_NAME(PAGE_MODIFICATION_LOG_FULL); |
| EXIT_REASON_NAME(XSAVES); |
| EXIT_REASON_NAME(XRSTORS); |
| #undef EXIT_REASON_NAME |
| default: return "UNKNOWN"; |
| } |
| } |
| |
| // VM exit interruption type. |
| enum class InterruptionType : uint8_t { |
| EXTERNAL_INTERRUPT = 0u, |
| NON_MASKABLE_INTERRUPT = 2u, |
| HARDWARE_EXCEPTION = 3u, |
| SOFTWARE_EXCEPTION = 6u, |
| }; |
| |
| // X2APIC MSR addresses from Volume 3, Section 10.12.1.2. |
| enum class X2ApicMsr : uint32_t { |
| ID = 0x802, |
| VERSION = 0x803, |
| EOI = 0x80b, |
| TPR = 0x808, |
| LDR = 0x80d, |
| SVR = 0x80f, |
| ISR_31_0 = 0x810, |
| ISR_63_32 = 0x811, |
| ISR_95_64 = 0x812, |
| ISR_127_96 = 0x813, |
| ISR_159_128 = 0x814, |
| ISR_191_160 = 0x815, |
| ISR_223_192 = 0x816, |
| ISR_255_224 = 0x817, |
| TMR_31_0 = 0x818, |
| TMR_63_32 = 0x819, |
| TMR_95_64 = 0x81a, |
| TMR_127_96 = 0x81b, |
| TMR_159_128 = 0x81c, |
| TMR_191_160 = 0x81d, |
| TMR_223_192 = 0x81e, |
| TMR_255_224 = 0x81f, |
| IRR_31_0 = 0x820, |
| IRR_63_32 = 0x821, |
| IRR_95_64 = 0x822, |
| IRR_127_96 = 0x823, |
| IRR_159_128 = 0x824, |
| IRR_191_160 = 0x825, |
| IRR_223_192 = 0x826, |
| IRR_255_224 = 0x827, |
| ESR = 0x828, |
| LVT_CMCI = 0x82f, |
| ICR = 0x830, |
| LVT_TIMER = 0x832, |
| LVT_THERMAL_SENSOR = 0x833, |
| LVT_MONITOR = 0x834, |
| LVT_LINT0 = 0x835, |
| LVT_LINT1 = 0x836, |
| LVT_ERROR = 0x837, |
| INITIAL_COUNT = 0x838, |
| DCR = 0x83e, |
| SELF_IPI = 0x83f, |
| }; |
| |
| enum class InterruptDeliveryMode : uint8_t { |
| FIXED = 0u, |
| SMI = 2u, |
| NMI = 4u, |
| INIT = 5u, |
| STARTUP = 6u, |
| }; |
| |
| enum class InterruptDestinationMode : bool { |
| PHYSICAL = false, |
| LOGICAL = true, |
| }; |
| |
| enum class InterruptDestinationShorthand : uint8_t { |
| NO_SHORTHAND = 0u, |
| SELF = 1u, |
| ALL_INCLUDING_SELF = 2u, |
| ALL_EXCLUDING_SELF = 3u, |
| }; |
| |
| enum class CrAccessType : uint8_t { |
| MOV_TO_CR = 0u, |
| MOV_FROM_CR = 1u, |
| CLTS = 2u, |
| LMSW = 3u, |
| }; |
| |
| enum VmCallStatus : int64_t { |
| OK = 0, |
| NOT_PERMITTED = -1, |
| FAULT = -14, |
| NOT_SUPPORTED = -95, |
| UNKNOWN_HYPERCALL = -1000, |
| }; |
| |
| enum class VmCallType : uint64_t { |
| CLOCK_PAIRING = 9u, |
| }; |
| |
| // clang-format on |
| |
| constexpr uint32_t kIpiBroadcastDestination = 0xffff'ffff; |
| |
| typedef struct zx_port_packet zx_port_packet_t; |
| |
| class AutoVmcs; |
| struct GuestState; |
| struct LocalApicState; |
| struct PvClockState; |
| |
| // Stores VM exit info from VMCS fields. |
| struct ExitInfo { |
| bool entry_failure; |
| ExitReason exit_reason; |
| uint64_t exit_qualification; |
| uint32_t exit_instruction_length; |
| uint64_t guest_physical_address; |
| uint64_t guest_rip; |
| |
| ExitInfo(const AutoVmcs& vmcs); |
| }; |
| |
| // Stores VM exit interruption information. See Volume 3, Section 24.9.2. |
| struct ExitInterruptionInformation { |
| uint8_t vector; |
| InterruptionType interruption_type; |
| bool valid; |
| |
| ExitInterruptionInformation(const AutoVmcs& vmcs); |
| }; |
| |
| // Stores EPT violation info from the VMCS exit qualification field. |
| struct EptViolationInfo { |
| bool read; |
| bool write; |
| bool instruction; |
| |
| EptViolationInfo(uint64_t qualification); |
| }; |
| |
| // Stores control register access info from the VMCS exit qualification field. |
| struct CrAccessInfo { |
| uint8_t cr_number; |
| CrAccessType access_type; |
| uint8_t reg; |
| |
| CrAccessInfo(uint64_t qualification); |
| }; |
| |
| // Stores IO instruction info from the VMCS exit qualification field. |
| struct IoInfo { |
| uint8_t access_size; |
| bool input; |
| bool string; |
| bool repeat; |
| uint16_t port; |
| |
| IoInfo(uint64_t qualification); |
| }; |
| |
| // Stores VMCALL type and arguments. |
| struct VmCallInfo { |
| VmCallType type; |
| uint64_t arg[4]; |
| |
| VmCallInfo(const GuestState* guest_state); |
| }; |
| |
| // Interrupt command register. |
| struct InterruptCommandRegister { |
| uint32_t destination; |
| enum InterruptDestinationMode destination_mode; |
| enum InterruptDeliveryMode delivery_mode; |
| enum InterruptDestinationShorthand destination_shorthand; |
| uint8_t vector; |
| |
| InterruptCommandRegister(uint32_t hi, uint32_t lo); |
| }; |
| |
| zx_status_t vmexit_handler(AutoVmcs* vmcs, GuestState* guest_state, |
| LocalApicState* local_apic_state, PvClockState* pv_clock, |
| hypervisor::GuestPhysicalAddressSpace* gpas, hypervisor::TrapMap* traps, |
| zx_port_packet_t* packet); |
| |
| #endif // ZIRCON_KERNEL_ARCH_X86_HYPERVISOR_VMEXIT_PRIV_H_ |