VirtualBox

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

Last change on this file since 86620 was 84119, checked in by vboxsync, 5 years ago

hmvmxinline.h,stam.h: Use the intrin.h wrapper in iprt or we'll end up trying to drag in malloc.h when IPRT_NO_CRT is defined. bugref:8489

  • 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-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 >= 16 && 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 * Restores some host-state fields that need not be done on every VM-exit.
349 *
350 * @returns VBox status code.
351 * @param fRestoreHostFlags Flags of which host registers needs to be
352 * restored.
353 * @param pRestoreHost Pointer to the host-restore structure.
354 */
355DECLASM(int) VMXRestoreHostState(uint32_t fRestoreHostFlags, PVMXRESTOREHOST pRestoreHost);
356
357
358/**
359 * Dispatches an NMI to the host.
360 */
361DECLASM(int) VMXDispatchHostNmi(void);
362
363
364/**
365 * Executes VMXON.
366 *
367 * @returns VBox status code.
368 * @param HCPhysVmxOn Physical address of VMXON structure.
369 */
370#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
371DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn);
372#else
373DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn)
374{
375# if VMX_USE_MSC_INTRINSICS
376 unsigned char rcMsc = __vmx_on(&HCPhysVmxOn);
377 if (RT_LIKELY(rcMsc == 0))
378 return VINF_SUCCESS;
379 return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED;
380
381# elif RT_INLINE_ASM_GNU_STYLE
382# ifdef RT_ARCH_AMD64
383 int rc;
384 __asm__ __volatile__ (
385 "pushq %2 \n\t"
386 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
387 "ja 2f \n\t"
388 "je 1f \n\t"
389 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
390 "jmp 2f \n\t"
391 "1: \n\t"
392 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
393 "2: \n\t"
394 "add $8, %%rsp \n\t"
395 :"=rm"(rc)
396 :"0"(VINF_SUCCESS),
397 "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */
398 /* this would not work with -fomit-frame-pointer */
399 :"memory"
400 );
401 return rc;
402# else
403 int rc;
404 __asm__ __volatile__ (
405 "push %3 \n\t"
406 "push %2 \n\t"
407 ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t"
408 "ja 2f \n\t"
409 "je 1f \n\t"
410 "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
411 "jmp 2f \n\t"
412 "1: \n\t"
413 "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t"
414 "2: \n\t"
415 "add $8, %%esp \n\t"
416 :"=rm"(rc)
417 :"0"(VINF_SUCCESS),
418 "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */
419 "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */
420 :"memory"
421 );
422 return rc;
423# endif
424
425# elif defined(RT_ARCH_X86)
426 int rc = VINF_SUCCESS;
427 __asm
428 {
429 push dword ptr [HCPhysVmxOn + 4]
430 push dword ptr [HCPhysVmxOn]
431 _emit 0xf3
432 _emit 0x0f
433 _emit 0xc7
434 _emit 0x34
435 _emit 0x24 /* VMXON [esp] */
436 jnc vmxon_good
437 mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR
438 jmp the_end
439
440vmxon_good:
441 jnz the_end
442 mov dword ptr [rc], VERR_VMX_VMXON_FAILED
443the_end:
444 add esp, 8
445 }
446 return rc;
447
448# else
449# error "Shouldn't be here..."
450# endif
451}
452#endif
453
454
455/**
456 * Executes VMXOFF.
457 */
458#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
459DECLASM(void) VMXDisable(void);
460#else
461DECLINLINE(void) VMXDisable(void)
462{
463# if VMX_USE_MSC_INTRINSICS
464 __vmx_off();
465
466# elif RT_INLINE_ASM_GNU_STYLE
467 __asm__ __volatile__ (
468 ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t"
469 );
470
471# elif defined(RT_ARCH_X86)
472 __asm
473 {
474 _emit 0x0f
475 _emit 0x01
476 _emit 0xc4 /* VMXOFF */
477 }
478
479# else
480# error "Shouldn't be here..."
481# endif
482}
483#endif
484
485
486/**
487 * Executes VMCLEAR.
488 *
489 * @returns VBox status code.
490 * @param HCPhysVmcs Physical address of VM control structure.
491 */
492#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
493DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs);
494#else
495DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs)
496{
497# if VMX_USE_MSC_INTRINSICS
498 unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs);
499 if (RT_LIKELY(rcMsc == 0))
500 return VINF_SUCCESS;
501 return VERR_VMX_INVALID_VMCS_PTR;
502
503# elif RT_INLINE_ASM_GNU_STYLE
504# ifdef RT_ARCH_AMD64
505 int rc;
506 __asm__ __volatile__ (
507 "pushq %2 \n\t"
508 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
509 "jnc 1f \n\t"
510 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
511 "1: \n\t"
512 "add $8, %%rsp \n\t"
513 :"=rm"(rc)
514 :"0"(VINF_SUCCESS),
515 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
516 /* this would not work with -fomit-frame-pointer */
517 :"memory"
518 );
519 return rc;
520# else
521 int rc;
522 __asm__ __volatile__ (
523 "push %3 \n\t"
524 "push %2 \n\t"
525 ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
526 "jnc 1f \n\t"
527 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
528 "1: \n\t"
529 "add $8, %%esp \n\t"
530 :"=rm"(rc)
531 :"0"(VINF_SUCCESS),
532 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
533 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */
534 :"memory"
535 );
536 return rc;
537# endif
538
539# elif defined(RT_ARCH_X86)
540 int rc = VINF_SUCCESS;
541 __asm
542 {
543 push dword ptr [HCPhysVmcs + 4]
544 push dword ptr [HCPhysVmcs]
545 _emit 0x66
546 _emit 0x0f
547 _emit 0xc7
548 _emit 0x34
549 _emit 0x24 /* VMCLEAR [esp] */
550 jnc success
551 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
552success:
553 add esp, 8
554 }
555 return rc;
556
557# else
558# error "Shouldn't be here..."
559# endif
560}
561#endif
562
563
564/**
565 * Executes VMPTRLD.
566 *
567 * @returns VBox status code.
568 * @param HCPhysVmcs Physical address of VMCS structure.
569 */
570#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
571DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs);
572#else
573DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs)
574{
575# if VMX_USE_MSC_INTRINSICS
576 unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs);
577 if (RT_LIKELY(rcMsc == 0))
578 return VINF_SUCCESS;
579 return VERR_VMX_INVALID_VMCS_PTR;
580
581# elif RT_INLINE_ASM_GNU_STYLE
582# ifdef RT_ARCH_AMD64
583 int rc;
584 __asm__ __volatile__ (
585 "pushq %2 \n\t"
586 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
587 "jnc 1f \n\t"
588 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
589 "1: \n\t"
590 "add $8, %%rsp \n\t"
591 :"=rm"(rc)
592 :"0"(VINF_SUCCESS),
593 "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */
594 /* this will not work with -fomit-frame-pointer */
595 :"memory"
596 );
597 return rc;
598# else
599 int rc;
600 __asm__ __volatile__ (
601 "push %3 \n\t"
602 "push %2 \n\t"
603 ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
604 "jnc 1f \n\t"
605 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
606 "1: \n\t"
607 "add $8, %%esp \n\t"
608 :"=rm"(rc)
609 :"0"(VINF_SUCCESS),
610 "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */
611 "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */
612 :"memory"
613 );
614 return rc;
615# endif
616
617# elif defined(RT_ARCH_X86)
618 int rc = VINF_SUCCESS;
619 __asm
620 {
621 push dword ptr [HCPhysVmcs + 4]
622 push dword ptr [HCPhysVmcs]
623 _emit 0x0f
624 _emit 0xc7
625 _emit 0x34
626 _emit 0x24 /* VMPTRLD [esp] */
627 jnc success
628 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
629success:
630 add esp, 8
631 }
632 return rc;
633
634# else
635# error "Shouldn't be here..."
636# endif
637}
638#endif
639
640
641/**
642 * Executes VMPTRST.
643 *
644 * @returns VBox status code.
645 * @param pHCPhysVmcs Where to store the physical address of the current
646 * VMCS.
647 */
648DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs);
649
650
651/**
652 * Executes VMWRITE for a 32-bit field.
653 *
654 * @returns VBox status code.
655 * @retval VINF_SUCCESS.
656 * @retval VERR_VMX_INVALID_VMCS_PTR.
657 * @retval VERR_VMX_INVALID_VMCS_FIELD.
658 *
659 * @param uFieldEnc VMCS field encoding.
660 * @param u32Val The 32-bit value to set.
661 *
662 * @remarks The values of the two status codes can be OR'ed together, the result
663 * will be VERR_VMX_INVALID_VMCS_PTR.
664 */
665#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
666DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val);
667#else
668DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val)
669{
670# if VMX_USE_MSC_INTRINSICS
671# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
672 __vmx_vmwrite(uFieldEnc, u32Val);
673 return VINF_SUCCESS;
674# else
675 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val);
676 if (RT_LIKELY(rcMsc == 0))
677 return VINF_SUCCESS;
678 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
679# endif
680
681# elif RT_INLINE_ASM_GNU_STYLE
682# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
683 __asm__ __volatile__ (
684 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
685 :
686 :"a"(uFieldEnc),
687 "d"(u32Val)
688 );
689 return VINF_SUCCESS;
690# else
691 int rc;
692 __asm__ __volatile__ (
693 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
694 "ja 2f \n\t"
695 "je 1f \n\t"
696 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
697 "jmp 2f \n\t"
698 "1: \n\t"
699 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
700 "2: \n\t"
701 :"=rm"(rc)
702 :"0"(VINF_SUCCESS),
703 "a"(uFieldEnc),
704 "d"(u32Val)
705 );
706 return rc;
707# endif
708
709# elif defined(RT_ARCH_X86)
710 int rc = VINF_SUCCESS;
711 __asm
712 {
713 push dword ptr [u32Val]
714 mov eax, [uFieldEnc]
715 _emit 0x0f
716 _emit 0x79
717 _emit 0x04
718 _emit 0x24 /* VMWRITE eax, [esp] */
719 jnc valid_vmcs
720 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
721 jmp the_end
722valid_vmcs:
723 jnz the_end
724 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
725the_end:
726 add esp, 4
727 }
728 return rc;
729
730# else
731# error "Shouldn't be here..."
732# endif
733}
734#endif
735
736
737/**
738 * Executes VMWRITE for a 64-bit field.
739 *
740 * @returns VBox status code.
741 * @retval VINF_SUCCESS.
742 * @retval VERR_VMX_INVALID_VMCS_PTR.
743 * @retval VERR_VMX_INVALID_VMCS_FIELD.
744 *
745 * @param uFieldEnc The VMCS field encoding.
746 * @param u64Val The 16, 32 or 64-bit value to set.
747 *
748 * @remarks The values of the two status codes can be OR'ed together, the result
749 * will be VERR_VMX_INVALID_VMCS_PTR.
750 */
751#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
752DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val);
753#else
754DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val)
755{
756# if VMX_USE_MSC_INTRINSICS
757# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
758 __vmx_vmwrite(uFieldEnc, u64Val);
759 return VINF_SUCCESS;
760# else
761 unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val);
762 if (RT_LIKELY(rcMsc == 0))
763 return VINF_SUCCESS;
764 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
765# endif
766
767# elif RT_INLINE_ASM_GNU_STYLE
768# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
769 __asm__ __volatile__ (
770 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
771 :
772 :"a"(uFieldEnc),
773 "d"(u64Val)
774 );
775 return VINF_SUCCESS;
776# else
777 int rc;
778 __asm__ __volatile__ (
779 ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t"
780 "ja 2f \n\t"
781 "je 1f \n\t"
782 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
783 "jmp 2f \n\t"
784 "1: \n\t"
785 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
786 "2: \n\t"
787 :"=rm"(rc)
788 :"0"(VINF_SUCCESS),
789 "a"(uFieldEnc),
790 "d"(u64Val)
791 );
792 return rc;
793# endif
794
795# else
796# error "Shouldn't be here..."
797# endif
798}
799#endif
800
801
802/**
803 * Executes VMWRITE for a 16-bit VMCS field.
804 *
805 * @returns VBox status code.
806 * @retval VINF_SUCCESS.
807 * @retval VERR_VMX_INVALID_VMCS_PTR.
808 * @retval VERR_VMX_INVALID_VMCS_FIELD.
809 *
810 * @param uVmcsField The VMCS field.
811 * @param u16Val The 16-bit value to set.
812 *
813 * @remarks The values of the two status codes can be OR'ed together, the result
814 * will be VERR_VMX_INVALID_VMCS_PTR.
815 */
816DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val)
817{
818 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
819 return VMXWriteVmcs32(uVmcsField, u16Val);
820}
821
822
823/**
824 * Executes VMWRITE for a natural-width VMCS field.
825 */
826#ifdef RT_ARCH_AMD64
827# define VMXWriteVmcsNw VMXWriteVmcs64
828#else
829# define VMXWriteVmcsNw VMXWriteVmcs32
830#endif
831
832
833/**
834 * Invalidate a page using INVEPT.
835 *
836 * @returns VBox status code.
837 * @param enmFlush Type of flush.
838 * @param pDescriptor Pointer to the descriptor.
839 */
840DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor);
841
842
843/**
844 * Invalidate a page using INVVPID.
845 *
846 * @returns VBox status code.
847 * @param enmFlush Type of flush.
848 * @param pDescriptor Pointer to the descriptor.
849 */
850DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor);
851
852
853/**
854 * Executes VMREAD for a 32-bit field.
855 *
856 * @returns VBox status code.
857 * @retval VINF_SUCCESS.
858 * @retval VERR_VMX_INVALID_VMCS_PTR.
859 * @retval VERR_VMX_INVALID_VMCS_FIELD.
860 *
861 * @param uFieldEnc The VMCS field encoding.
862 * @param pData Where to store VMCS field value.
863 *
864 * @remarks The values of the two status codes can be OR'ed together, the result
865 * will be VERR_VMX_INVALID_VMCS_PTR.
866 */
867#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS
868DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData);
869#else
870DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData)
871{
872# if VMX_USE_MSC_INTRINSICS
873# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
874 uint64_t u64Tmp = 0;
875 __vmx_vmread(uFieldEnc, &u64Tmp);
876 *pData = (uint32_t)u64Tmp;
877 return VINF_SUCCESS;
878# else
879 unsigned char rcMsc;
880 uint64_t u64Tmp;
881 rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp);
882 *pData = (uint32_t)u64Tmp;
883 if (RT_LIKELY(rcMsc == 0))
884 return VINF_SUCCESS;
885 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
886# endif
887
888# elif RT_INLINE_ASM_GNU_STYLE
889# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
890 __asm__ __volatile__ (
891 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
892 :"=d"(*pData)
893 :"a"(uFieldEnc),
894 "d"(0)
895 );
896 return VINF_SUCCESS;
897# else
898 int rc;
899 __asm__ __volatile__ (
900 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
901 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
902 "ja 2f \n\t"
903 "je 1f \n\t"
904 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
905 "jmp 2f \n\t"
906 "1: \n\t"
907 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
908 "2: \n\t"
909 :"=&r"(rc),
910 "=d"(*pData)
911 :"a"(uFieldEnc),
912 "d"(0)
913 );
914 return rc;
915# endif
916
917# elif defined(RT_ARCH_X86)
918 int rc = VINF_SUCCESS;
919 __asm
920 {
921 sub esp, 4
922 mov dword ptr [esp], 0
923 mov eax, [uFieldEnc]
924 _emit 0x0f
925 _emit 0x78
926 _emit 0x04
927 _emit 0x24 /* VMREAD eax, [esp] */
928 mov edx, pData
929 pop dword ptr [edx]
930 jnc valid_vmcs
931 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR
932 jmp the_end
933valid_vmcs:
934 jnz the_end
935 mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD
936the_end:
937 }
938 return rc;
939
940# else
941# error "Shouldn't be here..."
942# endif
943}
944#endif
945
946
947/**
948 * Executes VMREAD for a 64-bit field.
949 *
950 * @returns VBox status code.
951 * @retval VINF_SUCCESS.
952 * @retval VERR_VMX_INVALID_VMCS_PTR.
953 * @retval VERR_VMX_INVALID_VMCS_FIELD.
954 *
955 * @param uFieldEnc The VMCS field encoding.
956 * @param pData Where to store VMCS field value.
957 *
958 * @remarks The values of the two status codes can be OR'ed together, the result
959 * will be VERR_VMX_INVALID_VMCS_PTR.
960 */
961#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS)
962DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData);
963#else
964DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData)
965{
966# if VMX_USE_MSC_INTRINSICS
967# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
968 __vmx_vmread(uFieldEnc, pData);
969 return VINF_SUCCESS;
970# else
971 unsigned char rcMsc;
972 rcMsc = __vmx_vmread(uFieldEnc, pData);
973 if (RT_LIKELY(rcMsc == 0))
974 return VINF_SUCCESS;
975 return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD;
976# endif
977
978# elif RT_INLINE_ASM_GNU_STYLE
979# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK
980 __asm__ __volatile__ (
981 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
982 :"=d"(*pData)
983 :"a"(uFieldEnc),
984 "d"(0)
985 );
986 return VINF_SUCCESS;
987# else
988 int rc;
989 __asm__ __volatile__ (
990 "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t"
991 ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t"
992 "ja 2f \n\t"
993 "je 1f \n\t"
994 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
995 "jmp 2f \n\t"
996 "1: \n\t"
997 "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
998 "2: \n\t"
999 :"=&r"(rc),
1000 "=d"(*pData)
1001 :"a"(uFieldEnc),
1002 "d"(0)
1003 );
1004 return rc;
1005# endif
1006# else
1007# error "Shouldn't be here..."
1008# endif
1009}
1010#endif
1011
1012
1013/**
1014 * Executes VMREAD for a 16-bit field.
1015 *
1016 * @returns VBox status code.
1017 * @retval VINF_SUCCESS.
1018 * @retval VERR_VMX_INVALID_VMCS_PTR.
1019 * @retval VERR_VMX_INVALID_VMCS_FIELD.
1020 *
1021 * @param uVmcsField The VMCS field.
1022 * @param pData Where to store VMCS field value.
1023 *
1024 * @remarks The values of the two status codes can be OR'ed together, the result
1025 * will be VERR_VMX_INVALID_VMCS_PTR.
1026 */
1027DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData)
1028{
1029 uint32_t u32Tmp;
1030 int rc;
1031 AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField));
1032 rc = VMXReadVmcs32(uVmcsField, &u32Tmp);
1033 *pData = (uint16_t)u32Tmp;
1034 return rc;
1035}
1036
1037
1038/**
1039 * Executes VMREAD for a natural-width VMCS field.
1040 */
1041#ifdef RT_ARCH_AMD64
1042# define VMXReadVmcsNw VMXReadVmcs64
1043#else
1044# define VMXReadVmcsNw VMXReadVmcs32
1045#endif
1046
1047#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */
1048
1049/** @} */
1050
1051#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */
1052
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