|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-or-later */ |
| 2 | +/* |
| 3 | + * Copyright (C) 2024 SUSE LLC <[email protected]> |
| 4 | + * |
| 5 | + * x86-specific KVM helper functions and structures for Intel VMX |
| 6 | + */ |
| 7 | + |
| 8 | +#ifndef KVM_X86_VMX_H_ |
| 9 | +#define KVM_X86_VMX_H_ |
| 10 | + |
| 11 | +#include "kvm_x86.h" |
| 12 | + |
| 13 | +/* CPUID_GET_MODEL_INFO flags returned in ECX */ |
| 14 | +#define CPUID_MODEL_VMX (1 << 5) |
| 15 | +#define CPUID_MODEL_SMX (1 << 6) |
| 16 | + |
| 17 | +#define MSR_IA32_VMX_BASIC 0x480 |
| 18 | +#define MSR_IA32_VMX_PINX_MASK 0x481 |
| 19 | +#define MSR_IA32_VMX_EXECCTL_MASK 0x482 |
| 20 | +#define MSR_IA32_VMX_EXITCTL_MASK 0x483 |
| 21 | +#define MSR_IA32_VMX_ENTRYCTL_MASK 0x484 |
| 22 | +#define MSR_IA32_VMX_CR0_FIXED0 0x486 |
| 23 | +#define MSR_IA32_VMX_CR0_FIXED1 0x487 |
| 24 | +#define MSR_IA32_VMX_CR4_FIXED0 0x488 |
| 25 | +#define MSR_IA32_VMX_CR4_FIXED1 0x489 |
| 26 | +#define MSR_IA32_VMX_EXECCTL2_MASK 0x48b |
| 27 | +#define MSR_IA32_VMX_PINX_MASK2 0x48d |
| 28 | +#define MSR_IA32_VMX_EXECCTL_MASK2 0x48e |
| 29 | +#define MSR_IA32_VMX_EXITCTL_MASK2 0x48f |
| 30 | +#define MSR_IA32_VMX_ENTRYCTL_MASK2 0x490 |
| 31 | + |
| 32 | +#define IA32FC_LOCK (1 << 0) |
| 33 | +#define IA32FC_VMXON_SMX (1 << 1) |
| 34 | +#define IA32FC_VMXON_NORMAL (1 << 2) |
| 35 | + |
| 36 | +#define IA32_VMXBASIC_USELESS_CTL_MASKS (1ULL << 55) |
| 37 | + |
| 38 | +#define VMX_VMCS_GUEST_ES 0x800 |
| 39 | +#define VMX_VMCS_GUEST_CS 0x802 |
| 40 | +#define VMX_VMCS_GUEST_SS 0x804 |
| 41 | +#define VMX_VMCS_GUEST_DS 0x806 |
| 42 | +#define VMX_VMCS_GUEST_FS 0x808 |
| 43 | +#define VMX_VMCS_GUEST_GS 0x80a |
| 44 | +#define VMX_VMCS_GUEST_LDTR 0x80c |
| 45 | +#define VMX_VMCS_GUEST_TR 0x80e |
| 46 | +#define VMX_VMCS_GUEST_INTR 0x810 |
| 47 | +#define VMX_VMCS_HOST_ES 0xc00 |
| 48 | +#define VMX_VMCS_HOST_CS 0xc02 |
| 49 | +#define VMX_VMCS_HOST_SS 0xc04 |
| 50 | +#define VMX_VMCS_HOST_DS 0xc06 |
| 51 | +#define VMX_VMCS_HOST_FS 0xc08 |
| 52 | +#define VMX_VMCS_HOST_GS 0xc0a |
| 53 | +#define VMX_VMCS_HOST_TR 0xc0c |
| 54 | + |
| 55 | +#define VMX_VMCS_LINK_POINTER 0x2800 |
| 56 | + |
| 57 | +#define VMX_VMCS_GUEST_ES_LIMIT 0x4800 |
| 58 | +#define VMX_VMCS_GUEST_CS_LIMIT 0x4802 |
| 59 | +#define VMX_VMCS_GUEST_SS_LIMIT 0x4804 |
| 60 | +#define VMX_VMCS_GUEST_DS_LIMIT 0x4806 |
| 61 | +#define VMX_VMCS_GUEST_FS_LIMIT 0x4808 |
| 62 | +#define VMX_VMCS_GUEST_GS_LIMIT 0x480a |
| 63 | +#define VMX_VMCS_GUEST_LDTR_LIMIT 0x480c |
| 64 | +#define VMX_VMCS_GUEST_TR_LIMIT 0x480e |
| 65 | +#define VMX_VMCS_GUEST_GDTR_LIMIT 0x4810 |
| 66 | +#define VMX_VMCS_GUEST_IDTR_LIMIT 0x4812 |
| 67 | +#define VMX_VMCS_GUEST_ES_ACCESS 0x4814 |
| 68 | +#define VMX_VMCS_GUEST_CS_ACCESS 0x4816 |
| 69 | +#define VMX_VMCS_GUEST_SS_ACCESS 0x4818 |
| 70 | +#define VMX_VMCS_GUEST_DS_ACCESS 0x481a |
| 71 | +#define VMX_VMCS_GUEST_FS_ACCESS 0x481c |
| 72 | +#define VMX_VMCS_GUEST_GS_ACCESS 0x481e |
| 73 | +#define VMX_VMCS_GUEST_LDTR_ACCESS 0x4820 |
| 74 | +#define VMX_VMCS_GUEST_TR_ACCESS 0x4822 |
| 75 | +#define VMX_VMCS_GUEST_INTR_STATE 0x4824 |
| 76 | +#define VMX_VMCS_GUEST_ACT_STATE 0x4826 |
| 77 | +#define VMX_VMCS_GUEST_SMBASE 0x4828 |
| 78 | +#define VMX_VMCS_GUEST_SYSENTER_CS 0x482a |
| 79 | +#define VMX_VMCS_HOST_SYSENTER_CS 0x4c00 |
| 80 | + |
| 81 | +#define VMX_VMCS_GUEST_CR0 0x6800 |
| 82 | +#define VMX_VMCS_GUEST_CR3 0x6802 |
| 83 | +#define VMX_VMCS_GUEST_CR4 0x6804 |
| 84 | +#define VMX_VMCS_GUEST_ES_BASE 0x6806 |
| 85 | +#define VMX_VMCS_GUEST_CS_BASE 0x6808 |
| 86 | +#define VMX_VMCS_GUEST_SS_BASE 0x680a |
| 87 | +#define VMX_VMCS_GUEST_DS_BASE 0x680c |
| 88 | +#define VMX_VMCS_GUEST_FS_BASE 0x680e |
| 89 | +#define VMX_VMCS_GUEST_GS_BASE 0x6810 |
| 90 | +#define VMX_VMCS_GUEST_LDTR_BASE 0x6812 |
| 91 | +#define VMX_VMCS_GUEST_TR_BASE 0x6814 |
| 92 | +#define VMX_VMCS_GUEST_GDTR_BASE 0x6816 |
| 93 | +#define VMX_VMCS_GUEST_IDTR_BASE 0x6818 |
| 94 | +#define VMX_VMCS_GUEST_DR7 0x681a |
| 95 | +#define VMX_VMCS_GUEST_RSP 0x681c |
| 96 | +#define VMX_VMCS_GUEST_RIP 0x681e |
| 97 | +#define VMX_VMCS_GUEST_RFLAGS 0x6820 |
| 98 | +#define VMX_VMCS_GUEST_DEBUG_EXC 0x6822 |
| 99 | +#define VMX_VMCS_GUEST_SYSENTER_ESP 0x6824 |
| 100 | +#define VMX_VMCS_GUEST_SYSENTER_EIP 0x6826 |
| 101 | +#define VMX_VMCS_HOST_CR0 0x6c00 |
| 102 | +#define VMX_VMCS_HOST_CR3 0x6c02 |
| 103 | +#define VMX_VMCS_HOST_CR4 0x6c04 |
| 104 | +#define VMX_VMCS_HOST_FS_BASE 0x6c06 |
| 105 | +#define VMX_VMCS_HOST_GS_BASE 0x6c08 |
| 106 | +#define VMX_VMCS_HOST_TR_BASE 0x6c0a |
| 107 | +#define VMX_VMCS_HOST_GDTR_BASE 0x6c0c |
| 108 | +#define VMX_VMCS_HOST_IDTR_BASE 0x6c0e |
| 109 | +#define VMX_VMCS_HOST_SYSENTER_ESP 0x6c10 |
| 110 | +#define VMX_VMCS_HOST_SYSENTER_EIP 0x6c12 |
| 111 | +#define VMX_VMCS_HOST_RSP 0x6c14 |
| 112 | +#define VMX_VMCS_HOST_RIP 0x6c16 |
| 113 | + |
| 114 | +#define VMX_VMCS_VMPINX_CTL 0x4000 |
| 115 | +#define VMX_VMCS_VMEXEC_CTL 0x4002 |
| 116 | +#define VMX_VMCS_VMEXIT_CTL 0x400c |
| 117 | +#define VMX_VMCS_VMEXIT_MSR_STORE 0x400e |
| 118 | +#define VMX_VMCS_VMEXIT_MSR_LOAD 0x4010 |
| 119 | +#define VMX_VMCS_VMENTRY_CTL 0x4012 |
| 120 | +#define VMX_VMCS_VMENTRY_MSR_LOAD 0x4014 |
| 121 | +#define VMX_VMCS_VMENTRY_INTR 0x4016 |
| 122 | +#define VMX_VMCS_VMENTRY_EXC 0x4018 |
| 123 | +#define VMX_VMCS_VMENTRY_INST_LEN 0x401a |
| 124 | +#define VMX_VMCS_VMEXEC_CTL2 0x401e |
| 125 | + |
| 126 | +#define VMX_VMCS_VMINST_ERROR 0x4400 |
| 127 | +#define VMX_VMCS_EXIT_REASON 0x4402 |
| 128 | +#define VMX_VMCS_VMEXIT_INTR_INFO 0x4404 |
| 129 | +#define VMX_VMCS_VMEXIT_INTR_ERRNO 0x4406 |
| 130 | +#define VMX_VMCS_IDTVEC_INFO 0x4408 |
| 131 | +#define VMX_VMCS_IDTVEC_ERRNO 0x440a |
| 132 | +#define VMX_VMCS_VMEXIT_INST_LEN 0x440c |
| 133 | +#define VMX_VMCS_VMEXIT_INST_INFO 0x440e |
| 134 | +#define VMX_VMCS_EXIT_QUALIFICATION 0x6400 |
| 135 | + |
| 136 | +#define VMX_INTERCEPT_HLT (1 << 7) |
| 137 | +#define VMX_EXECCTL_ENABLE_CTL2 (1 << 31) |
| 138 | + |
| 139 | +#define VMX_EXECCTL2_SHADOW_VMCS (1 << 14) |
| 140 | + |
| 141 | +#define VMX_EXITCTL_SAVE_DR (1 << 2) |
| 142 | +#define VMX_EXITCTL_X64 (1 << 9) |
| 143 | + |
| 144 | +#define VMX_ENTRYCTL_LOAD_DR (1 << 2) |
| 145 | +#define VMX_ENTRYCTL_X64 (1 << 9) |
| 146 | + |
| 147 | +#define VMX_SHADOW_VMCS 0x80000000 |
| 148 | +#define VMX_VMCSFIELD_64BIT 0x2000 |
| 149 | +#define VMX_VMCSFIELD_SIZE_MASK 0x6000 |
| 150 | + |
| 151 | +#define VMX_INVALID_VMCS 0xffffffffffffffffULL |
| 152 | + |
| 153 | +#define VMX_EXIT_HLT 12 |
| 154 | +#define VMX_EXIT_FAILED_ENTRY 0x80000000 |
| 155 | + |
| 156 | +struct kvm_vmcs { |
| 157 | + uint32_t version; |
| 158 | + uint32_t abort; |
| 159 | + uint8_t data[4088]; |
| 160 | +}; |
| 161 | + |
| 162 | +struct kvm_vmx_vcpu { |
| 163 | + struct kvm_vmcs *vmcs; |
| 164 | + struct kvm_regs64 regs; |
| 165 | + int launched; |
| 166 | +}; |
| 167 | + |
| 168 | +/* Intel VMX virtualization helper functions */ |
| 169 | +int kvm_is_vmx_supported(void); |
| 170 | +void kvm_set_vmx_state(int enabled); |
| 171 | +struct kvm_vmcs *kvm_alloc_vmcs(void); |
| 172 | + |
| 173 | +/* Copy GDT entry to given fields of the current VMCS */ |
| 174 | +void kvm_vmcs_copy_gdt_descriptor(unsigned int gdt_id, |
| 175 | + unsigned long vmcs_selector, unsigned long vmcs_flags, |
| 176 | + unsigned long vmcs_limit, unsigned long vmcs_baseaddr); |
| 177 | +void kvm_init_vmx_vcpu(struct kvm_vmx_vcpu *cpu, uint16_t ss, void *rsp, |
| 178 | + int (*guest_main)(void)); |
| 179 | +struct kvm_vmx_vcpu *kvm_create_vmx_vcpu(int (*guest_main)(void), |
| 180 | + int alloc_stack); |
| 181 | + |
| 182 | +/* Set the VMCS as current and update the host state fields */ |
| 183 | +void kvm_vmx_activate_vcpu(struct kvm_vmx_vcpu *cpu); |
| 184 | +void kvm_vmx_vmrun(struct kvm_vmx_vcpu *cpu); |
| 185 | + |
| 186 | +void kvm_vmx_vmclear(struct kvm_vmcs *buf); |
| 187 | +void kvm_vmx_vmptrld(struct kvm_vmcs *buf); |
| 188 | +uint64_t kvm_vmx_vmptrst(void); |
| 189 | +uint64_t kvm_vmx_vmread(unsigned long var_id); |
| 190 | +void kvm_vmx_vmwrite(unsigned long var_id, uint64_t value); |
| 191 | +int kvm_vmx_vmlaunch(struct kvm_vmx_vcpu *buf); |
| 192 | +int kvm_vmx_vmresume(struct kvm_vmx_vcpu *buf); |
| 193 | + |
| 194 | +/* Read last VMX instruction error from current VMCS */ |
| 195 | +int kvm_vmx_inst_errno(void); |
| 196 | +/* Get VMX instruction error description */ |
| 197 | +const char *kvm_vmx_inst_strerr(int vmx_errno); |
| 198 | +/* Get description of last VMX instruction error in current VMCS */ |
| 199 | +const char *kvm_vmx_inst_err(void); |
| 200 | + |
| 201 | +#endif /* KVM_X86_VMX_H_ */ |
0 commit comments