VirtualBox

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

Last change on this file since 89363 was 87402, checked in by vboxsync, 4 years ago

iprt/cdefs.h,asm*.h,hmvmxinline.h: Changed the RT_INLINE_ASM_USES_INTRIN value to RT_MSC_VER_XXX to make it more readable.

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