VirtualBox

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

最後變更 在這個檔案從82968是 82968,由 vboxsync 提交於 5 年 前

Copyright year updates by scm.

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

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