VirtualBox

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

Last change on this file since 96429 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette