summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/NEMInternal.h
blob: e0817e219ce2856e573b1f1ec5d6c18e2a965adb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
/* $Id: NEMInternal.h $ */
/** @file
 * NEM - Internal header file.
 */

/*
 * Copyright (C) 2018-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * SPDX-License-Identifier: GPL-3.0-only
 */

#ifndef VMM_INCLUDED_SRC_include_NEMInternal_h
#define VMM_INCLUDED_SRC_include_NEMInternal_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <VBox/cdefs.h>
#include <VBox/types.h>
#include <VBox/vmm/nem.h>
#include <VBox/vmm/cpum.h> /* For CPUMCPUVENDOR. */
#include <VBox/vmm/stam.h>
#include <VBox/vmm/vmapi.h>
#ifdef RT_OS_WINDOWS
#include <iprt/nt/hyperv.h>
#include <iprt/critsect.h>
#elif defined(RT_OS_DARWIN)
# include "VMXInternal.h"
#endif

RT_C_DECLS_BEGIN


/** @defgroup grp_nem_int      Internal
 * @ingroup grp_nem
 * @internal
 * @{
 */

#if defined(VBOX_WITH_NATIVE_NEM) && !defined(VBOX_WITH_PGM_NEM_MODE)
# error "VBOX_WITH_NATIVE_NEM requires VBOX_WITH_PGM_NEM_MODE to be defined"
#endif


#ifdef RT_OS_WINDOWS
/*
 * Windows: Code configuration.
 */
/* nothing at the moment */

/**
 * Windows VID I/O control information.
 */
typedef struct NEMWINIOCTL
{
    /** The I/O control function number. */
    uint32_t    uFunction;
    uint32_t    cbInput;
    uint32_t    cbOutput;
} NEMWINIOCTL;

/** @name Windows: Our two-bit physical page state for PGMPAGE
 * @{ */
# define NEM_WIN_PAGE_STATE_NOT_SET     0
# define NEM_WIN_PAGE_STATE_UNMAPPED    1
# define NEM_WIN_PAGE_STATE_READABLE    2
# define NEM_WIN_PAGE_STATE_WRITABLE    3
/** @} */

/** Windows: Checks if a_GCPhys is subject to the limited A20 gate emulation. */
# define NEM_WIN_IS_SUBJECT_TO_A20(a_GCPhys)    ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K)
/** Windows: Checks if a_GCPhys is relevant to the limited A20 gate emulation. */
# define NEM_WIN_IS_RELEVANT_TO_A20(a_GCPhys)    \
    ( ((RTGCPHYS)((a_GCPhys) - _1M) < (RTGCPHYS)_64K) || ((RTGCPHYS)(a_GCPhys) < (RTGCPHYS)_64K) )

/** The CPUMCTX_EXTRN_XXX mask for IEM. */
# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM      (  IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_INHIBIT_INT \
                                                  | CPUMCTX_EXTRN_INHIBIT_NMI )
/** The CPUMCTX_EXTRN_XXX mask for IEM when raising exceptions. */
# define NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM_XCPT (IEM_CPUMCTX_EXTRN_XCPT_MASK | NEM_WIN_CPUMCTX_EXTRN_MASK_FOR_IEM)

/** @name Windows: Interrupt window flags (NEM_WIN_INTW_F_XXX).
 * @{  */
# define NEM_WIN_INTW_F_NMI             UINT8_C(0x01)
# define NEM_WIN_INTW_F_REGULAR         UINT8_C(0x02)
# define NEM_WIN_INTW_F_PRIO_MASK       UINT8_C(0x3c)
# define NEM_WIN_INTW_F_PRIO_SHIFT      2
/** @} */

#endif /* RT_OS_WINDOWS */


#ifdef RT_OS_DARWIN
/** vCPU ID declaration to avoid dragging in HV headers here. */
typedef unsigned hv_vcpuid_t;
/** The HV VM memory space ID (ASID). */
typedef unsigned hv_vm_space_t;


/** @name Darwin: Our two-bit physical page state for PGMPAGE
 * @{ */
# define NEM_DARWIN_PAGE_STATE_UNMAPPED    0
# define NEM_DARWIN_PAGE_STATE_RX          1
# define NEM_DARWIN_PAGE_STATE_RW          2
# define NEM_DARWIN_PAGE_STATE_RWX         3
/** @} */

/** The CPUMCTX_EXTRN_XXX mask for IEM. */
# define NEM_DARWIN_CPUMCTX_EXTRN_MASK_FOR_IEM      (  IEM_CPUMCTX_EXTRN_MUST_MASK | CPUMCTX_EXTRN_INHIBIT_INT \
                                                     | CPUMCTX_EXTRN_INHIBIT_NMI )
/** The CPUMCTX_EXTRN_XXX mask for IEM when raising exceptions. */
# define NEM_DARWIN_CPUMCTX_EXTRN_MASK_FOR_IEM_XCPT (IEM_CPUMCTX_EXTRN_XCPT_MASK | NEM_DARWIN_CPUMCTX_EXTRN_MASK_FOR_IEM)

#endif


/** Trick to make slickedit see the static functions in the template. */
#ifndef IN_SLICKEDIT
# define NEM_TMPL_STATIC static
#else
# define NEM_TMPL_STATIC
#endif


/**
 * Generic NEM exit type enumeration for use with EMHistoryAddExit.
 *
 * On windows we've got two different set of exit types and they are both jumping
 * around the place value wise, so EM can use their values.
 *
 * @note We only have exit types for exits not covered by EM here.
 */
typedef enum NEMEXITTYPE
{
    NEMEXITTYPE_INVALID = 0,

    /* Common: */
    NEMEXITTYPE_INTTERRUPT_WINDOW,
    NEMEXITTYPE_HALT,

    /* Windows: */
    NEMEXITTYPE_UNRECOVERABLE_EXCEPTION,
    NEMEXITTYPE_INVALID_VP_REGISTER_VALUE,
    NEMEXITTYPE_XCPT_UD,
    NEMEXITTYPE_XCPT_DB,
    NEMEXITTYPE_XCPT_BP,
    NEMEXITTYPE_CANCELED,
    NEMEXITTYPE_MEMORY_ACCESS,

    /* Linux: */
    NEMEXITTYPE_INTERNAL_ERROR_EMULATION,
    NEMEXITTYPE_INTERNAL_ERROR_FATAL,
    NEMEXITTYPE_INTERRUPTED,
    NEMEXITTYPE_FAILED_ENTRY,

    /* End of valid types. */
    NEMEXITTYPE_END
} NEMEXITTYPE;


/**
 * NEM VM Instance data.
 */
typedef struct NEM
{
    /** NEM_MAGIC. */
    uint32_t                    u32Magic;

    /** Set if enabled. */
    bool                        fEnabled;
    /** Set if long mode guests are allowed. */
    bool                        fAllow64BitGuests;
    /** Set when the debug facility has breakpoints/events enabled that requires
     *  us to use the debug execution loop. */
    bool                        fUseDebugLoop;

#if defined(RT_OS_LINUX)
    /** The '/dev/kvm' file descriptor.   */
    int32_t                     fdKvm;
    /** The KVM_CREATE_VM file descriptor. */
    int32_t                     fdVm;

    /** KVM_GET_VCPU_MMAP_SIZE. */
    uint32_t                    cbVCpuMmap;
    /** KVM_CAP_NR_MEMSLOTS. */
    uint32_t                    cMaxMemSlots;
    /** KVM_CAP_X86_ROBUST_SINGLESTEP. */
    bool                        fRobustSingleStep;

    /** Hint where there might be a free slot. */
    uint16_t                    idPrevSlot;
    /** Memory slot ID allocation bitmap. */
    uint64_t                    bmSlotIds[_32K / 8 / sizeof(uint64_t)];

#elif defined(RT_OS_WINDOWS)
    /** Set if we've created the EMTs. */
    bool                        fCreatedEmts : 1;
    /** WHvRunVpExitReasonX64Cpuid is supported. */
    bool                        fExtendedMsrExit : 1;
    /** WHvRunVpExitReasonX64MsrAccess is supported. */
    bool                        fExtendedCpuIdExit : 1;
    /** WHvRunVpExitReasonException is supported. */
    bool                        fExtendedXcptExit : 1;
# ifdef NEM_WIN_WITH_A20
    /** Set if we've started more than one CPU and cannot mess with A20. */
    bool                        fA20Fixed : 1;
    /** Set if A20 is enabled. */
    bool                        fA20Enabled : 1;
# endif
    /** The reported CPU vendor.   */
    CPUMCPUVENDOR               enmCpuVendor;
    /** Cache line flush size as a power of two. */
    uint8_t                     cCacheLineFlushShift;
    /** The result of WHvCapabilityCodeProcessorFeatures. */
    union
    {
        /** 64-bit view. */
        uint64_t                u64;
# ifdef _WINHVAPIDEFS_H_
        /** Interpreed features. */
        WHV_PROCESSOR_FEATURES  u;
# endif
    } uCpuFeatures;

    /** The partition handle. */
# ifdef _WINHVAPIDEFS_H_
    WHV_PARTITION_HANDLE
# else
    RTHCUINTPTR
# endif
                                hPartition;
    /** The device handle for the partition, for use with Vid APIs or direct I/O
     * controls. */
    RTR3PTR                     hPartitionDevice;

    /** Number of currently mapped pages. */
    uint32_t volatile           cMappedPages;
    uint32_t                    u32Padding;
    STAMCOUNTER                 StatMapPage;
    STAMCOUNTER                 StatUnmapPage;
    STAMCOUNTER                 StatMapPageFailed;
    STAMCOUNTER                 StatUnmapPageFailed;
    STAMPROFILE                 StatProfMapGpaRange;
    STAMPROFILE                 StatProfUnmapGpaRange;
    STAMPROFILE                 StatProfMapGpaRangePage;
    STAMPROFILE                 StatProfUnmapGpaRangePage;

    /** Statistics updated by NEMR0UpdateStatistics. */
    struct
    {
        uint64_t                cPagesAvailable;
        uint64_t                cPagesInUse;
    } R0Stats;

#elif defined(RT_OS_DARWIN)
    /** Set if we've created the EMTs. */
    bool                        fCreatedEmts : 1;
    /** Set if hv_vm_create() was called successfully. */
    bool                        fCreatedVm   : 1;
    /** Set if hv_vm_space_create() was called successfully. */
    bool                        fCreatedAsid : 1;
    /** Set if Last Branch Record (LBR) is enabled. */
    bool                        fLbr;
    /** The ASID for this VM (only valid if fCreatedAsid is true). */
    hv_vm_space_t               uVmAsid;
    /** Number of mach time units per NS, for hv_vcpu_run_until(). */
    uint64_t                    cMachTimePerNs;
    /** Pause-loop exiting (PLE) gap in ticks. */
    uint32_t                    cPleGapTicks;
    /** Pause-loop exiting (PLE) window in ticks. */
    uint32_t                    cPleWindowTicks;

    /** The host LBR TOS (top-of-stack) MSR id. */
    uint32_t                    idLbrTosMsr;
    /** The host LBR select MSR id. */
    uint32_t                    idLbrSelectMsr;
    /** The host last event record from IP MSR id. */
    uint32_t                    idLerFromIpMsr;
    /** The host last event record to IP MSR id. */
    uint32_t                    idLerToIpMsr;

    /** The first valid host LBR branch-from-IP stack range. */
    uint32_t                    idLbrFromIpMsrFirst;
    /** The last valid host LBR branch-from-IP stack range. */
    uint32_t                    idLbrFromIpMsrLast;

    /** The first valid host LBR branch-to-IP stack range. */
    uint32_t                    idLbrToIpMsrFirst;
    /** The last valid host LBR branch-to-IP stack range. */
    uint32_t                    idLbrToIpMsrLast;

    /** The first valid host LBR info stack range. */
    uint32_t                    idLbrInfoMsrFirst;
    /** The last valid host LBR info stack range. */
    uint32_t                    idLbrInfoMsrLast;

    STAMCOUNTER                 StatMapPage;
    STAMCOUNTER                 StatUnmapPage;
    STAMCOUNTER                 StatMapPageFailed;
    STAMCOUNTER                 StatUnmapPageFailed;
#endif /* RT_OS_WINDOWS */
} NEM;
/** Pointer to NEM VM instance data. */
typedef NEM *PNEM;

/** NEM::u32Magic value. */
#define NEM_MAGIC               UINT32_C(0x004d454e)
/** NEM::u32Magic value after termination. */
#define NEM_MAGIC_DEAD          UINT32_C(0xdead1111)


/**
 * NEM VMCPU Instance data.
 */
typedef struct NEMCPU
{
    /** NEMCPU_MAGIC. */
    uint32_t                    u32Magic;
    /** Whether \#UD needs to be intercepted and presented to GIM. */
    bool                        fGIMTrapXcptUD : 1;
    /** Whether \#GP needs to be intercept for mesa driver workaround. */
    bool                        fTrapXcptGpForLovelyMesaDrv: 1;
    /** Whether we should use the debug loop because of single stepping or special
     *  debug breakpoints / events are armed. */
    bool                        fUseDebugLoop : 1;
    /** Whether we're executing a single instruction. */
    bool                        fSingleInstruction : 1;
    /** Set if we using the debug loop and wish to intercept RDTSC. */
    bool                        fDebugWantRdTscExit : 1;
    /** Whether we are currently executing in the debug loop.
     *  Mainly for assertions. */
    bool                        fUsingDebugLoop : 1;
    /** Set if we need to clear the trap flag because of single stepping. */
    bool                        fClearTrapFlag : 1;
    /** Whether we're using the hyper DR7 or guest DR7. */
    bool                        fUsingHyperDR7 : 1;
    /** Whether \#DE needs to be intercepted for GIM. */
    bool                        fGCMTrapXcptDE : 1;

#if defined(RT_OS_LINUX)
    uint8_t                     abPadding[3];
    /** The KVM VCpu file descriptor. */
    int32_t                     fdVCpu;
    /** Pointer to the KVM_RUN data exchange region. */
    R3PTRTYPE(struct kvm_run *) pRun;
    /** The MSR_IA32_APICBASE value known to KVM. */
    uint64_t                    uKvmApicBase;

    /** @name Statistics
     * @{ */
    STAMCOUNTER                 StatExitTotal;
    STAMCOUNTER                 StatExitIo;
    STAMCOUNTER                 StatExitMmio;
    STAMCOUNTER                 StatExitSetTpr;
    STAMCOUNTER                 StatExitTprAccess;
    STAMCOUNTER                 StatExitRdMsr;
    STAMCOUNTER                 StatExitWrMsr;
    STAMCOUNTER                 StatExitIrqWindowOpen;
    STAMCOUNTER                 StatExitHalt;
    STAMCOUNTER                 StatExitIntr;
    STAMCOUNTER                 StatExitHypercall;
    STAMCOUNTER                 StatExitDebug;
    STAMCOUNTER                 StatExitBusLock;
    STAMCOUNTER                 StatExitInternalErrorEmulation;
    STAMCOUNTER                 StatExitInternalErrorFatal;
# if 0
    STAMCOUNTER                 StatExitCpuId;
    STAMCOUNTER                 StatExitUnrecoverable;
    STAMCOUNTER                 StatGetMsgTimeout;
    STAMCOUNTER                 StatStopCpuSuccess;
    STAMCOUNTER                 StatStopCpuPending;
    STAMCOUNTER                 StatStopCpuPendingAlerts;
    STAMCOUNTER                 StatStopCpuPendingOdd;
    STAMCOUNTER                 StatCancelChangedState;
    STAMCOUNTER                 StatCancelAlertedThread;
# endif
    STAMCOUNTER                 StatBreakOnCancel;
    STAMCOUNTER                 StatBreakOnFFPre;
    STAMCOUNTER                 StatBreakOnFFPost;
    STAMCOUNTER                 StatBreakOnStatus;
    STAMCOUNTER                 StatFlushExitOnReturn;
    STAMCOUNTER                 StatFlushExitOnReturn1Loop;
    STAMCOUNTER                 StatFlushExitOnReturn2Loops;
    STAMCOUNTER                 StatFlushExitOnReturn3Loops;
    STAMCOUNTER                 StatFlushExitOnReturn4PlusLoops;
    STAMCOUNTER                 StatImportOnDemand;
    STAMCOUNTER                 StatImportOnReturn;
    STAMCOUNTER                 StatImportOnReturnSkipped;
    STAMCOUNTER                 StatImportPendingInterrupt;
    STAMCOUNTER                 StatExportPendingInterrupt;
    STAMCOUNTER                 StatQueryCpuTick;
    /** @} */


#elif defined(RT_OS_WINDOWS)
    /** The current state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
    uint8_t                     fCurrentInterruptWindows;
    /** The desired state of the interrupt windows (NEM_WIN_INTW_F_XXX). */
    uint8_t                     fDesiredInterruptWindows;
    /** Last copy of HV_X64_VP_EXECUTION_STATE::InterruptShadow. */
    bool                        fLastInterruptShadow : 1;
    uint32_t                    uPadding;
    /** The VID_MSHAGN_F_XXX flags.
     * Either VID_MSHAGN_F_HANDLE_MESSAGE | VID_MSHAGN_F_GET_NEXT_MESSAGE or zero. */
    uint32_t                    fHandleAndGetFlags;
    /** What VidMessageSlotMap returns and is used for passing exit info. */
    RTR3PTR                     pvMsgSlotMapping;
    /** The windows thread handle. */
    RTR3PTR                     hNativeThreadHandle;

    /** @name Statistics
     * @{ */
    STAMCOUNTER                 StatExitPortIo;
    STAMCOUNTER                 StatExitMemUnmapped;
    STAMCOUNTER                 StatExitMemIntercept;
    STAMCOUNTER                 StatExitHalt;
    STAMCOUNTER                 StatExitInterruptWindow;
    STAMCOUNTER                 StatExitCpuId;
    STAMCOUNTER                 StatExitMsr;
    STAMCOUNTER                 StatExitException;
    STAMCOUNTER                 StatExitExceptionBp;
    STAMCOUNTER                 StatExitExceptionDb;
    STAMCOUNTER                 StatExitExceptionGp;
    STAMCOUNTER                 StatExitExceptionGpMesa;
    STAMCOUNTER                 StatExitExceptionUd;
    STAMCOUNTER                 StatExitExceptionUdHandled;
    STAMCOUNTER                 StatExitUnrecoverable;
    STAMCOUNTER                 StatGetMsgTimeout;
    STAMCOUNTER                 StatStopCpuSuccess;
    STAMCOUNTER                 StatStopCpuPending;
    STAMCOUNTER                 StatStopCpuPendingAlerts;
    STAMCOUNTER                 StatStopCpuPendingOdd;
    STAMCOUNTER                 StatCancelChangedState;
    STAMCOUNTER                 StatCancelAlertedThread;
    STAMCOUNTER                 StatBreakOnCancel;
    STAMCOUNTER                 StatBreakOnFFPre;
    STAMCOUNTER                 StatBreakOnFFPost;
    STAMCOUNTER                 StatBreakOnStatus;
    STAMCOUNTER                 StatImportOnDemand;
    STAMCOUNTER                 StatImportOnReturn;
    STAMCOUNTER                 StatImportOnReturnSkipped;
    STAMCOUNTER                 StatQueryCpuTick;
    /** @} */

#elif defined(RT_OS_DARWIN)
    /** The vCPU handle associated with the EMT executing this vCPU. */
    hv_vcpuid_t                 hVCpuId;

    /** @name State shared with the VT-x code.
     * @{ */
    /** An additional error code used for some gurus. */
    uint32_t                    u32HMError;
    /** The last exit-to-ring-3 reason. */
    int32_t                     rcLastExitToR3;
    /** CPU-context changed flags (see HM_CHANGED_xxx). */
    uint64_t                    fCtxChanged;

    /** The guest VMCS information. */
    VMXVMCSINFO                 VmcsInfo;

    /** VT-x data.   */
    struct HMCPUVMX
    {
        /** @name Guest information.
         * @{ */
        /** Guest VMCS information shared with ring-3. */
        VMXVMCSINFOSHARED           VmcsInfo;
        /** Nested-guest VMCS information shared with ring-3. */
        VMXVMCSINFOSHARED           VmcsInfoNstGst;
        /** Whether the nested-guest VMCS was the last current VMCS (shadow copy for ring-3).
         * @see HMR0PERVCPU::vmx.fSwitchedToNstGstVmcs  */
        bool                        fSwitchedToNstGstVmcsCopyForRing3;
        /** Whether the static guest VMCS controls has been merged with the
         *  nested-guest VMCS controls. */
        bool                        fMergedNstGstCtls;
        /** Whether the nested-guest VMCS has been copied to the shadow VMCS. */
        bool                        fCopiedNstGstToShadowVmcs;
        /** Whether flushing the TLB is required due to switching to/from the
         *  nested-guest. */
        bool                        fSwitchedNstGstFlushTlb;
        /** Alignment. */
        bool                        afAlignment0[4];
        /** Cached guest APIC-base MSR for identifying when to map the APIC-access page. */
        uint64_t                    u64GstMsrApicBase;
        /** @} */

        /** @name Error reporting and diagnostics.
         * @{ */
        /** VT-x error-reporting (mainly for ring-3 propagation). */
        struct
        {
            RTCPUID                 idCurrentCpu;
            RTCPUID                 idEnteredCpu;
            RTHCPHYS                HCPhysCurrentVmcs;
            uint32_t                u32VmcsRev;
            uint32_t                u32InstrError;
            uint32_t                u32ExitReason;
            uint32_t                u32GuestIntrState;
        } LastError;
        /** @} */
    } vmx;

    /** Event injection state. */
    HMEVENT                     Event;

    /** Current shadow paging mode for updating CR4.
     * @todo move later (@bugref{9217}).  */
    PGMMODE                     enmShadowMode;
    uint32_t                    u32TemporaryPadding;

    /** The PAE PDPEs used with Nested Paging (only valid when
     *  VMCPU_FF_HM_UPDATE_PAE_PDPES is set). */
    X86PDPE                     aPdpes[4];
    /** Pointer to the VMX statistics. */
    PVMXSTATISTICS              pVmxStats;

    /** @name Statistics
     * @{ */
    STAMCOUNTER                 StatExitAll;
    STAMCOUNTER                 StatBreakOnCancel;
    STAMCOUNTER                 StatBreakOnFFPre;
    STAMCOUNTER                 StatBreakOnFFPost;
    STAMCOUNTER                 StatBreakOnStatus;
    STAMCOUNTER                 StatImportOnDemand;
    STAMCOUNTER                 StatImportOnReturn;
    STAMCOUNTER                 StatImportOnReturnSkipped;
    STAMCOUNTER                 StatQueryCpuTick;
#ifdef VBOX_WITH_STATISTICS
    STAMPROFILEADV              StatProfGstStateImport;
    STAMPROFILEADV              StatProfGstStateExport;
#endif
    /** @} */

    /** @} */
#endif /* RT_OS_DARWIN */
} NEMCPU;
/** Pointer to NEM VMCPU instance data. */
typedef NEMCPU *PNEMCPU;

/** NEMCPU::u32Magic value. */
#define NEMCPU_MAGIC            UINT32_C(0x4d454e20)
/** NEMCPU::u32Magic value after termination. */
#define NEMCPU_MAGIC_DEAD       UINT32_C(0xdead2222)


#ifdef IN_RING0
# ifdef RT_OS_WINDOWS
/**
 * Windows: Hypercall input/ouput page info.
 */
typedef struct NEMR0HYPERCALLDATA
{
    /** Host physical address of the hypercall input/output page. */
    RTHCPHYS                    HCPhysPage;
    /** Pointer to the hypercall input/output page. */
    uint8_t                    *pbPage;
    /** Handle to the memory object of the hypercall input/output page. */
    RTR0MEMOBJ                  hMemObj;
} NEMR0HYPERCALLDATA;
/** Pointer to a Windows hypercall input/output page info. */
typedef NEMR0HYPERCALLDATA *PNEMR0HYPERCALLDATA;
# endif /* RT_OS_WINDOWS */

/**
 * NEM GVMCPU instance data.
 */
typedef struct NEMR0PERVCPU
{
    uint32_t                    uDummy;
} NEMR0PERVCPU;

/**
 * NEM GVM instance data.
 */
typedef struct NEMR0PERVM
{
    uint32_t                    uDummy;
} NEMR0PERVM;

#endif /* IN_RING*/


#ifdef IN_RING3

int     nemR3DisableCpuIsaExt(PVM pVM, const char *pszIsaExt);

int     nemR3NativeInit(PVM pVM, bool fFallback, bool fForced);
int     nemR3NativeInitAfterCPUM(PVM pVM);
int     nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat);
int     nemR3NativeTerm(PVM pVM);
void    nemR3NativeReset(PVM pVM);
void    nemR3NativeResetCpu(PVMCPU pVCpu, bool fInitIpi);
VBOXSTRICTRC    nemR3NativeRunGC(PVM pVM, PVMCPU pVCpu);
bool            nemR3NativeCanExecuteGuest(PVM pVM, PVMCPU pVCpu);
bool            nemR3NativeSetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable);

/**
 * Forced flag notification call from VMEmt.h.
 *
 * This is only called when pVCpu is in the VMCPUSTATE_STARTED_EXEC_NEM state.
 *
 * @param   pVM             The cross context VM structure.
 * @param   pVCpu           The cross context virtual CPU structure of the CPU
 *                          to be notified.
 * @param   fFlags          Notification flags, VMNOTIFYFF_FLAGS_XXX.
 */
void            nemR3NativeNotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags);

/**
 * Called by NEMR3NotifyDebugEventChanged() to let the native backend take the final decision
 * on whether to switch to the debug loop.
 *
 * @returns Final flag whether to switch to the debug loop.
 * @param   pVM             The VM cross context VM structure.
 * @param   fUseDebugLoop   The current value determined by NEMR3NotifyDebugEventChanged().
 * @thread  EMT(0)
 */
DECLHIDDEN(bool) nemR3NativeNotifyDebugEventChanged(PVM pVM, bool fUseDebugLoop);


/**
 * Called by NEMR3NotifyDebugEventChangedPerCpu() to let the native backend take the final decision
 * on whether to switch to the debug loop.
 *
 * @returns Final flag whether to switch to the debug loop.
 * @param   pVM             The VM cross context VM structure.
 * @param   pVCpu           The cross context virtual CPU structure of the calling EMT.
 * @param   fUseDebugLoop   The current value determined by NEMR3NotifyDebugEventChangedPerCpu().
 */
DECLHIDDEN(bool) nemR3NativeNotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu, bool fUseDebugLoop);

#endif /* IN_RING3 */

void    nemHCNativeNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb);
void    nemHCNativeNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld,
                                               RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM);
int     nemHCNativeNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt,
                                           PGMPAGETYPE enmType, uint8_t *pu2State);


#ifdef RT_OS_WINDOWS
/** Maximum number of pages we can map in a single NEMR0MapPages call. */
# define NEM_MAX_MAP_PAGES      ((HOST_PAGE_SIZE - RT_UOFFSETOF(HV_INPUT_MAP_GPA_PAGES, PageList)) / sizeof(HV_SPA_PAGE_NUMBER))
/** Maximum number of pages we can unmap in a single NEMR0UnmapPages call. */
# define NEM_MAX_UNMAP_PAGES    4095

#endif
/** @} */

RT_C_DECLS_END

#endif /* !VMM_INCLUDED_SRC_include_NEMInternal_h */