VirtualBox

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

Last change on this file since 80537 was 80364, checked in by vboxsync, 5 years ago

VMM: Nested VMX: bugref:9180 Move some of the description functions into the inline header. Removed some temporary debugging nits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 43.4 KB
Line 
1/** @file
2 * HM - VMX Structures and Definitions. (VMM)
3 */
4
5/*
6 * Copyright (C) 2006-2019 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 >= 16 && defined(RT_ARCH_AMD64)
38# pragma warning(push)
39# pragma warning(disable:4668) /* Several incorrect __cplusplus uses. */
40# pragma warning(disable:4255) /* Incorrect __slwpcb prototype. */
41# include <intrin.h>
42# pragma warning(pop)
43/* We always want them as intrinsics, no functions. */
44# pragma intrinsic(__vmx_on)
45# pragma intrinsic(__vmx_off)
46# pragma intrinsic(__vmx_vmclear)
47# pragma intrinsic(__vmx_vmptrld)
48# pragma intrinsic(__vmx_vmread)
49# pragma intrinsic(__vmx_vmwrite)
50# define VMX_USE_MSC_INTRINSICS 1
51#else
52# define VMX_USE_MSC_INTRINSICS 0
53#endif
54
55/* Skip checking VMREAD/VMWRITE failures on non-strict builds. */
56#ifndef VBOX_STRICT
57# define VBOX_WITH_VMREAD_VMWRITE_NOCHECK
58#endif
59
60
61/** @defgroup grp_hm_vmx_inline VMX Inline Helpers
62 * @ingroup grp_hm_vmx
63 * @{
64 */
65/**
66 * Gets the effective width of a VMCS field given it's encoding adjusted for
67 * HIGH/FULL access for 64-bit fields.
68 *
69 * @returns The effective VMCS field width.
70 * @param uFieldEnc The VMCS field encoding.
71 *
72 * @remarks Warning! This function does not verify the encoding is for a valid and
73 * supported VMCS field.
74 */
75DECLINLINE(uint8_t) VMXGetVmcsFieldWidthEff(uint32_t uFieldEnc)
76{
77 /* Only the "HIGH" parts of all 64-bit fields have bit 0 set. */
78 if (uFieldEnc & RT_BIT(0))
79 return VMXVMCSFIELDWIDTH_32BIT;
80
81 /* Bits 13:14 contains the width of the VMCS field, see VMXVMCSFIELDWIDTH_XXX. */
82 return (uFieldEnc >> 13) & 0x3;
83}
84
85
86/**
87 * Returns whether the given VMCS field is a read-only VMCS field or not.
88 *
89 * @returns @c true if it's a read-only field, @c false otherwise.
90 * @param uFieldEnc The VMCS field encoding.
91 *
92 * @remarks Warning! This function does not verify that the encoding is for a valid
93 * and/or supported VMCS field.
94 */
95DECLINLINE(bool) VMXIsVmcsFieldReadOnly(uint32_t uFieldEnc)
96{
97 /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */
98 return (RT_BF_GET(uFieldEnc, VMX_BF_VMCSFIELD_TYPE) == VMXVMCSFIELDTYPE_VMEXIT_INFO);
99}
100
101
102/**
103 * Returns whether the given VM-entry interruption-information type is valid or not.
104 *
105 * @returns @c true if it's a valid type, @c false otherwise.
106 * @param fSupportsMTF Whether the Monitor-Trap Flag CPU feature is supported.
107 * @param uType The VM-entry interruption-information type.
108 */
109DECLINLINE(bool) VMXIsEntryIntInfoTypeValid(bool fSupportsMTF, uint8_t uType)
110{
111 /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */
112 switch (uType)
113 {
114 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
115 case VMX_ENTRY_INT_INFO_TYPE_NMI:
116 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
117 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
118 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
119 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return true;
120 case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return fSupportsMTF;
121 default:
122 return false;
123 }
124}
125
126
127/**
128 * Returns whether the given VM-entry interruption-information vector and type
129 * combination is valid or not.
130 *
131 * @returns @c true if it's a valid vector/type combination, @c false otherwise.
132 * @param uVector The VM-entry interruption-information vector.
133 * @param uType The VM-entry interruption-information type.
134 *
135 * @remarks Warning! This function does not validate the type field individually.
136 * Use it after verifying type is valid using HMVmxIsEntryIntInfoTypeValid.
137 */
138DECLINLINE(bool) VMXIsEntryIntInfoVectorValid(uint8_t uVector, uint8_t uType)
139{
140 /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */
141 if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI
142 && uVector != X86_XCPT_NMI)
143 return false;
144 if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT
145 && uVector > X86_XCPT_LAST)
146 return false;
147 if ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT
148 && uVector != VMX_ENTRY_INT_INFO_VECTOR_MTF)
149 return false;
150 return true;
151}
152
153
154/**
155 * Returns whether or not the VM-exit is trap-like or fault-like.
156 *
157 * @returns @c true if it's a trap-like VM-exit, @c false otherwise.
158 * @param uExitReason The VM-exit reason.
159 *
160 * @remarks Warning! This does not validate the VM-exit reason.
161 */
162DECLINLINE(bool) VMXIsVmexitTrapLike(uint32_t uExitReason)
163{
164 /*
165 * Trap-like VM-exits - The instruction causing the VM-exit completes before the
166 * VM-exit occurs.
167 *
168 * Fault-like VM-exits - The instruction causing the VM-exit is not completed before
169 * the VM-exit occurs.
170 *
171 * See Intel spec. 25.5.2 "Monitor Trap Flag".
172 * See Intel spec. 29.1.4 "EOI Virtualization".
173 * See Intel spec. 29.4.3.3 "APIC-Write VM Exits".
174 * See Intel spec. 29.1.2 "TPR Virtualization".
175 */
176 /** @todo NSTVMX: r=ramshankar: What about VM-exits due to debug traps (single-step,
177 * I/O breakpoints, data breakpoints), debug exceptions (data breakpoint)
178 * delayed by MovSS blocking, machine-check exceptions. */
179 switch (uExitReason)
180 {
181 case VMX_EXIT_MTF:
182 case VMX_EXIT_VIRTUALIZED_EOI:
183 case VMX_EXIT_APIC_WRITE:
184 case VMX_EXIT_TPR_BELOW_THRESHOLD:
185 return true;
186 }
187 return false;
188}
189
190
191/**
192 * Returns whether the VM-entry is vectoring or not given the VM-entry interruption
193 * information field.
194 *
195 * @returns @c true if the VM-entry is vectoring, @c false otherwise.
196 * @param uEntryIntInfo The VM-entry interruption information field.
197 * @param pEntryIntInfoType The VM-entry interruption information type field.
198 * Optional, can be NULL. Only updated when this
199 * function returns @c true.
200 */
201DECLINLINE(bool) VMXIsVmentryVectoring(uint32_t uEntryIntInfo, uint8_t *pEntryIntInfoType)
202{
203 /*
204 * The definition of what is a vectoring VM-entry is taken
205 * from Intel spec. 26.6 "Special Features of VM Entry".
206 */
207 if (!VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo))
208 return false;
209
210 /* Scope and keep variable defines on top to satisy archaic c89 nonsense. */
211 {
212 uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo);
213 switch (uType)
214 {
215 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT:
216 case VMX_ENTRY_INT_INFO_TYPE_NMI:
217 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT:
218 case VMX_ENTRY_INT_INFO_TYPE_SW_INT:
219 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT:
220 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT:
221 {
222 if (pEntryIntInfoType)
223 *pEntryIntInfoType = uType;
224 return true;
225 }
226 }
227 }
228 return false;
229}
230
231
232/**
233 * Gets the description for a VMX abort reason.
234 *
235 * @returns The descriptive string.
236 * @param enmAbort The VMX abort reason.
237 */
238DECLINLINE(const char *) VMXGetAbortDesc(VMXABORT enmAbort)
239{
240 switch (enmAbort)
241 {
242 case VMXABORT_NONE: return "VMXABORT_NONE";
243 case VMXABORT_SAVE_GUEST_MSRS: return "VMXABORT_SAVE_GUEST_MSRS";
244 case VMXBOART_HOST_PDPTE: return "VMXBOART_HOST_PDPTE";
245 case VMXABORT_CURRENT_VMCS_CORRUPT: return "VMXABORT_CURRENT_VMCS_CORRUPT";
246 case VMXABORT_LOAD_HOST_MSR: return "VMXABORT_LOAD_HOST_MSR";
247 case VMXABORT_MACHINE_CHECK_XCPT: return "VMXABORT_MACHINE_CHECK_XCPT";
248 case VMXABORT_HOST_NOT_IN_LONG_MODE: return "VMXABORT_HOST_NOT_IN_LONG_MODE";
249 default:
250 break;
251 }
252 return "Unknown/invalid";
253}
254
255
256/**
257 * Gets the description for a virtual VMCS state.
258 *
259 * @returns The descriptive string.
260 * @param fVmcsState The virtual-VMCS state.
261 */
262DECLINLINE(const char *) VMXGetVmcsStateDesc(uint8_t fVmcsState)
263{
264 switch (fVmcsState)
265 {
266 case VMX_V_VMCS_LAUNCH_STATE_CLEAR: return "Clear";
267 case VMX_V_VMCS_LAUNCH_STATE_LAUNCHED: return "Launched";
268 default: return "Unknown";
269 }
270}
271
272
273/**
274 * Gets the description for a VM-entry interruption information event type.
275 *
276 * @returns The descriptive string.
277 * @param uType The event type.
278 */
279DECLINLINE(const char *) VMXGetEntryIntInfoTypeDesc(uint8_t uType)
280{
281 switch (uType)
282 {
283 case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: return "External Interrupt";
284 case VMX_ENTRY_INT_INFO_TYPE_NMI: return "NMI";
285 case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception";
286 case VMX_ENTRY_INT_INFO_TYPE_SW_INT: return "Software Interrupt";
287 case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
288 case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return "Software Exception";
289 case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return "Other Event";
290 default:
291 break;
292 }
293 return "Unknown/invalid";
294}
295
296
297/**
298 * Gets the description for a VM-exit interruption information event type.
299 *
300 * @returns The descriptive string.
301 * @param uType The event type.
302 */
303DECLINLINE(const char *) VMXGetExitIntInfoTypeDesc(uint8_t uType)
304{
305 switch (uType)
306 {
307 case VMX_EXIT_INT_INFO_TYPE_EXT_INT: return "External Interrupt";
308 case VMX_EXIT_INT_INFO_TYPE_NMI: return "NMI";
309 case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception";
310 case VMX_EXIT_INT_INFO_TYPE_SW_INT: return "Software Interrupt";
311 case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
312 case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: return "Software Exception";
313 default:
314 break;
315 }
316 return "Unknown/invalid";
317}
318
319
320/**
321 * Gets the description for an IDT-vectoring information event type.
322 *
323 * @returns The descriptive string.
324 * @param uType The event type.
325 */
326DECLINLINE(const char *) VMXGetIdtVectoringInfoTypeDesc(uint8_t uType)
327{
328 switch (uType)
329 {
330 case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT: return "External Interrupt";
331 case VMX_IDT_VECTORING_INFO_TYPE_NMI: return "NMI";
332 case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT: return "Hardware Exception";
333 case VMX_IDT_VECTORING_INFO_TYPE_SW_INT: return "Software Interrupt";
334 case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception";
335 case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: return "Software Exception";
336 default:
337 break;
338 }
339 return "Unknown/invalid";
340}
341
342
343/** @} */
344
345
346/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers
347 * @{
348 */
349#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
350
351/**
352 * Restores some host-state fields that need not be done on every VM-exit.
353 *
354 * @returns VBox status code.
355 * @param fRestoreHostFlags Flags of which host registers needs to be
356 * restored.
357 * @param pRestoreHost Pointer to the host-restore structure.
358 */
359DECLASM(int) VMXRestoreHostState(uint32_t fRestoreHostFlags, PVMXRESTOREHOST pRestoreHost);
360
361
362/**
363 * Dispatches an NMI to the host.
364 */
365DECLASM(int) VMXDispatchHostNmi(void);
366
367
368/**
369 * Executes VMXON.
370 *
371 * @returns VBox status code.
372 * @param HCPhysVmxOn Physical address of VMXON structure.
373 */
374#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
375DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn);
376#else
377DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn)
378{
379# if VMX_USE_MSC_INTRINSICS
380 unsigned char rcMsc = __vmx_on(&HCPhysVmxOn);
381 if (RT_LIKELY(rcMsc == 0))
382 return VINF_SUCCESS;
383 return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED;
384
385# elif RT_INLINE_ASM_GNU_STYLE
386# ifdef RT_ARCH_AMD64
387 int rc;
388 __asm__ __volatile__ (
389 "pushq %2 \n\t"
390 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
391 "ja 2f \n\t"
392 "je 1f \n\t"
393 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
394 "jmp 2f \n\t"
395 "1: \n\t"
396 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
397 "2: \n\t"
398 "add $8, %%rsp \n\t"
399 :"=rm"(rc)
400 :"0"(VINF_SUCCESS),
401 "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */
402 /* this would not work with -fomit-frame-pointer */
403 :"memory"
404 );
405 return rc;
406# else
407 int rc;
408 __asm__ __volatile__ (
409 "push %3 \n\t"
410 "push %2 \n\t"
411 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
412 "ja 2f \n\t"
413 "je 1f \n\t"
414 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
415 "jmp 2f \n\t"
416 "1: \n\t"
417 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
418 "2: \n\t"
419 "add $8, %%esp \n\t"
420 :"=rm"(rc)
421 :"0"(VINF_SUCCESS),
422 "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */
423 "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */
424 :"memory"
425 );
426 return rc;
427# endif
428
429# elif defined(RT_ARCH_X86)
430 int rc = VINF_SUCCESS;
431 __asm
432 {
433 push dword ptr [HCPhysVmxOn + 4]
434 push dword ptr [HCPhysVmxOn]
435 _emit 0xf3
436 _emit 0x0f
437 _emit 0xc7
438 _emit 0x34
439 _emit 0x24 /* VMXON [esp] */
440 jnc vmxon_good
441 mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR
442 jmp the_end
443
444vmxon_good:
445 jnz the_end
446 mov dword ptr [rc], VERR_VMX_VMXON_FAILED
447the_end:
448 add esp, 8
449 }
450 return rc;
451
452# else
453# error "Shouldn't be here..."
454# endif
455}
456#endif
457
458
459#if 0
460#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
461DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn);
462#else
463DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn)
464{
465# if RT_INLINE_ASM_GNU_STYLE
466 int rc = VINF_SUCCESS;
467 __asm__ __volatile__ (
468 "push %3 \n\t"
469 "push %2 \n\t"
470 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
471 "ja 2f \n\t"
472 "je 1f \n\t"
473 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
474 "jmp 2f \n\t"
475 "1: \n\t"
476 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
477 "2: \n\t"
478 "add $8, %%esp \n\t"
479 :"=rm"(rc)
480 :"0"(VINF_SUCCESS),
481 "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */
482 "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */
483 :"memory"
484 );
485 return rc;
486
487# elif VMX_USE_MSC_INTRINSICS
488 unsigned char rcMsc = __vmx_on(&HCPhysVmxOn);
489 if (RT_LIKELY(rcMsc == 0))
490 return VINF_SUCCESS;
491 return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED;
492
493# else
494 int rc = VINF_SUCCESS;
495 __asm
496 {
497 push dword ptr [HCPhysVmxOn + 4]
498 push dword ptr [HCPhysVmxOn]
499 _emit 0xf3
500 _emit 0x0f
501 _emit 0xc7
502 _emit 0x34
503 _emit 0x24 /* VMXON [esp] */
504 jnc vmxon_good
505 mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR
506 jmp the_end
507
508vmxon_good:
509 jnz the_end
510 mov dword ptr [rc], VERR_VMX_VMXON_FAILED
511the_end:
512 add esp, 8
513 }
514 return rc;
515# endif
516}
517#endif
518#endif
519
520
521/**
522 * Executes VMXOFF.
523 */
524#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
525DECLASM(void) VMXDisable(void);
526#else
527DECLINLINE(void) VMXDisable(void)
528{
529# if VMX_USE_MSC_INTRINSICS
530 __vmx_off();
531
532# elif RT_INLINE_ASM_GNU_STYLE
533 __asm__ __volatile__ (
534 ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t"
535 );
536
537# elif defined(RT_ARCH_X86)
538 __asm
539 {
540 _emit 0x0f
541 _emit 0x01
542 _emit 0xc4 /* VMXOFF */
543 }
544
545# else
546# error "Shouldn't be here..."
547# endif
548}
549#endif
550
551
552#if 0
553#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
554DECLASM(void) VMXDisable(void);
555#else
556DECLINLINE(void) VMXDisable(void)
557{
558# if RT_INLINE_ASM_GNU_STYLE
559 __asm__ __volatile__ (
560 ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t"
561 );
562
563# elif VMX_USE_MSC_INTRINSICS
564 __vmx_off();
565
566# else
567 __asm
568 {
569 _emit 0x0f
570 _emit 0x01
571 _emit 0xc4 /* VMXOFF */
572 }
573# endif
574}
575#endif
576#endif
577
578
579/**
580 * Executes VMCLEAR.
581 *
582 * @returns VBox status code.
583 * @param HCPhysVmcs Physical address of VM control structure.
584 */
585#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
586DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
587#else
588DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs)
589{
590# if VMX_USE_MSC_INTRINSICS
591 unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs);
592 if (RT_LIKELY(rcMsc == 0))
593 return VINF_SUCCESS;
594 return VERR_VMX_INVALID_VMCS_PTR;
595
596# elif RT_INLINE_ASM_GNU_STYLE
597# ifdef RT_ARCH_AMD64
598 int rc;
599 __asm__ __volatile__ (
600 "pushq %2 \n\t"
601 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
602 "jnc 1f \n\t"
603 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
604 "1: \n\t"
605 "add $8, %%rsp \n\t"
606 :"=rm"(rc)
607 :"0"(VINF_SUCCESS),
608 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
609 /* this would not work with -fomit-frame-pointer */
610 :"memory"
611 );
612 return rc;
613# else
614 int rc;
615 __asm__ __volatile__ (
616 "push %3 \n\t"
617 "push %2 \n\t"
618 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
619 "jnc 1f \n\t"
620 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
621 "1: \n\t"
622 "add $8, %%esp \n\t"
623 :"=rm"(rc)
624 :"0"(VINF_SUCCESS),
625 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
626 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */
627 :"memory"
628 );
629 return rc;
630# endif
631
632# elif defined(RT_ARCH_X86)
633 int rc = VINF_SUCCESS;
634 __asm
635 {
636 push dword ptr [HCPhysVmcs + 4]
637 push dword ptr [HCPhysVmcs]
638 _emit 0x66
639 _emit 0x0f
640 _emit 0xc7
641 _emit 0x34
642 _emit 0x24 /* VMCLEAR [esp] */
643 jnc success
644 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
645success:
646 add esp, 8
647 }
648 return rc;
649
650# else
651# error "Shouldn't be here..."
652# endif
653}
654#endif
655
656
657#if 0
658#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
659DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
660#else
661DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs)
662{
663# if RT_INLINE_ASM_GNU_STYLE
664 int rc = VINF_SUCCESS;
665 __asm__ __volatile__ (
666 "push %3 \n\t"
667 "push %2 \n\t"
668 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
669 "jnc 1f \n\t"
670 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
671 "1: \n\t"
672 "add $8, %%esp \n\t"
673 :"=rm"(rc)
674 :"0"(VINF_SUCCESS),
675 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
676 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */
677 :"memory"
678 );
679 return rc;
680
681# elif VMX_USE_MSC_INTRINSICS
682 unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs);
683 if (RT_LIKELY(rcMsc == 0))
684 return VINF_SUCCESS;
685 return VERR_VMX_INVALID_VMCS_PTR;
686
687# else
688 int rc = VINF_SUCCESS;
689 __asm
690 {
691 push dword ptr [HCPhysVmcs + 4]
692 push dword ptr [HCPhysVmcs]
693 _emit 0x66
694 _emit 0x0f
695 _emit 0xc7
696 _emit 0x34
697 _emit 0x24 /* VMCLEAR [esp] */
698 jnc success
699 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
700success:
701 add esp, 8
702 }
703 return rc;
704# endif
705}
706#endif
707#endif
708
709
710/**
711 * Executes VMPTRLD.
712 *
713 * @returns VBox status code.
714 * @param HCPhysVmcs Physical address of VMCS structure.
715 */
716#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
717DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs);
718#else
719DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs)
720{
721# if VMX_USE_MSC_INTRINSICS
722 unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs);
723 if (RT_LIKELY(rcMsc == 0))
724 return VINF_SUCCESS;
725 return VERR_VMX_INVALID_VMCS_PTR;
726
727# elif RT_INLINE_ASM_GNU_STYLE
728# ifdef RT_ARCH_AMD64
729 int rc;
730 __asm__ __volatile__ (
731 "pushq %2 \n\t"
732 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
733 "jnc 1f \n\t"
734 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
735 "1: \n\t"
736 "add $8, %%rsp \n\t"
737 :"=rm"(rc)
738 :"0"(VINF_SUCCESS),
739 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
740 /* this will not work with -fomit-frame-pointer */
741 :"memory"
742 );
743 return rc;
744# else
745 int rc;
746 __asm__ __volatile__ (
747 "push %3 \n\t"
748 "push %2 \n\t"
749 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
750 "jnc 1f \n\t"
751 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
752 "1: \n\t"
753 "add $8, %%esp \n\t"
754 :"=rm"(rc)
755 :"0"(VINF_SUCCESS),
756 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
757 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */
758 :"memory"
759 );
760 return rc;
761# endif
762
763# elif defined(RT_ARCH_X86)
764 int rc = VINF_SUCCESS;
765 __asm
766 {
767 push dword ptr [HCPhysVmcs + 4]
768 push dword ptr [HCPhysVmcs]
769 _emit 0x0f
770 _emit 0xc7
771 _emit 0x34
772 _emit 0x24 /* VMPTRLD [esp] */
773 jnc success
774 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
775success:
776 add esp, 8
777 }
778 return rc;
779
780# else
781# error "Shouldn't be here..."
782# endif
783}
784#endif
785
786#if 0
787#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
788DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs);
789#else
790DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs)
791{
792# if RT_INLINE_ASM_GNU_STYLE
793 int rc = VINF_SUCCESS;
794 __asm__ __volatile__ (
795 "push %3 \n\t"
796 "push %2 \n\t"
797 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
798 "jnc 1f \n\t"
799 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
800 "1: \n\t"
801 "add $8, %%esp \n\t"
802 :"=rm"(rc)
803 :"0"(VINF_SUCCESS),
804 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
805 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */
806 );
807 return rc;
808
809# elif VMX_USE_MSC_INTRINSICS
810 unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs);
811 if (RT_LIKELY(rcMsc == 0))
812 return VINF_SUCCESS;
813 return VERR_VMX_INVALID_VMCS_PTR;
814
815# else
816 int rc = VINF_SUCCESS;
817 __asm
818 {
819 push dword ptr [HCPhysVmcs + 4]
820 push dword ptr [HCPhysVmcs]
821 _emit 0x0f
822 _emit 0xc7
823 _emit 0x34
824 _emit 0x24 /* VMPTRLD [esp] */
825 jnc success
826 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
827
828success:
829 add esp, 8
830 }
831 return rc;
832# endif
833}
834#endif
835#endif
836
837
838/**
839 * Executes VMPTRST.
840 *
841 * @returns VBox status code.
842 * @param pHCPhysVmcs Where to store the physical address of the current
843 * VMCS.
844 */
845DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs);
846
847
848/**
849 * Executes VMWRITE for a 32-bit field.
850 *
851 * @returns VBox status code.
852 * @retval VINF_SUCCESS.
853 * @retval VERR_VMX_INVALID_VMCS_PTR.
854 * @retval VERR_VMX_INVALID_VMCS_FIELD.
855 *
856 * @param uFieldEnc VMCS field encoding.
857 * @param u32Val The 32-bit value to set.
858 *
859 * @remarks The values of the two status codes can be OR'ed together, the result
860 * will be VERR_VMX_INVALID_VMCS_PTR.
861 */
862#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
863DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val);
864#else
865DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val)
866{
867# if VMX_USE_MSC_INTRINSICS
868# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
869 __vmx_vmwrite(uFieldEnc, u32Val);
870 return VINF_SUCCESS;
871# else
872 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val);
873 if (RT_LIKELY(rcMsc == 0))
874 return VINF_SUCCESS;
875 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
876# endif
877
878# elif RT_INLINE_ASM_GNU_STYLE
879# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
880 __asm__ __volatile__ (
881 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
882 :
883 :"a"(uFieldEnc),
884 "d"(u32Val)
885 );
886 return VINF_SUCCESS;
887# else
888 int rc;
889 __asm__ __volatile__ (
890 ".byte 0x0f, 0x79, 0xc2 # VMWRITE 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 :"=rm"(rc)
899 :"0"(VINF_SUCCESS),
900 "a"(uFieldEnc),
901 "d"(u32Val)
902 );
903 return rc;
904# endif
905
906# elif defined(RT_ARCH_X86)
907 int rc = VINF_SUCCESS;
908 __asm
909 {
910 push dword ptr [u32Val]
911 mov eax, [uFieldEnc]
912 _emit 0x0f
913 _emit 0x79
914 _emit 0x04
915 _emit 0x24 /* VMWRITE eax, [esp] */
916 jnc valid_vmcs
917 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
918 jmp the_end
919valid_vmcs:
920 jnz the_end
921 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
922the_end:
923 add esp, 4
924 }
925 return rc;
926
927# else
928# error "Shouldn't be here..."
929# endif
930}
931#endif
932
933
934#if 0
935#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
936DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val);
937#else
938DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val)
939{
940# if RT_INLINE_ASM_GNU_STYLE
941 int rc = VINF_SUCCESS;
942 __asm__ __volatile__ (
943 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
944 "ja 2f \n\t"
945 "je 1f \n\t"
946 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
947 "jmp 2f \n\t"
948 "1: \n\t"
949 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
950 "2: \n\t"
951 :"=rm"(rc)
952 :"0"(VINF_SUCCESS),
953 "a"(uFieldEnc),
954 "d"(u32Val)
955 );
956 return rc;
957
958# elif VMX_USE_MSC_INTRINSICS
959 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val);
960 if (RT_LIKELY(rcMsc == 0))
961 return VINF_SUCCESS;
962 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
963
964#else
965 int rc = VINF_SUCCESS;
966 __asm
967 {
968 push dword ptr [u32Val]
969 mov eax, [uFieldEnc]
970 _emit 0x0f
971 _emit 0x79
972 _emit 0x04
973 _emit 0x24 /* VMWRITE eax, [esp] */
974 jnc valid_vmcs
975 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
976 jmp the_end
977
978valid_vmcs:
979 jnz the_end
980 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
981the_end:
982 add esp, 4
983 }
984 return rc;
985# endif
986}
987#endif
988#endif
989
990
991/**
992 * Executes VMWRITE for a 64-bit field.
993 *
994 * @returns VBox status code.
995 * @retval VINF_SUCCESS.
996 * @retval VERR_VMX_INVALID_VMCS_PTR.
997 * @retval VERR_VMX_INVALID_VMCS_FIELD.
998 *
999 * @param uFieldEnc The VMCS field encoding.
1000 * @param u64Val The 16, 32 or 64-bit value to set.
1001 *
1002 * @remarks The values of the two status codes can be OR'ed together, the result
1003 * will be VERR_VMX_INVALID_VMCS_PTR.
1004 */
1005#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
1006DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val);
1007#else
1008DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val)
1009{
1010# if VMX_USE_MSC_INTRINSICS
1011# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1012 __vmx_vmwrite(uFieldEnc, u64Val);
1013 return VINF_SUCCESS;
1014# else
1015 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val);
1016 if (RT_LIKELY(rcMsc == 0))
1017 return VINF_SUCCESS;
1018 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1019# endif
1020
1021# elif RT_INLINE_ASM_GNU_STYLE
1022# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1023 __asm__ __volatile__ (
1024 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
1025 :
1026 :"a"(uFieldEnc),
1027 "d"(u64Val)
1028 );
1029 return VINF_SUCCESS;
1030# else
1031 int rc;
1032 __asm__ __volatile__ (
1033 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
1034 "ja 2f \n\t"
1035 "je 1f \n\t"
1036 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
1037 "jmp 2f \n\t"
1038 "1: \n\t"
1039 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
1040 "2: \n\t"
1041 :"=rm"(rc)
1042 :"0"(VINF_SUCCESS),
1043 "a"(uFieldEnc),
1044 "d"(u64Val)
1045 );
1046 return rc;
1047# endif
1048
1049# else
1050# error "Shouldn't be here..."
1051# endif
1052}
1053#endif
1054
1055
1056#if 0
1057#if (defined(RT_ARCH_AMD64) && VMX_USE_MSC_INTRINSICS)
1058DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val)
1059{
1060 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val);
1061 if (RT_LIKELY(rcMsc == 0))
1062 return VINF_SUCCESS;
1063 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1064}
1065#else
1066DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val);
1067#endif
1068#endif
1069
1070
1071/**
1072 * Executes VMWRITE for a 16-bit VMCS field.
1073 *
1074 * @returns VBox status code.
1075 * @retval VINF_SUCCESS.
1076 * @retval VERR_VMX_INVALID_VMCS_PTR.
1077 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1078 *
1079 * @param uVmcsField The VMCS field.
1080 * @param u16Val The 16-bit value to set.
1081 *
1082 * @remarks The values of the two status codes can be OR'ed together, the result
1083 * will be VERR_VMX_INVALID_VMCS_PTR.
1084 */
1085DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val)
1086{
1087 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
1088 return VMXWriteVmcs32(uVmcsField, u16Val);
1089}
1090
1091
1092/**
1093 * Executes VMWRITE for a natural-width VMCS field.
1094 */
1095#ifdef RT_ARCH_AMD64
1096# define VMXWriteVmcsNw VMXWriteVmcs64
1097#else
1098# define VMXWriteVmcsNw VMXWriteVmcs32
1099#endif
1100
1101
1102/**
1103 * Invalidate a page using INVEPT.
1104 *
1105 * @returns VBox status code.
1106 * @param enmFlush Type of flush.
1107 * @param pDescriptor Pointer to the descriptor.
1108 */
1109DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor);
1110
1111
1112/**
1113 * Invalidate a page using INVVPID.
1114 *
1115 * @returns VBox status code.
1116 * @param enmFlush Type of flush.
1117 * @param pDescriptor Pointer to the descriptor.
1118 */
1119DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor);
1120
1121
1122/**
1123 * Executes VMREAD for a 32-bit field.
1124 *
1125 * @returns VBox status code.
1126 * @retval VINF_SUCCESS.
1127 * @retval VERR_VMX_INVALID_VMCS_PTR.
1128 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1129 *
1130 * @param uFieldEnc The VMCS field encoding.
1131 * @param pData Where to store VMCS field value.
1132 *
1133 * @remarks The values of the two status codes can be OR'ed together, the result
1134 * will be VERR_VMX_INVALID_VMCS_PTR.
1135 */
1136#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
1137DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData);
1138#else
1139DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData)
1140{
1141# if VMX_USE_MSC_INTRINSICS
1142# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1143 uint64_t u64Tmp = 0;
1144 __vmx_vmread(uFieldEnc, &u64Tmp);
1145 *pData = (uint32_t)u64Tmp;
1146 return VINF_SUCCESS;
1147# else
1148 unsigned char rcMsc;
1149 uint64_t u64Tmp;
1150 rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp);
1151 *pData = (uint32_t)u64Tmp;
1152 if (RT_LIKELY(rcMsc == 0))
1153 return VINF_SUCCESS;
1154 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1155# endif
1156
1157# elif RT_INLINE_ASM_GNU_STYLE
1158# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1159 __asm__ __volatile__ (
1160 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1161 :"=d"(*pData)
1162 :"a"(uFieldEnc),
1163 "d"(0)
1164 );
1165 return VINF_SUCCESS;
1166# else
1167 int rc;
1168 __asm__ __volatile__ (
1169 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
1170 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1171 "ja 2f \n\t"
1172 "je 1f \n\t"
1173 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
1174 "jmp 2f \n\t"
1175 "1: \n\t"
1176 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
1177 "2: \n\t"
1178 :"=&r"(rc),
1179 "=d"(*pData)
1180 :"a"(uFieldEnc),
1181 "d"(0)
1182 );
1183 return rc;
1184# endif
1185
1186# elif defined(RT_ARCH_X86)
1187 int rc = VINF_SUCCESS;
1188 __asm
1189 {
1190 sub esp, 4
1191 mov dword ptr [esp], 0
1192 mov eax, [uFieldEnc]
1193 _emit 0x0f
1194 _emit 0x78
1195 _emit 0x04
1196 _emit 0x24 /* VMREAD eax, [esp] */
1197 mov edx, pData
1198 pop dword ptr [edx]
1199 jnc valid_vmcs
1200 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
1201 jmp the_end
1202valid_vmcs:
1203 jnz the_end
1204 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
1205the_end:
1206 }
1207 return rc;
1208
1209# else
1210# error "Shouldn't be here..."
1211# endif
1212}
1213#endif
1214
1215#if 0
1216#if ((RT_INLINE_ASM_EXTERNAL || !defined(RT_ARCH_X86)) && !VMX_USE_MSC_INTRINSICS)
1217DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData);
1218#else
1219DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData)
1220{
1221# if RT_INLINE_ASM_GNU_STYLE
1222 int rc = VINF_SUCCESS;
1223 __asm__ __volatile__ (
1224 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
1225 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1226 "ja 2f \n\t"
1227 "je 1f \n\t"
1228 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
1229 "jmp 2f \n\t"
1230 "1: \n\t"
1231 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
1232 "2: \n\t"
1233 :"=&r"(rc),
1234 "=d"(*pData)
1235 :"a"(uFieldEnc),
1236 "d"(0)
1237 );
1238 return rc;
1239
1240# elif VMX_USE_MSC_INTRINSICS
1241 unsigned char rcMsc;
1242# ifdef RT_ARCH_X86
1243 rcMsc = __vmx_vmread(uFieldEnc, pData);
1244# else
1245 uint64_t u64Tmp;
1246 rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp);
1247 *pData = (uint32_t)u64Tmp;
1248# endif
1249 if (RT_LIKELY(rcMsc == 0))
1250 return VINF_SUCCESS;
1251 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1252
1253#else
1254 int rc = VINF_SUCCESS;
1255 __asm
1256 {
1257 sub esp, 4
1258 mov dword ptr [esp], 0
1259 mov eax, [uFieldEnc]
1260 _emit 0x0f
1261 _emit 0x78
1262 _emit 0x04
1263 _emit 0x24 /* VMREAD eax, [esp] */
1264 mov edx, pData
1265 pop dword ptr [edx]
1266 jnc valid_vmcs
1267 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
1268 jmp the_end
1269
1270valid_vmcs:
1271 jnz the_end
1272 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
1273the_end:
1274 }
1275 return rc;
1276# endif
1277}
1278#endif
1279#endif
1280
1281
1282/**
1283 * Executes VMREAD for a 64-bit field.
1284 *
1285 * @returns VBox status code.
1286 * @retval VINF_SUCCESS.
1287 * @retval VERR_VMX_INVALID_VMCS_PTR.
1288 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1289 *
1290 * @param uFieldEnc The VMCS field encoding.
1291 * @param pData Where to store VMCS field value.
1292 *
1293 * @remarks The values of the two status codes can be OR'ed together, the result
1294 * will be VERR_VMX_INVALID_VMCS_PTR.
1295 */
1296#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
1297DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData);
1298#else
1299DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData)
1300{
1301# if VMX_USE_MSC_INTRINSICS
1302# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1303 __vmx_vmread(uFieldEnc, pData);
1304 return VINF_SUCCESS;
1305# else
1306 unsigned char rcMsc;
1307 rcMsc = __vmx_vmread(uFieldEnc, pData);
1308 if (RT_LIKELY(rcMsc == 0))
1309 return VINF_SUCCESS;
1310 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1311# endif
1312
1313# elif RT_INLINE_ASM_GNU_STYLE
1314# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
1315 __asm__ __volatile__ (
1316 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1317 :"=d"(*pData)
1318 :"a"(uFieldEnc),
1319 "d"(0)
1320 );
1321 return VINF_SUCCESS;
1322# else
1323 int rc;
1324 __asm__ __volatile__ (
1325 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
1326 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
1327 "ja 2f \n\t"
1328 "je 1f \n\t"
1329 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
1330 "jmp 2f \n\t"
1331 "1: \n\t"
1332 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
1333 "2: \n\t"
1334 :"=&r"(rc),
1335 "=d"(*pData)
1336 :"a"(uFieldEnc),
1337 "d"(0)
1338 );
1339 return rc;
1340# endif
1341# else
1342# error "Shouldn't be here..."
1343# endif
1344}
1345#endif
1346
1347
1348#if 0
1349#if (!defined(RT_ARCH_X86) && !VMX_USE_MSC_INTRINSICS)
1350DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData);
1351#else
1352DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData)
1353{
1354# if VMX_USE_MSC_INTRINSICS
1355 unsigned char rcMsc;
1356# ifdef RT_ARCH_X86
1357 size_t uLow;
1358 size_t uHigh;
1359 rcMsc = __vmx_vmread(uFieldEnc, &uLow);
1360 rcMsc |= __vmx_vmread(uFieldEnc + 1, &uHigh);
1361 *pData = RT_MAKE_U64(uLow, uHigh);
1362# else
1363 rcMsc = __vmx_vmread(uFieldEnc, pData);
1364# endif
1365 if (RT_LIKELY(rcMsc == 0))
1366 return VINF_SUCCESS;
1367 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
1368
1369# elif defined(RT_ARCH_X86)
1370 int rc;
1371 uint32_t val_hi, val;
1372 rc = VMXReadVmcs32(uFieldEnc, &val);
1373 rc |= VMXReadVmcs32(uFieldEnc + 1, &val_hi);
1374 AssertRC(rc);
1375 *pData = RT_MAKE_U64(val, val_hi);
1376 return rc;
1377
1378# else
1379# error "Shouldn't be here..."
1380# endif
1381}
1382#endif
1383#endif
1384
1385
1386/**
1387 * Executes VMREAD for a 16-bit field.
1388 *
1389 * @returns VBox status code.
1390 * @retval VINF_SUCCESS.
1391 * @retval VERR_VMX_INVALID_VMCS_PTR.
1392 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1393 *
1394 * @param uVmcsField The VMCS field.
1395 * @param pData Where to store VMCS field value.
1396 *
1397 * @remarks The values of the two status codes can be OR'ed together, the result
1398 * will be VERR_VMX_INVALID_VMCS_PTR.
1399 */
1400DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData)
1401{
1402 uint32_t u32Tmp;
1403 int rc;
1404 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
1405 rc = VMXReadVmcs32(uVmcsField, &u32Tmp);
1406 *pData = (uint16_t)u32Tmp;
1407 return rc;
1408}
1409
1410
1411/**
1412 * Executes VMREAD for a natural-width VMCS field.
1413 */
1414#ifdef RT_ARCH_AMD64
1415# define VMXReadVmcsNw VMXReadVmcs64
1416#else
1417# define VMXReadVmcsNw VMXReadVmcs32
1418#endif
1419
1420#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
1421
1422/** @} */
1423
1424#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */
1425
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