VirtualBox

source: vbox/trunk/include/VBox/vmm/hmvmxinline.h

Last change on this file was 103289, checked in by vboxsync, 3 months ago

VMM/HMVMXR0: Nested VMX: bugref:10318 VMCS state 'launched' shouldn't be ORed only in VMX R0 code, each value is a separate state for a while now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.3 KB
Line 
1/** @file
2 * HM - VMX Structures and Definitions. (VMM)
3 */
4
5/*
6 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
7 *
8 * This file is part of VirtualBox base platform packages, as
9 * available from https://www.virtualbox.org.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation, in version 3 of the
14 * License.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, see <https://www.gnu.org/licenses>.
23 *
24 * The contents of this file may alternatively be used under the terms
25 * of the Common Development and Distribution License Version 1.0
26 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
27 * in the VirtualBox distribution, in which case the provisions of the
28 * CDDL are applicable instead of those of the GPL.
29 *
30 * You may elect to license modified versions of this file under the
31 * terms and conditions of either the GPL or the CDDL or both.
32 *
33 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
34 */
35
36#ifndef VBOX_INCLUDED_vmm_hmvmxinline_h
37#define VBOX_INCLUDED_vmm_hmvmxinline_h
38#ifndef RT_WITHOUT_PRAGMA_ONCE
39# pragma once
40#endif
41
42#include <VBox/vmm/hm_vmx.h>
43#include <VBox/err.h>
44
45/* In Visual C++ versions prior to 2012, the vmx intrinsics are only available
46 when targeting AMD64. */
47#if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 && defined(RT_ARCH_AMD64)
48# include <iprt/sanitized/intrin.h>
49/* We always want them as intrinsics, no functions. */
50# pragma intrinsic(__vmx_on)
51# pragma intrinsic(__vmx_off)
52# pragma intrinsic(__vmx_vmclear)
53# pragma intrinsic(__vmx_vmptrld)
54# pragma intrinsic(__vmx_vmread)
55# pragma intrinsic(__vmx_vmwrite)
56# define VMX_USE_MSC_INTRINSICS 1
57#else
58# define VMX_USE_MSC_INTRINSICS 0
59#endif
60
61/**
62 * Whether we think the assembler supports VMX instructions.
63 *
64 * Guess that GCC 5 should have sufficient recent enough binutils.
65 */
66#if RT_INLINE_ASM_GNU_STYLE && RT_GNUC_PREREQ(5,0)
67# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 1
68#else
69# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 0
70#endif
71
72/** Whether we can use the subsection trick to put error handling code
73 * elsewhere. */
74#if VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS && defined(__ELF__)
75# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 1
76#else
77# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 0
78#endif
79
80/* Skip checking VMREAD/VMWRITE failures on non-strict builds. */
81#ifndef VBOX_STRICT
82# define VBOX_WITH_VMREAD_VMWRITE_NOCHECK
83#endif
84
85
86/** @defgroup grp_hm_vmx_inline VMX Inline Helpers
87 * @ingroup grp_hm_vmx
88 * @{
89 */
90/**
91 * Gets the effective width of a VMCS field given it's encoding adjusted for
92 * HIGH/FULL access for 64-bit fields.
93 *
94 * @returns The effective VMCS field width.
95 * @param uFieldEnc The VMCS field encoding.
96 *
97 * @remarks Warning! This function does not verify the encoding is for a valid and
98 * supported VMCS field.
99 */
100DECLINLINE(uint8_t) VMXGetVmcsFieldWidthEff(uint32_t uFieldEnc)
101{
102 /* Only the "HIGH" parts of all 64-bit fields have bit 0 set. */
103 if (uFieldEnc & RT_BIT(0))
104 return VMXVMCSFIELDWIDTH_32BIT;
105
106 /* Bits 13:14 contains the width of the VMCS field, see VMXVMCSFIELDWIDTH_XXX. */
107 return (uFieldEnc >> 13) & 0x3;
108}
109
110
111/**
112 * Returns whether the given VMCS field is a read-only VMCS field or not.
113 *
114 * @returns @c true if it's a read-only field, @c false otherwise.
115 * @param uFieldEnc The VMCS field encoding.
116 *
117 * @remarks Warning! This function does not verify that the encoding is for a valid
118 * and/or supported VMCS field.
119 */
120DECLINLINE(bool) VMXIsVmcsFieldReadOnly(uint32_t uFieldEnc)
121{
122 /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */
123 return (RT_BF_GET(uFieldEnc, VMX_BF_VMCSFIELD_TYPE) == VMXVMCSFIELDTYPE_VMEXIT_INFO);
124}
125
126
127/**
128 * Returns whether the given VM-entry interruption-information type is valid or not.
129 *
130 * @returns @c true if it's a valid type, @c false otherwise.
131 * @param fSupportsMTF Whether the Monitor-Trap Flag CPU feature is supported.
132 * @param uType The VM-entry interruption-information type.
133 */
134DECLINLINE(bool) VMXIsEntryIntInfoTypeValid(bool fSupportsMTF, uint8_t uType)
135{
136 /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */
137 switch (uType)
138 {
139 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
140 case VMX_ENTRY_INT_INFO_TYPE_NMI:
141 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
142 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
143 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
144 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return true;
145 case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return fSupportsMTF;
146 default:
147 return false;
148 }
149}
150
151
152/**
153 * Returns whether the given VM-entry interruption-information vector and type
154 * combination is valid or not.
155 *
156 * @returns @c true if it's a valid vector/type combination, @c false otherwise.
157 * @param uVector The VM-entry interruption-information vector.
158 * @param uType The VM-entry interruption-information type.
159 *
160 * @remarks Warning! This function does not validate the type field individually.
161 * Use it after verifying type is valid using HMVmxIsEntryIntInfoTypeValid.
162 */
163DECLINLINE(bool) VMXIsEntryIntInfoVectorValid(uint8_t uVector, uint8_t uType)
164{
165 /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */
166 if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI
167 && uVector != X86_XCPT_NMI)
168 return false;
169 if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
170 && uVector > X86_XCPT_LAST)
171 return false;
172 if ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT
173 && uVector != VMX_ENTRY_INT_INFO_VECTOR_MTF)
174 return false;
175 return true;
176}
177
178
179/**
180 * Returns whether or not the VM-exit is trap-like or fault-like.
181 *
182 * @returns @c true if it's a trap-like VM-exit, @c false otherwise.
183 * @param uExitReason The VM-exit reason.
184 *
185 * @remarks Warning! This does not validate the VM-exit reason.
186 */
187DECLINLINE(bool) VMXIsVmexitTrapLike(uint32_t uExitReason)
188{
189 /*
190 * Trap-like VM-exits - The instruction causing the VM-exit completes before the
191 * VM-exit occurs.
192 *
193 * Fault-like VM-exits - The instruction causing the VM-exit is not completed before
194 * the VM-exit occurs.
195 *
196 * See Intel spec. 25.5.2 "Monitor Trap Flag".
197 * See Intel spec. 29.1.4 "EOI Virtualization".
198 * See Intel spec. 29.4.3.3 "APIC-Write VM Exits".
199 * See Intel spec. 29.1.2 "TPR Virtualization".
200 */
201 /** @todo NSTVMX: r=ramshankar: What about VM-exits due to debug traps (single-step,
202 * I/O breakpoints, data breakpoints), debug exceptions (data breakpoint)
203 * delayed by MovSS blocking, machine-check exceptions. */
204 switch (uExitReason)
205 {
206 case VMX_EXIT_MTF:
207 case VMX_EXIT_VIRTUALIZED_EOI:
208 case VMX_EXIT_APIC_WRITE:
209 case VMX_EXIT_TPR_BELOW_THRESHOLD:
210 return true;
211 }
212 return false;
213}
214
215
216/**
217 * Returns whether the VM-entry is vectoring or not given the VM-entry interruption
218 * information field.
219 *
220 * @returns @c true if the VM-entry is vectoring, @c false otherwise.
221 * @param uEntryIntInfo The VM-entry interruption information field.
222 * @param pEntryIntInfoType The VM-entry interruption information type field.
223 * Optional, can be NULL. Only updated when this
224 * function returns @c true.
225 */
226DECLINLINE(bool) VMXIsVmentryVectoring(uint32_t uEntryIntInfo, uint8_t *pEntryIntInfoType)
227{
228 /*
229 * The definition of what is a vectoring VM-entry is taken
230 * from Intel spec. 26.6 "Special Features of VM Entry".
231 */
232 if (!VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo))
233 return false;
234
235 /* Scope and keep variable defines on top to satisy archaic c89 nonsense. */
236 {
237 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo);
238 switch (uType)
239 {
240 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
241 case VMX_ENTRY_INT_INFO_TYPE_NMI:
242 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
243 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
244 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
245 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT:
246 {
247 if (pEntryIntInfoType)
248 *pEntryIntInfoType = uType;
249 return true;
250 }
251 }
252 }
253 return false;
254}
255
256
257/**
258 * Gets the description for a VMX abort reason.
259 *
260 * @returns The descriptive string.
261 * @param enmAbort The VMX abort reason.
262 */
263DECLINLINE(const char *) VMXGetAbortDesc(VMXABORT enmAbort)
264{
265 switch (enmAbort)
266 {
267 case VMXABORT_NONE: return "VMXABORT_NONE";
268 case VMXABORT_SAVE_GUEST_MSRS: return "VMXABORT_SAVE_GUEST_MSRS";
269 case VMXBOART_HOST_PDPTE: return "VMXBOART_HOST_PDPTE";
270 case VMXABORT_CURRENT_VMCS_CORRUPT: return "VMXABORT_CURRENT_VMCS_CORRUPT";
271 case VMXABORT_LOAD_HOST_MSR: return "VMXABORT_LOAD_HOST_MSR";
272 case VMXABORT_MACHINE_CHECK_XCPT: return "VMXABORT_MACHINE_CHECK_XCPT";
273 case VMXABORT_HOST_NOT_IN_LONG_MODE: return "VMXABORT_HOST_NOT_IN_LONG_MODE";
274 default:
275 break;
276 }
277 return "Unknown/invalid";
278}
279
280
281/**
282 * Gets the description for a virtual VMCS state.
283 *
284 * @returns The descriptive string.
285 * @param fVmcsState The virtual-VMCS state.
286 */
287DECLINLINE(const char *) VMXGetVmcsStateDesc(uint8_t fVmcsState)
288{
289 switch (fVmcsState)
290 {
291 case VMX_V_VMCS_LAUNCH_STATE_CLEAR: return "Clear";
292 case VMX_V_VMCS_LAUNCH_STATE_CLEAR_LEGACY: return "Clear (Legacy)";
293 case VMX_V_VMCS_LAUNCH_STATE_LAUNCHED: return "Launched";
294 default: return "Unknown";
295 }
296}
297
298
299/**
300 * Gets the description for a VM-entry interruption information event type.
301 *
302 * @returns The descriptive string.
303 * @param uType The event type.
304 */
305DECLINLINE(const char *) VMXGetEntryIntInfoTypeDesc(uint8_t uType)
306{
307 switch (uType)
308 {
309 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: return "External Interrupt";
310 case VMX_ENTRY_INT_INFO_TYPE_NMI: return "NMI";
311 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception";
312 case VMX_ENTRY_INT_INFO_TYPE_SW_INT: return "Software Interrupt";
313 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
314 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return "Software Exception";
315 case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return "Other Event";
316 default:
317 break;
318 }
319 return "Unknown/invalid";
320}
321
322
323/**
324 * Gets the description for a VM-exit interruption information event type.
325 *
326 * @returns The descriptive string.
327 * @param uType The event type.
328 */
329DECLINLINE(const char *) VMXGetExitIntInfoTypeDesc(uint8_t uType)
330{
331 switch (uType)
332 {
333 case VMX_EXIT_INT_INFO_TYPE_EXT_INT: return "External Interrupt";
334 case VMX_EXIT_INT_INFO_TYPE_NMI: return "NMI";
335 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception";
336 case VMX_EXIT_INT_INFO_TYPE_SW_INT: return "Software Interrupt";
337 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
338 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: return "Software Exception";
339 default:
340 break;
341 }
342 return "Unknown/invalid";
343}
344
345
346/**
347 * Gets the description for an IDT-vectoring information event type.
348 *
349 * @returns The descriptive string.
350 * @param uType The event type.
351 */
352DECLINLINE(const char *) VMXGetIdtVectoringInfoTypeDesc(uint8_t uType)
353{
354 switch (uType)
355 {
356 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT: return "External Interrupt";
357 case VMX_IDT_VECTORING_INFO_TYPE_NMI: return "NMI";
358 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT: return "Hardware Exception";
359 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT: return "Software Interrupt";
360 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
361 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: return "Software Exception";
362 default:
363 break;
364 }
365 return "Unknown/invalid";
366}
367
368
369/** @} */
370
371
372/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers
373 * @{
374 */
375#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
376
377/**
378 * Dispatches an NMI to the host.
379 */
380DECLASM(int) VMXDispatchHostNmi(void);
381
382
383/**
384 * Executes VMXON.
385 *
386 * @returns VBox status code.
387 * @param HCPhysVmxOn Physical address of VMXON structure.
388 */
389#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
390DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn);
391#else
392DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn)
393{
394# if VMX_USE_MSC_INTRINSICS
395 unsigned char rcMsc = __vmx_on(&HCPhysVmxOn);
396 if (RT_LIKELY(rcMsc == 0))
397 return VINF_SUCCESS;
398 return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED;
399
400# elif RT_INLINE_ASM_GNU_STYLE
401# ifdef RT_ARCH_AMD64
402 int rc;
403 __asm__ __volatile__ (
404 "pushq %2 \n\t"
405 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
406 "ja 2f \n\t"
407 "je 1f \n\t"
408 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
409 "jmp 2f \n\t"
410 "1: \n\t"
411 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
412 "2: \n\t"
413 "add $8, %%rsp \n\t"
414 :"=rm"(rc)
415 :"0"(VINF_SUCCESS),
416 "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */
417 /* this would not work with -fomit-frame-pointer */
418 :"memory"
419 );
420 return rc;
421# else
422 int rc;
423 __asm__ __volatile__ (
424 "push %3 \n\t"
425 "push %2 \n\t"
426 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
427 "ja 2f \n\t"
428 "je 1f \n\t"
429 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
430 "jmp 2f \n\t"
431 "1: \n\t"
432 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
433 "2: \n\t"
434 "add $8, %%esp \n\t"
435 :"=rm"(rc)
436 :"0"(VINF_SUCCESS),
437 "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */
438 "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */
439 :"memory"
440 );
441 return rc;
442# endif
443
444# elif defined(RT_ARCH_X86)
445 int rc = VINF_SUCCESS;
446 __asm
447 {
448 push dword ptr [HCPhysVmxOn + 4]
449 push dword ptr [HCPhysVmxOn]
450 _emit 0xf3
451 _emit 0x0f
452 _emit 0xc7
453 _emit 0x34
454 _emit 0x24 /* VMXON [esp] */
455 jnc vmxon_good
456 mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR
457 jmp the_end
458
459vmxon_good:
460 jnz the_end
461 mov dword ptr [rc], VERR_VMX_VMXON_FAILED
462the_end:
463 add esp, 8
464 }
465 return rc;
466
467# else
468# error "Shouldn't be here..."
469# endif
470}
471#endif
472
473
474/**
475 * Executes VMXOFF.
476 */
477#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
478DECLASM(void) VMXDisable(void);
479#else
480DECLINLINE(void) VMXDisable(void)
481{
482# if VMX_USE_MSC_INTRINSICS
483 __vmx_off();
484
485# elif RT_INLINE_ASM_GNU_STYLE
486 __asm__ __volatile__ (
487 ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t"
488 );
489
490# elif defined(RT_ARCH_X86)
491 __asm
492 {
493 _emit 0x0f
494 _emit 0x01
495 _emit 0xc4 /* VMXOFF */
496 }
497
498# else
499# error "Shouldn't be here..."
500# endif
501}
502#endif
503
504
505/**
506 * Executes VMCLEAR.
507 *
508 * @returns VBox status code.
509 * @param HCPhysVmcs Physical address of VM control structure.
510 */
511#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
512DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
513#else
514DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs)
515{
516# if VMX_USE_MSC_INTRINSICS
517 unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs);
518 if (RT_LIKELY(rcMsc == 0))
519 return VINF_SUCCESS;
520 return VERR_VMX_INVALID_VMCS_PTR;
521
522# elif RT_INLINE_ASM_GNU_STYLE
523# ifdef RT_ARCH_AMD64
524 int rc;
525 __asm__ __volatile__ (
526 "pushq %2 \n\t"
527 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
528 "jnc 1f \n\t"
529 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
530 "1: \n\t"
531 "add $8, %%rsp \n\t"
532 :"=rm"(rc)
533 :"0"(VINF_SUCCESS),
534 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
535 /* this would not work with -fomit-frame-pointer */
536 :"memory"
537 );
538 return rc;
539# else
540 int rc;
541 __asm__ __volatile__ (
542 "push %3 \n\t"
543 "push %2 \n\t"
544 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
545 "jnc 1f \n\t"
546 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
547 "1: \n\t"
548 "add $8, %%esp \n\t"
549 :"=rm"(rc)
550 :"0"(VINF_SUCCESS),
551 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
552 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */
553 :"memory"
554 );
555 return rc;
556# endif
557
558# elif defined(RT_ARCH_X86)
559 int rc = VINF_SUCCESS;
560 __asm
561 {
562 push dword ptr [HCPhysVmcs + 4]
563 push dword ptr [HCPhysVmcs]
564 _emit 0x66
565 _emit 0x0f
566 _emit 0xc7
567 _emit 0x34
568 _emit 0x24 /* VMCLEAR [esp] */
569 jnc success
570 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
571success:
572 add esp, 8
573 }
574 return rc;
575
576# else
577# error "Shouldn't be here..."
578# endif
579}
580#endif
581
582
583/**
584 * Executes VMPTRLD.
585 *
586 * @returns VBox status code.
587 * @param HCPhysVmcs Physical address of VMCS structure.
588 */
589#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
590DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs);
591#else
592DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs)
593{
594# if VMX_USE_MSC_INTRINSICS
595 unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs);
596 if (RT_LIKELY(rcMsc == 0))
597 return VINF_SUCCESS;
598 return VERR_VMX_INVALID_VMCS_PTR;
599
600# elif RT_INLINE_ASM_GNU_STYLE
601# ifdef RT_ARCH_AMD64
602 int rc;
603 __asm__ __volatile__ (
604 "pushq %2 \n\t"
605 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
606 "jnc 1f \n\t"
607 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
608 "1: \n\t"
609 "add $8, %%rsp \n\t"
610 :"=rm"(rc)
611 :"0"(VINF_SUCCESS),
612 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
613 /* this will not work with -fomit-frame-pointer */
614 :"memory"
615 );
616 return rc;
617# else
618 int rc;
619 __asm__ __volatile__ (
620 "push %3 \n\t"
621 "push %2 \n\t"
622 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
623 "jnc 1f \n\t"
624 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
625 "1: \n\t"
626 "add $8, %%esp \n\t"
627 :"=rm"(rc)
628 :"0"(VINF_SUCCESS),
629 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
630 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */
631 :"memory"
632 );
633 return rc;
634# endif
635
636# elif defined(RT_ARCH_X86)
637 int rc = VINF_SUCCESS;
638 __asm
639 {
640 push dword ptr [HCPhysVmcs + 4]
641 push dword ptr [HCPhysVmcs]
642 _emit 0x0f
643 _emit 0xc7
644 _emit 0x34
645 _emit 0x24 /* VMPTRLD [esp] */
646 jnc success
647 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
648success:
649 add esp, 8
650 }
651 return rc;
652
653# else
654# error "Shouldn't be here..."
655# endif
656}
657#endif
658
659
660/**
661 * Executes VMPTRST.
662 *
663 * @returns VBox status code.
664 * @param pHCPhysVmcs Where to store the physical address of the current
665 * VMCS.
666 */
667DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs);
668
669
670/**
671 * Executes VMWRITE for a 32-bit field.
672 *
673 * @returns VBox status code.
674 * @retval VINF_SUCCESS.
675 * @retval VERR_VMX_INVALID_VMCS_PTR.
676 * @retval VERR_VMX_INVALID_VMCS_FIELD.
677 *
678 * @param uFieldEnc VMCS field encoding.
679 * @param u32Val The 32-bit value to set.
680 *
681 * @remarks The values of the two status codes can be OR'ed together, the result
682 * will be VERR_VMX_INVALID_VMCS_PTR.
683 */
684#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
685DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val);
686#else
687DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val)
688{
689# if VMX_USE_MSC_INTRINSICS
690# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
691 __vmx_vmwrite(uFieldEnc, u32Val);
692 return VINF_SUCCESS;
693# else
694 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val);
695 if (RT_LIKELY(rcMsc == 0))
696 return VINF_SUCCESS;
697 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
698# endif
699
700# elif RT_INLINE_ASM_GNU_STYLE
701# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
702 __asm__ __volatile__ (
703 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
704 :
705 :"a"(uFieldEnc),
706 "d"(u32Val)
707 );
708 return VINF_SUCCESS;
709# else
710 int rc;
711 __asm__ __volatile__ (
712 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
713 "ja 2f \n\t"
714 "je 1f \n\t"
715 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
716 "jmp 2f \n\t"
717 "1: \n\t"
718 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
719 "2: \n\t"
720 :"=rm"(rc)
721 :"0"(VINF_SUCCESS),
722 "a"(uFieldEnc),
723 "d"(u32Val)
724 );
725 return rc;
726# endif
727
728# elif defined(RT_ARCH_X86)
729 int rc = VINF_SUCCESS;
730 __asm
731 {
732 push dword ptr [u32Val]
733 mov eax, [uFieldEnc]
734 _emit 0x0f
735 _emit 0x79
736 _emit 0x04
737 _emit 0x24 /* VMWRITE eax, [esp] */
738 jnc valid_vmcs
739 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
740 jmp the_end
741valid_vmcs:
742 jnz the_end
743 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
744the_end:
745 add esp, 4
746 }
747 return rc;
748
749# else
750# error "Shouldn't be here..."
751# endif
752}
753#endif
754
755
756/**
757 * Executes VMWRITE for a 64-bit field.
758 *
759 * @returns VBox status code.
760 * @retval VINF_SUCCESS.
761 * @retval VERR_VMX_INVALID_VMCS_PTR.
762 * @retval VERR_VMX_INVALID_VMCS_FIELD.
763 *
764 * @param uFieldEnc The VMCS field encoding.
765 * @param u64Val The 16, 32 or 64-bit value to set.
766 *
767 * @remarks The values of the two status codes can be OR'ed together, the result
768 * will be VERR_VMX_INVALID_VMCS_PTR.
769 */
770#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
771DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val);
772#else
773DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val)
774{
775# if VMX_USE_MSC_INTRINSICS
776# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
777 __vmx_vmwrite(uFieldEnc, u64Val);
778 return VINF_SUCCESS;
779# else
780 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val);
781 if (RT_LIKELY(rcMsc == 0))
782 return VINF_SUCCESS;
783 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
784# endif
785
786# elif RT_INLINE_ASM_GNU_STYLE
787# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
788 __asm__ __volatile__ (
789 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
790 :
791 :"a"(uFieldEnc),
792 "d"(u64Val)
793 );
794 return VINF_SUCCESS;
795# else
796 int rc;
797 __asm__ __volatile__ (
798 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
799 "ja 2f \n\t"
800 "je 1f \n\t"
801 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
802 "jmp 2f \n\t"
803 "1: \n\t"
804 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
805 "2: \n\t"
806 :"=rm"(rc)
807 :"0"(VINF_SUCCESS),
808 "a"(uFieldEnc),
809 "d"(u64Val)
810 );
811 return rc;
812# endif
813
814# else
815# error "Shouldn't be here..."
816# endif
817}
818#endif
819
820
821/**
822 * Executes VMWRITE for a 16-bit VMCS field.
823 *
824 * @returns VBox status code.
825 * @retval VINF_SUCCESS.
826 * @retval VERR_VMX_INVALID_VMCS_PTR.
827 * @retval VERR_VMX_INVALID_VMCS_FIELD.
828 *
829 * @param uVmcsField The VMCS field.
830 * @param u16Val The 16-bit value to set.
831 *
832 * @remarks The values of the two status codes can be OR'ed together, the result
833 * will be VERR_VMX_INVALID_VMCS_PTR.
834 */
835DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val)
836{
837 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
838 return VMXWriteVmcs32(uVmcsField, u16Val);
839}
840
841
842/**
843 * Executes VMWRITE for a natural-width VMCS field.
844 */
845#ifdef RT_ARCH_AMD64
846# define VMXWriteVmcsNw VMXWriteVmcs64
847#else
848# define VMXWriteVmcsNw VMXWriteVmcs32
849#endif
850
851
852/**
853 * Invalidate a page using INVEPT.
854 *
855 * @returns VBox status code.
856 * @param enmFlush Type of flush.
857 * @param pDescriptor Pointer to the descriptor.
858 */
859DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor);
860
861
862/**
863 * Invalidate a page using INVVPID.
864 *
865 * @returns VBox status code.
866 * @param enmFlush Type of flush.
867 * @param pDescriptor Pointer to the descriptor.
868 */
869DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor);
870
871
872/**
873 * Executes VMREAD for a 32-bit field.
874 *
875 * @returns VBox status code.
876 * @retval VINF_SUCCESS.
877 * @retval VERR_VMX_INVALID_VMCS_PTR.
878 * @retval VERR_VMX_INVALID_VMCS_FIELD.
879 *
880 * @param uFieldEnc The VMCS field encoding.
881 * @param pData Where to store VMCS field value.
882 *
883 * @remarks The values of the two status codes can be OR'ed together, the result
884 * will be VERR_VMX_INVALID_VMCS_PTR.
885 */
886#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
887DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData);
888#else
889DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData)
890{
891# if VMX_USE_MSC_INTRINSICS
892# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
893 uint64_t u64Tmp = 0;
894 __vmx_vmread(uFieldEnc, &u64Tmp);
895 *pData = (uint32_t)u64Tmp;
896 return VINF_SUCCESS;
897# else
898 unsigned char rcMsc;
899 uint64_t u64Tmp;
900 rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp);
901 *pData = (uint32_t)u64Tmp;
902 if (RT_LIKELY(rcMsc == 0))
903 return VINF_SUCCESS;
904 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
905# endif
906
907# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS
908 RTCCUINTREG uTmp = 0;
909# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
910 __asm__ __volatile__("vmread %[uField],%[uDst]"
911 : [uDst] "=mr" (uTmp)
912 : [uField] "r" ((RTCCUINTREG)uFieldEnc));
913 *pData = (uint32_t)uTmp;
914 return VINF_SUCCESS;
915# else
916#if 0
917 int rc;
918 __asm__ __volatile__("vmread %[uField],%[uDst]\n\t"
919 "movl %[rcSuccess],%[rc]\n\t"
920# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK
921 "jna 1f\n\t"
922 ".section .text.vmread_failures, \"ax?\"\n\t"
923 "1:\n\t"
924 "movl %[rcInvalidVmcsPtr],%[rc]\n\t"
925 "jnz 2f\n\t"
926 "movl %[rcInvalidVmcsField],%[rc]\n\t"
927 "2:\n\t"
928 "jmp 3f\n\t"
929 ".previous\n\t"
930 "3:\n\t"
931# else
932 "ja 1f\n\t"
933 "movl %[rcInvalidVmcsPtr],%[rc]\n\t"
934 "jnz 1f\n\t"
935 "movl %[rcInvalidVmcsField],%[rc]\n\t"
936 "1:\n\t"
937# endif
938 : [uDst] "=mr" (uTmp)
939 , [rc] "=r" (rc)
940 : [uField] "r" ((RTCCUINTREG)uFieldEnc)
941 , [rcSuccess] "i" (VINF_SUCCESS)
942 , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR)
943 , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD));
944 *pData = uTmp;
945 return rc;
946#else
947 int fSuccess, fFieldError;
948 __asm__ __volatile__("vmread %[uField],%[uDst]"
949 : [uDst] "=mr" (uTmp)
950 , "=@cca" (fSuccess)
951 , "=@ccnc" (fFieldError)
952 : [uField] "r" ((RTCCUINTREG)uFieldEnc));
953 *pData = uTmp;
954 return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR;
955#endif
956# endif
957
958# elif RT_INLINE_ASM_GNU_STYLE
959# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
960 __asm__ __volatile__ (
961 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
962 :"=d"(*pData)
963 :"a"(uFieldEnc),
964 "d"(0)
965 );
966 return VINF_SUCCESS;
967# else
968 int rc;
969 __asm__ __volatile__ (
970 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
971 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
972 "ja 2f \n\t"
973 "je 1f \n\t"
974 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
975 "jmp 2f \n\t"
976 "1: \n\t"
977 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
978 "2: \n\t"
979 :"=&r"(rc),
980 "=d"(*pData)
981 :"a"(uFieldEnc),
982 "d"(0)
983 );
984 return rc;
985# endif
986
987# elif defined(RT_ARCH_X86)
988 int rc = VINF_SUCCESS;
989 __asm
990 {
991 sub esp, 4
992 mov dword ptr [esp], 0
993 mov eax, [uFieldEnc]
994 _emit 0x0f
995 _emit 0x78
996 _emit 0x04
997 _emit 0x24 /* VMREAD eax, [esp] */
998 mov edx, pData
999 pop dword ptr [edx]
1000 jnc valid_vmcs
1001 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
1002 jmp the_end
1003valid_vmcs:
1004 jnz the_end
1005 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
1006the_end:
1007 }
1008 return rc;
1009
1010# else
1011# error "Shouldn't be here..."
1012# endif
1013}
1014#endif
1015
1016
1017/**
1018 * Executes VMREAD for a 64-bit field.
1019 *
1020 * @returns VBox status code.
1021 * @retval VINF_SUCCESS.
1022 * @retval VERR_VMX_INVALID_VMCS_PTR.
1023 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1024 *
1025 * @param uFieldEnc The VMCS field encoding.
1026 * @param pData Where to store VMCS field value.
1027 *
1028 * @remarks The values of the two status codes can be OR'ed together, the result
1029 * will be VERR_VMX_INVALID_VMCS_PTR.
1030 */
1031#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
1032DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData);
1033#else
1034DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData)
1035{
1036# if VMX_USE_MSC_INTRINSICS
1037# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1038 __vmx_vmread(uFieldEnc, pData);
1039 return VINF_SUCCESS;
1040# else
1041 unsigned char rcMsc;
1042 rcMsc = __vmx_vmread(uFieldEnc, pData);
1043 if (RT_LIKELY(rcMsc == 0))
1044 return VINF_SUCCESS;
1045 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1046# endif
1047
1048# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS
1049 uint64_t uTmp = 0;
1050# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1051 __asm__ __volatile__("vmreadq %[uField],%[uDst]"
1052 : [uDst] "=m" (uTmp)
1053 : [uField] "r" ((uint64_t)uFieldEnc));
1054 *pData = uTmp;
1055 return VINF_SUCCESS;
1056# elif 0
1057 int rc;
1058 __asm__ __volatile__("vmreadq %[uField],%[uDst]\n\t"
1059 "movl %[rcSuccess],%[rc]\n\t"
1060# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK
1061 "jna 1f\n\t"
1062 ".section .text.vmread_failures, \"ax?\"\n\t"
1063 "1:\n\t"
1064 "movl %[rcInvalidVmcsPtr],%[rc]\n\t"
1065 "jnz 2f\n\t"
1066 "movl %[rcInvalidVmcsField],%[rc]\n\t"
1067 "2:\n\t"
1068 "jmp 3f\n\t"
1069 ".previous\n\t"
1070 "3:\n\t"
1071# else
1072 "ja 1f\n\t"
1073 "movl %[rcInvalidVmcsPtr],%[rc]\n\t"
1074 "jnz 1f\n\t"
1075 "movl %[rcInvalidVmcsField],%[rc]\n\t"
1076 "1:\n\t"
1077# endif
1078 : [uDst] "=mr" (uTmp)
1079 , [rc] "=r" (rc)
1080 : [uField] "r" ((uint64_t)uFieldEnc)
1081 , [rcSuccess] "i" (VINF_SUCCESS)
1082 , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR)
1083 , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD)
1084 );
1085 *pData = uTmp;
1086 return rc;
1087# else
1088 int fSuccess, fFieldError;
1089 __asm__ __volatile__("vmread %[uField],%[uDst]"
1090 : [uDst] "=mr" (uTmp)
1091 , "=@cca" (fSuccess)
1092 , "=@ccnc" (fFieldError)
1093 : [uField] "r" ((RTCCUINTREG)uFieldEnc));
1094 *pData = uTmp;
1095 return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR;
1096# endif
1097
1098# elif RT_INLINE_ASM_GNU_STYLE
1099# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1100 __asm__ __volatile__ (
1101 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1102 :"=d"(*pData)
1103 :"a"(uFieldEnc),
1104 "d"(0)
1105 );
1106 return VINF_SUCCESS;
1107# else
1108 int rc;
1109 __asm__ __volatile__ (
1110 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
1111 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1112 "ja 2f \n\t"
1113 "je 1f \n\t"
1114 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
1115 "jmp 2f \n\t"
1116 "1: \n\t"
1117 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
1118 "2: \n\t"
1119 :"=&r"(rc),
1120 "=d"(*pData)
1121 :"a"(uFieldEnc),
1122 "d"(0)
1123 );
1124 return rc;
1125# endif
1126
1127# else
1128# error "Shouldn't be here..."
1129# endif
1130}
1131#endif
1132
1133
1134/**
1135 * Executes VMREAD for a 16-bit field.
1136 *
1137 * @returns VBox status code.
1138 * @retval VINF_SUCCESS.
1139 * @retval VERR_VMX_INVALID_VMCS_PTR.
1140 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1141 *
1142 * @param uVmcsField The VMCS field.
1143 * @param pData Where to store VMCS field value.
1144 *
1145 * @remarks The values of the two status codes can be OR'ed together, the result
1146 * will be VERR_VMX_INVALID_VMCS_PTR.
1147 */
1148DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData)
1149{
1150 uint32_t u32Tmp;
1151 int rc;
1152 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
1153 rc = VMXReadVmcs32(uVmcsField, &u32Tmp);
1154 *pData = (uint16_t)u32Tmp;
1155 return rc;
1156}
1157
1158
1159/**
1160 * Executes VMREAD for a natural-width VMCS field.
1161 */
1162#ifdef RT_ARCH_AMD64
1163# define VMXReadVmcsNw VMXReadVmcs64
1164#else
1165# define VMXReadVmcsNw VMXReadVmcs32
1166#endif
1167
1168#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
1169
1170/** @} */
1171
1172#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */
1173
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use