1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#ifndef VMX_H
26#define VMX_H
27
28#include <Hypervisor/hv.h>
29#include <Hypervisor/hv_vmx.h>
30#include "vmcs.h"
31#include "cpu.h"
32#include "x86.h"
33
34#include "exec/address-spaces.h"
35
36static inline uint64_t rreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg)
37{
38 uint64_t v;
39
40 if (hv_vcpu_read_register(vcpu, reg, &v)) {
41 abort();
42 }
43
44 return v;
45}
46
47
48static inline void wreg(hv_vcpuid_t vcpu, hv_x86_reg_t reg, uint64_t v)
49{
50 if (hv_vcpu_write_register(vcpu, reg, v)) {
51 abort();
52 }
53}
54
55
56static inline uint64_t rvmcs(hv_vcpuid_t vcpu, uint32_t field)
57{
58 uint64_t v;
59
60 hv_vmx_vcpu_read_vmcs(vcpu, field, &v);
61
62 return v;
63}
64
65
66static inline void wvmcs(hv_vcpuid_t vcpu, uint32_t field, uint64_t v)
67{
68 hv_vmx_vcpu_write_vmcs(vcpu, field, v);
69}
70
71
72static inline uint64_t cap2ctrl(uint64_t cap, uint64_t ctrl)
73{
74 return (ctrl | (cap & 0xffffffff)) & (cap >> 32);
75}
76
77#define VM_ENTRY_GUEST_LMA (1LL << 9)
78
79#define AR_TYPE_ACCESSES_MASK 1
80#define AR_TYPE_READABLE_MASK (1 << 1)
81#define AR_TYPE_WRITEABLE_MASK (1 << 2)
82#define AR_TYPE_CODE_MASK (1 << 3)
83#define AR_TYPE_MASK 0x0f
84#define AR_TYPE_BUSY_64_TSS 11
85#define AR_TYPE_BUSY_32_TSS 11
86#define AR_TYPE_BUSY_16_TSS 3
87#define AR_TYPE_LDT 2
88
89static void enter_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer)
90{
91 uint64_t entry_ctls;
92
93 efer |= MSR_EFER_LMA;
94 wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer);
95 entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS);
96 wvmcs(vcpu, VMCS_ENTRY_CTLS, rvmcs(vcpu, VMCS_ENTRY_CTLS) |
97 VM_ENTRY_GUEST_LMA);
98
99 uint64_t guest_tr_ar = rvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS);
100 if ((efer & MSR_EFER_LME) &&
101 (guest_tr_ar & AR_TYPE_MASK) != AR_TYPE_BUSY_64_TSS) {
102 wvmcs(vcpu, VMCS_GUEST_TR_ACCESS_RIGHTS,
103 (guest_tr_ar & ~AR_TYPE_MASK) | AR_TYPE_BUSY_64_TSS);
104 }
105}
106
107static void exit_long_mode(hv_vcpuid_t vcpu, uint64_t cr0, uint64_t efer)
108{
109 uint64_t entry_ctls;
110
111 entry_ctls = rvmcs(vcpu, VMCS_ENTRY_CTLS);
112 wvmcs(vcpu, VMCS_ENTRY_CTLS, entry_ctls & ~VM_ENTRY_GUEST_LMA);
113
114 efer &= ~MSR_EFER_LMA;
115 wvmcs(vcpu, VMCS_GUEST_IA32_EFER, efer);
116}
117
118static inline void macvm_set_cr0(hv_vcpuid_t vcpu, uint64_t cr0)
119{
120 int i;
121 uint64_t pdpte[4] = {0, 0, 0, 0};
122 uint64_t efer = rvmcs(vcpu, VMCS_GUEST_IA32_EFER);
123 uint64_t old_cr0 = rvmcs(vcpu, VMCS_GUEST_CR0);
124
125 if ((cr0 & CR0_PG) && (rvmcs(vcpu, VMCS_GUEST_CR4) & CR4_PAE) &&
126 !(efer & MSR_EFER_LME)) {
127 address_space_rw(&address_space_memory,
128 rvmcs(vcpu, VMCS_GUEST_CR3) & ~0x1f,
129 MEMTXATTRS_UNSPECIFIED,
130 (uint8_t *)pdpte, 32, 0);
131 }
132
133 for (i = 0; i < 4; i++) {
134 wvmcs(vcpu, VMCS_GUEST_PDPTE0 + i * 2, pdpte[i]);
135 }
136
137 wvmcs(vcpu, VMCS_CR0_MASK, CR0_CD | CR0_NE | CR0_PG);
138 wvmcs(vcpu, VMCS_CR0_SHADOW, cr0);
139
140 cr0 &= ~CR0_CD;
141 wvmcs(vcpu, VMCS_GUEST_CR0, cr0 | CR0_NE | CR0_ET);
142
143 if (efer & MSR_EFER_LME) {
144 if (!(old_cr0 & CR0_PG) && (cr0 & CR0_PG)) {
145 enter_long_mode(vcpu, cr0, efer);
146 }
147 if ( !(cr0 & CR0_PG)) {
148 exit_long_mode(vcpu, cr0, efer);
149 }
150 }
151
152 hv_vcpu_invalidate_tlb(vcpu);
153 hv_vcpu_flush(vcpu);
154}
155
156static inline void macvm_set_cr4(hv_vcpuid_t vcpu, uint64_t cr4)
157{
158 uint64_t guest_cr4 = cr4 | CR4_VMXE;
159
160 wvmcs(vcpu, VMCS_GUEST_CR4, guest_cr4);
161 wvmcs(vcpu, VMCS_CR4_SHADOW, cr4);
162
163 hv_vcpu_invalidate_tlb(vcpu);
164 hv_vcpu_flush(vcpu);
165}
166
167static inline void macvm_set_rip(CPUState *cpu, uint64_t rip)
168{
169 uint64_t val;
170
171
172 wreg(cpu->hvf_fd, HV_X86_RIP, rip);
173
174
175 val = rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
176 if (val & (VMCS_INTERRUPTIBILITY_STI_BLOCKING |
177 VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING)) {
178 wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY,
179 val & ~(VMCS_INTERRUPTIBILITY_STI_BLOCKING |
180 VMCS_INTERRUPTIBILITY_MOVSS_BLOCKING));
181 }
182}
183
184static inline void vmx_clear_nmi_blocking(CPUState *cpu)
185{
186 X86CPU *x86_cpu = X86_CPU(cpu);
187 CPUX86State *env = &x86_cpu->env;
188
189 env->hflags2 &= ~HF2_NMI_MASK;
190 uint32_t gi = (uint32_t) rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
191 gi &= ~VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
192 wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
193}
194
195static inline void vmx_set_nmi_blocking(CPUState *cpu)
196{
197 X86CPU *x86_cpu = X86_CPU(cpu);
198 CPUX86State *env = &x86_cpu->env;
199
200 env->hflags2 |= HF2_NMI_MASK;
201 uint32_t gi = (uint32_t)rvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY);
202 gi |= VMCS_INTERRUPTIBILITY_NMI_BLOCKING;
203 wvmcs(cpu->hvf_fd, VMCS_GUEST_INTERRUPTIBILITY, gi);
204}
205
206static inline void vmx_set_nmi_window_exiting(CPUState *cpu)
207{
208 uint64_t val;
209 val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS);
210 wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val |
211 VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING);
212
213}
214
215static inline void vmx_clear_nmi_window_exiting(CPUState *cpu)
216{
217
218 uint64_t val;
219 val = rvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS);
220 wvmcs(cpu->hvf_fd, VMCS_PRI_PROC_BASED_CTLS, val &
221 ~VMCS_PRI_PROC_BASED_CTLS_NMI_WINDOW_EXITING);
222}
223
224#endif
225