2 * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <pexpert/pexpert.h>
30 #include <i386/cpuid.h>
31 #include <i386/cpu_data.h>
33 #include <i386/proc_reg.h>
35 #include <i386/vmx/vmx_asm.h>
36 #include <i386/vmx/vmx_shims.h>
37 #include <i386/vmx/vmx_cpu.h>
38 #include <i386/mtrr.h>
39 #include <mach/mach_host.h> /* for host_info() */
41 #define VMX_KPRINTF(x...) /* kprintf("vmx: " x) */
43 int vmx_use_count
= 0;
44 boolean_t vmx_exclusive
= FALSE
;
45 decl_simple_lock_data(static,vmx_use_count_lock
)
47 /* -----------------------------------------------------------------------------
49 Is the VMX facility available on this CPU?
50 -------------------------------------------------------------------------- */
51 static inline boolean_t
52 vmx_is_available(void)
54 return (0 != (cpuid_features() & CPUID_FEATURE_VMX
));
57 /* -----------------------------------------------------------------------------
59 Is the VMXON instruction enabled on this CPU?
60 -------------------------------------------------------------------------- */
61 static inline boolean_t
62 vmxon_is_enabled(void)
64 return (vmx_is_available() &&
65 (rdmsr64(MSR_IA32_FEATURE_CONTROL
) & MSR_IA32_FEATCTL_VMXON
));
68 /* -----------------------------------------------------------------------------
70 Is CR0 valid for executing VMXON on this CPU?
71 -------------------------------------------------------------------------- */
72 static inline boolean_t
73 vmx_is_cr0_valid(vmx_specs_t
*specs
)
75 uintptr_t cr0
= get_cr0();
76 return (0 == ((~cr0
& specs
->cr0_fixed_0
)|(cr0
& ~specs
->cr0_fixed_1
)));
79 /* -----------------------------------------------------------------------------
81 Is CR4 valid for executing VMXON on this CPU?
82 -------------------------------------------------------------------------- */
83 static inline boolean_t
84 vmx_is_cr4_valid(vmx_specs_t
*specs
)
86 uintptr_t cr4
= get_cr4();
87 return (0 == ((~cr4
& specs
->cr4_fixed_0
)|(cr4
& ~specs
->cr4_fixed_1
)));
95 if (!vmx_is_available())
99 * We don't count on EFI initializing MSR_IA32_FEATURE_CONTROL
100 * and turning VMXON on and locking the bit, so we do that now.
102 msr_image
= rdmsr64(MSR_IA32_FEATURE_CONTROL
);
103 if (0 == ((msr_image
& MSR_IA32_FEATCTL_LOCK
)))
104 wrmsr64(MSR_IA32_FEATURE_CONTROL
,
106 MSR_IA32_FEATCTL_VMXON
|
107 MSR_IA32_FEATCTL_LOCK
));
110 /* -----------------------------------------------------------------------------
112 Obtain VMX facility specifications for this CPU and
113 enter them into the vmx_specs_t structure. If VMX is not available or
114 disabled on this CPU, set vmx_present to false and return leaving
115 the remainder of the vmx_specs_t uninitialized.
116 -------------------------------------------------------------------------- */
120 vmx_specs_t
*specs
= ¤t_cpu_datap()->cpu_vmx
.specs
;
123 /* this is called once for every CPU, but the lock doesn't care :-) */
124 simple_lock_init(&vmx_use_count_lock
, 0);
129 * if we have read the data on boot, we won't read it
130 * again on wakeup, otherwise *bad* things will happen
132 if (specs
->initialized
)
135 specs
->initialized
= TRUE
;
137 /* See if VMX is present, return if it is not */
138 specs
->vmx_present
= vmx_is_available() && vmxon_is_enabled();
139 if (!specs
->vmx_present
)
142 #define bitfield(x,f) ((x >> f##_BIT) & f##_MASK)
143 /* Obtain and decode VMX general capabilities */
144 msr_image
= rdmsr64(MSR_IA32_VMX_BASIC
);
145 specs
->vmcs_id
= (uint32_t)(msr_image
& VMX_VCR_VMCS_REV_ID
);
146 specs
->vmcs_mem_type
= bitfield(msr_image
, VMX_VCR_VMCS_MEM_TYPE
) != 0;
147 specs
->vmcs_size
= bitfield(msr_image
, VMX_VCR_VMCS_SIZE
);
149 /* Obtain allowed settings for pin-based execution controls */
150 msr_image
= rdmsr64(MSR_IA32_VMXPINBASED_CTLS
);
151 specs
->pin_exctls_0
= (uint32_t)(msr_image
& 0xFFFFFFFF);
152 specs
->pin_exctls_1
= (uint32_t)(msr_image
>> 32);
154 /* Obtain allowed settings for processor-based execution controls */
155 msr_image
= rdmsr64(MSR_IA32_PROCBASED_CTLS
);
156 specs
->proc_exctls_0
= (uint32_t)(msr_image
& 0xFFFFFFFF);
157 specs
->proc_exctls_1
= (uint32_t)(msr_image
>> 32);
159 /* Obtain allowed settings for VM-exit controls */
160 msr_image
= rdmsr64(MSR_IA32_VMX_EXIT_CTLS
);
161 specs
->exit_ctls_0
= (uint32_t)(msr_image
& 0xFFFFFFFF);
162 specs
->exit_ctls_1
= (uint32_t)(msr_image
>> 32);
164 /* Obtain allowed settings for VM-entry controls */
165 msr_image
= rdmsr64(MSR_IA32_VMX_ENTRY_CTLS
);
166 specs
->enter_ctls_0
= (uint32_t)(msr_image
& 0xFFFFFFFF);
167 specs
->enter_ctls_0
= (uint32_t)(msr_image
>> 32);
169 /* Obtain and decode miscellaneous capabilities */
170 msr_image
= rdmsr64(MSR_IA32_VMX_MISC
);
171 specs
->act_halt
= bitfield(msr_image
, VMX_VCR_ACT_HLT
) != 0;
172 specs
->act_shutdown
= bitfield(msr_image
, VMX_VCR_ACT_SHUTDOWN
) != 0;
173 specs
->act_SIPI
= bitfield(msr_image
, VMX_VCR_ACT_SIPI
) != 0;
174 specs
->act_CSTATE
= bitfield(msr_image
, VMX_VCR_ACT_CSTATE
) != 0;
175 specs
->cr3_targs
= bitfield(msr_image
, VMX_VCR_CR3_TARGS
);
176 specs
->max_msrs
= (uint32_t)(512 * (1 + bitfield(msr_image
, VMX_VCR_MAX_MSRS
)));
177 specs
->mseg_id
= (uint32_t)bitfield(msr_image
, VMX_VCR_MSEG_ID
);
179 /* Obtain VMX-fixed bits in CR0 */
180 specs
->cr0_fixed_0
= (uint32_t)rdmsr64(MSR_IA32_VMX_CR0_FIXED0
) & 0xFFFFFFFF;
181 specs
->cr0_fixed_1
= (uint32_t)rdmsr64(MSR_IA32_VMX_CR0_FIXED1
) & 0xFFFFFFFF;
183 /* Obtain VMX-fixed bits in CR4 */
184 specs
->cr4_fixed_0
= (uint32_t)rdmsr64(MSR_IA32_VMX_CR4_FIXED0
) & 0xFFFFFFFF;
185 specs
->cr4_fixed_1
= (uint32_t)rdmsr64(MSR_IA32_VMX_CR4_FIXED1
) & 0xFFFFFFFF;
188 /* -----------------------------------------------------------------------------
190 Enter VMX root operation on this CPU.
191 -------------------------------------------------------------------------- */
195 vmx_cpu_t
*cpu
= ¤t_cpu_datap()->cpu_vmx
;
196 addr64_t vmxon_region_paddr
;
201 assert(cpu
->specs
.vmx_present
);
203 if (NULL
== cpu
->vmxon_region
)
204 panic("vmx_on: VMXON region not allocated");
205 vmxon_region_paddr
= vmx_paddr(cpu
->vmxon_region
);
208 * Enable VMX operation.
210 set_cr4(get_cr4() | CR4_VMXE
);
212 assert(vmx_is_cr0_valid(&cpu
->specs
));
213 assert(vmx_is_cr4_valid(&cpu
->specs
));
215 if ((result
= __vmxon(&vmxon_region_paddr
)) != VMX_SUCCEED
) {
216 panic("vmx_on: unexpected return %d from __vmxon()", result
);
220 /* -----------------------------------------------------------------------------
222 Leave VMX root operation on this CPU.
223 -------------------------------------------------------------------------- */
229 /* Tell the CPU to release the VMXON region */
230 if ((result
= __vmxoff()) != VMX_SUCCEED
) {
231 panic("vmx_off: unexpected return %d from __vmxoff()", result
);
235 /* -----------------------------------------------------------------------------
236 vmx_allocate_vmxon_regions()
237 Allocate, clear and init VMXON regions for all CPUs.
238 -------------------------------------------------------------------------- */
240 vmx_allocate_vmxon_regions(void)
244 for (i
=0; i
<real_ncpus
; i
++) {
245 vmx_cpu_t
*cpu
= &cpu_datap(i
)->cpu_vmx
;
247 /* The size is defined to be always <= 4K, so we just allocate a page */
248 cpu
->vmxon_region
= vmx_pcalloc();
249 if (NULL
== cpu
->vmxon_region
)
250 panic("vmx_allocate_vmxon_regions: unable to allocate VMXON region");
251 *(uint32_t*)(cpu
->vmxon_region
) = cpu
->specs
.vmcs_id
;
255 /* -----------------------------------------------------------------------------
256 vmx_free_vmxon_regions()
257 Free VMXON regions for all CPUs.
258 -------------------------------------------------------------------------- */
260 vmx_free_vmxon_regions(void)
264 for (i
=0; i
<real_ncpus
; i
++) {
265 vmx_cpu_t
*cpu
= &cpu_datap(i
)->cpu_vmx
;
267 vmx_pfree(cpu
->vmxon_region
);
268 cpu
->vmxon_region
= NULL
;
272 /* -----------------------------------------------------------------------------
273 vmx_globally_available()
274 Checks whether VT can be turned on for all CPUs.
275 -------------------------------------------------------------------------- */
277 vmx_globally_available(void)
281 boolean_t available
= TRUE
;
283 for (i
=0; i
<real_ncpus
; i
++) {
284 vmx_cpu_t
*cpu
= &cpu_datap(i
)->cpu_vmx
;
286 if (!cpu
->specs
.vmx_present
)
289 VMX_KPRINTF("VMX available: %d\n", available
);
294 /* -----------------------------------------------------------------------------
296 Turn on VT operation on all CPUs.
297 -------------------------------------------------------------------------- */
299 host_vmxon(boolean_t exclusive
)
302 boolean_t do_it
= FALSE
; /* do the cpu sync outside of the area holding the lock */
304 if (!vmx_globally_available())
305 return VMX_UNSUPPORTED
;
307 simple_lock(&vmx_use_count_lock
);
313 if (vmx_use_count
== 1) /* was turned off before */
315 vmx_exclusive
= exclusive
;
317 VMX_KPRINTF("VMX use count: %d\n", vmx_use_count
);
321 simple_unlock(&vmx_use_count_lock
);
324 vmx_allocate_vmxon_regions();
325 mp_rendezvous(NULL
, (void (*)(void *))vmx_on
, NULL
, NULL
);
330 /* -----------------------------------------------------------------------------
332 Turn off VT operation on all CPUs.
333 -------------------------------------------------------------------------- */
337 boolean_t do_it
= FALSE
; /* do the cpu sync outside of the area holding the lock */
339 simple_lock(&vmx_use_count_lock
);
343 vmx_exclusive
= FALSE
;
348 simple_unlock(&vmx_use_count_lock
);
351 mp_rendezvous(NULL
, (void (*)(void *))vmx_off
, NULL
, NULL
);
352 vmx_free_vmxon_regions();
355 VMX_KPRINTF("VMX use count: %d\n", vmx_use_count
);
358 /* -----------------------------------------------------------------------------
360 Turn off VT operation on this CPU if it was on.
361 Called when a CPU goes offline.
362 -------------------------------------------------------------------------- */
366 VMX_KPRINTF("vmx_suspend\n");
371 /* -----------------------------------------------------------------------------
373 Restore the previous VT state. Called when CPU comes back online.
374 -------------------------------------------------------------------------- */
378 VMX_KPRINTF("vmx_resume\n");
379 vmx_init(); /* init VMX on CPU #0 */