/** @file
 * VM - The Virtual Machine, data.
 */

/*
 * Copyright (C) 2006-2020 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
 * VirtualBox OSE distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 */



#pragma D  depends_on library vbox-types.d
#pragma D  depends_on library CPUMInternal.d




/** @defgroup grp_vm    The Virtual Machine
 * @ingroup grp_vmm
 * @{
 */

/**
 * The state of a Virtual CPU.
 *
 * The basic state indicated here is whether the CPU has been started or not. In
 * addition, there are sub-states when started for assisting scheduling (GVMM
 * mostly).
 *
 * The transition out of the STOPPED state is done by a vmR3PowerOn.
 * The transition back to the STOPPED state is done by vmR3PowerOff.
 *
 * (Alternatively we could let vmR3PowerOn start CPU 0 only and let the SPIP
 * handling switch on the other CPUs. Then vmR3Reset would stop all but CPU 0.)
 */
typedef enum VMCPUSTATE
{
    /** The customary invalid zero. */
    VMCPUSTATE_INVALID = 0,

    /** Virtual CPU has not yet been started.  */
    VMCPUSTATE_STOPPED,

    /** CPU started. */
    VMCPUSTATE_STARTED,
    /** CPU started in HM context. */
    VMCPUSTATE_STARTED_HM,
    /** Executing guest code and can be poked (RC or STI bits of HM). */
    VMCPUSTATE_STARTED_EXEC,
    /** Executing guest code using NEM. */
    VMCPUSTATE_STARTED_EXEC_NEM,
    VMCPUSTATE_STARTED_EXEC_NEM_WAIT,
    VMCPUSTATE_STARTED_EXEC_NEM_CANCELED,
    /** Halted. */
    VMCPUSTATE_STARTED_HALTED,

    /** The end of valid virtual CPU states. */
    VMCPUSTATE_END,

    /** Ensure 32-bit type. */
    VMCPUSTATE_32BIT_HACK = 0x7fffffff
} VMCPUSTATE;

/** Enables 64-bit FFs. */



/**
 * The cross context virtual CPU structure.
 *
 * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating!
 */
typedef struct VMCPU
{
    /** @name Volatile per-cpu data.
     * @{ */
    /** Per CPU forced action.
     * See the VMCPU_FF_* \#defines. Updated atomically. */
    uint64_t volatile       fLocalForcedActions;
    /** The CPU state. */
    VMCPUSTATE volatile     enmState;

    /** Which host CPU ID is this EMT running on.
     * Only valid when in RC or HMR0 with scheduling disabled. */
    RTCPUID volatile        idHostCpu;
    /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid.
     * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */
    uint32_t volatile       iHostCpuSet;
    /** Padding up to 64 bytes. */
    uint8_t                 abAlignment0[64 - 20];
    /** @} */

    /** IEM part.
     * @remarks This comes first as it allows the use of 8-bit immediates for the
     *          first 64 bytes of the structure, reducing code size a wee bit. */
    union VMCPUUNIONIEMSTUB
    {
        uint8_t             padding[18496];     /* multiple of 64 */
    } iem;

    /** @name Static per-cpu data.
     * (Putting this after IEM, hoping that it's less frequently used than it.)
     * @{ */
    /** Ring-3 Host Context VM Pointer. */
    PVMR3                   pVMR3;
    /** Ring-0 Host Context VM Pointer, currently used by VTG/dtrace. */
    RTR0PTR                 pVCpuR0ForVtg;
    /** Raw-mode Context VM Pointer. */
    uint32_t                pVMRC;
    /** Padding for new raw-mode (long mode).   */
    uint32_t                pVMRCPadding;
    /** Pointer to the ring-3 UVMCPU structure. */
    PUVMCPU                 pUVCpu;
    /** The native thread handle. */
    RTNATIVETHREAD          hNativeThread;
    /** The native R0 thread handle. (different from the R3 handle!) */
    RTNATIVETHREAD          hNativeThreadR0;
    /** The CPU ID.
     * This is the index into the VM::aCpu array. */
    VMCPUID                 idCpuUnsafe;

    /** Align the structures below bit on a 64-byte boundary and make sure it starts
     * at the same offset in both 64-bit and 32-bit builds.
     *
     * @remarks The alignments of the members that are larger than 48 bytes should be
     *          64-byte for cache line reasons. structs containing small amounts of
     *          data could be lumped together at the end with a < 64 byte padding
     *          following it (to grow into and align the struct size).
     */
    uint8_t                 abAlignment1[64 - 5 * (64 == 32 ? 4 : 8) - 8 - 4];
    /** @} */

    /** HM part. */
    union VMCPUUNIONHM
    {
        uint8_t             padding[5888];      /* multiple of 64 */
    } hm;

    /** NEM part. */
    union VMCPUUNIONNEM
    {
        uint8_t             padding[512];       /* multiple of 64 */
    } nem;

    /** TRPM part. */
    union VMCPUUNIONTRPM
    {
        uint8_t             padding[128];       /* multiple of 64 */
    } trpm;

    /** TM part. */
    union VMCPUUNIONTM
    {
        uint8_t             padding[5760];      /* multiple of 64 */
    } tm;

    /** VMM part. */
    union VMCPUUNIONVMM
    {
        uint8_t             padding[896];       /* multiple of 64 */
    } vmm;

    /** PDM part. */
    union VMCPUUNIONPDM
    {
        uint8_t             padding[256];       /* multiple of 64 */
    } pdm;

    /** IOM part. */
    union VMCPUUNIONIOM
    {
        uint8_t             padding[512];       /* multiple of 64 */
    } iom;

    /** DBGF part.
     * @todo Combine this with other tiny structures. */
    union VMCPUUNIONDBGF
    {
        uint8_t             padding[256];       /* multiple of 64 */
    } dbgf;

    /** GIM part. */
    union VMCPUUNIONGIM
    {
        uint8_t             padding[512];       /* multiple of 64 */
    } gim;

    /** APIC part. */
    union VMCPUUNIONAPIC
    {
        uint8_t             padding[1792];      /* multiple of 64 */
    } apic;

    /*
     * Some less frequently used global members that doesn't need to take up
     * precious space at the head of the structure.
     */

    /** Trace groups enable flags.  */
    uint32_t                fTraceGroups;                           /* 64 / 44 */
    /** State data for use by ad hoc profiling. */
    uint32_t                uAdHoc;
    /** Profiling samples for use by ad hoc profiling. */
    STAMPROFILEADV          aStatAdHoc[8];                          /* size: 40*8 = 320 */

    /** Align the following members on page boundary. */
    uint8_t                 abAlignment2[1400];

    /** PGM part. */
    union VMCPUUNIONPGM
    {
        uint8_t             padding[4096];      /* multiple of 4096 */
    } pgm;

    /** CPUM part. */
    union VMCPUUNIONCPUM
    {
        struct CPUMCPU      s;
        uint8_t             padding[4096];      /* multiple of 4096 */
    } cpum;

    /** EM part. */
    union VMCPUUNIONEM
    {
        uint8_t             padding[40960];      /* multiple of 4096 */
    } em;
} VMCPU;




/**
 * Helper that HM and NEM uses for safely modifying VM::bMainExecutionEngine.
 *
 * ONLY HM and NEM MAY USE THIS!
 *
 * @param   a_pVM       The cross context VM structure.
 * @param   a_bValue    The new value.
 * @internal
 */


/**
 * Checks whether raw-mode is used.
 *
 * @retval  true if either is used.
 * @retval  false if software virtualization (raw-mode) is used.
 *
 * @param   a_pVM       The cross context VM structure.
 * @sa      VM_IS_HM_OR_NEM_ENABLED, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED.
 * @internal
 */


/**
 * Checks whether HM (VT-x/AMD-V) or NEM is being used by this VM.
 *
 * @retval  true if either is used.
 * @retval  false if software virtualization (raw-mode) is used.
 *
 * @param   a_pVM       The cross context VM structure.
 * @sa      VM_IS_RAW_MODE_ENABLED, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED.
 * @internal
 */


/**
 * Checks whether HM is being used by this VM.
 *
 * @retval  true if HM (VT-x/AMD-v) is used.
 * @retval  false if not.
 *
 * @param   a_pVM       The cross context VM structure.
 * @sa      VM_IS_NEM_ENABLED, VM_IS_RAW_MODE_ENABLED, VM_IS_HM_OR_NEM_ENABLED.
 * @internal
 */


/**
 * Checks whether NEM is being used by this VM.
 *
 * @retval  true if a native hypervisor API is used.
 * @retval  false if not.
 *
 * @param   a_pVM       The cross context VM structure.
 * @sa      VM_IS_HM_ENABLED, VM_IS_RAW_MODE_ENABLED, VM_IS_HM_OR_NEM_ENABLED.
 * @internal
 */



/**
 * The cross context VM structure.
 *
 * It contains all the VM data which have to be available in all contexts.
 * Even if it contains all the data the idea is to use APIs not to modify all
 * the members all around the place.  Therefore we make use of unions to hide
 * everything which isn't local to the current source module.  This means we'll
 * have to pay a little bit of attention when adding new members to structures
 * in the unions and make sure to keep the padding sizes up to date.
 *
 * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating!
 */
typedef struct VM
{
    /** The state of the VM.
     * This field is read only to everyone except the VM and EM. */
    VMSTATE volatile            enmVMState;
    /** Forced action flags.
     * See the VM_FF_* \#defines. Updated atomically.
     */
    volatile uint32_t           fGlobalForcedActions;
    /** Pointer to the array of page descriptors for the VM structure allocation. */
    RTR3PTR         paVMPagesR3;
    /** Session handle. For use when calling SUPR0 APIs. */
    PSUPDRVSESSION              pSessionUnsafe;
    /** Pointer to the ring-3 VM structure. */
    PUVM                        pUVM;
    /** Ring-3 Host Context VM Pointer. */
    RTR3PTR      pVMR3Unsafe;
    /** Ring-0 Host Context VM pointer for making ring-0 calls. */
    struct VM *       pVMR0ForCall;
    /** Raw-mode Context VM Pointer. */
    uint32_t                    pVMRC;
    /** Padding for new raw-mode (long mode).   */
    uint32_t                    pVMRCPadding;

    /** The GVM VM handle. Only the GVM should modify this field. */
    uint32_t                    hSelfUnsafe;
    /** Number of virtual CPUs. */
    uint32_t                    cCpusUnsafe;
    /** CPU excution cap (1-100) */
    uint32_t                    uCpuExecutionCap;

    /** Size of the VM structure. */
    uint32_t                    cbSelf;
    /** Size of the VMCPU structure. */
    uint32_t                    cbVCpu;
    /** Structure version number (TBD). */
    uint32_t                    uStructVersion;

    /** @name Various items that are frequently accessed.
     * @{ */
    /** The main execution engine, VM_EXEC_ENGINE_XXX.
     * This is set early during vmR3InitRing3 by HM or NEM.  */
    uint8_t const               bMainExecutionEngine;

    /** Hardware VM support is available and enabled.
     * Determined very early during init.
     * This is placed here for performance reasons.
     * @todo obsoleted by bMainExecutionEngine, eliminate. */
    uint8_t                        fHMEnabled;

    /** Large page enabled flag.
     * @todo This doesn't need to be here, PGM should store it in it's own
     *       structures instead. */
    uint8_t                        fUseLargePages;
    /** @} */

    /** Alignment padding. */
    uint8_t                     uPadding1[5];

    /** @name Debugging
     * @{ */
    /** Ring-3 Host Context VM Pointer. */
    RTR3PTR       hTraceBufR3;
    /** Ring-0 Host Context VM Pointer. */
    RTTRACEBUF        hTraceBufR0;
    /** @} */

    /** Padding - the unions must be aligned on a 64 bytes boundary. */
    uint8_t                     abAlignment3[64 == 64 ? 24 : 52];

    /** CPUM part. */
    union
    {
        struct CPUM s;
        uint8_t     padding[1536];      /* multiple of 64 */
    } cpum;

    /** VMM part. */
    union
    {
        uint8_t     padding[1600];      /* multiple of 64 */
    } vmm;

    /** PGM part. */
    union
    {
        uint8_t     padding[21120];      /* multiple of 64 */
    } pgm;

    /** HM part. */
    union
    {
        uint8_t     padding[5504];      /* multiple of 64 */
    } hm;

    /** TRPM part. */
    union
    {
        uint8_t     padding[5248];      /* multiple of 64 */
    } trpm;

    /** SELM part. */
    union
    {
        uint8_t     padding[768];       /* multiple of 64 */
    } selm;

    /** MM part. */
    union
    {
        uint8_t     padding[192];       /* multiple of 64 */
    } mm;

    /** PDM part. */
    union
    {
        uint8_t     padding[7808];      /* multiple of 64 */
    } pdm;

    /** IOM part. */
    union
    {
        uint8_t     padding[1152];      /* multiple of 64 */
    } iom;

    /** EM part. */
    union
    {
        uint8_t     padding[256];       /* multiple of 64 */
    } em;

    /** NEM part. */
    union
    {
        uint8_t     padding[128];       /* multiple of 64 */
    } nem;

    /** TM part. */
    union
    {
        uint8_t     padding[7872];      /* multiple of 64 */
    } tm;

    /** DBGF part. */
    union
    {
        uint8_t     padding[2432];      /* multiple of 64 */
    } dbgf;

    /** SSM part. */
    union
    {
        uint8_t     padding[128];       /* multiple of 64 */
    } ssm;

    union
    {
        uint8_t     padding[448];       /* multiple of 64 */
    } gim;

    union
    {
        uint8_t     padding[128];       /* multiple of 8 */
    } apic;

    /* ---- begin small stuff ---- */

    /** VM part. */
    union
    {
        uint8_t     padding[32];        /* multiple of 8 */
    } vm;

    /** CFGM part. */
    union
    {
        uint8_t     padding[8];         /* multiple of 8 */
    } cfgm;

    /** Statistics for ring-0 only components. */
    struct
    {
        /** GMMR0 stats. */
        struct
        {
            /** Chunk TLB hits. */
            uint64_t    cChunkTlbHits;
            /** Chunk TLB misses. */
            uint64_t    cChunkTlbMisses;
        } gmm;
        uint64_t    au64Padding[6];     /* probably more comming here... */
    } R0Stats;

    /** Padding for aligning the structure size on a page boundrary. */
    uint8_t         abAlignment2[600 - 64 + 256 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT];

    /* ---- end small stuff ---- */

    /** Array of VMCPU ring-3 pointers. */
    PVMCPUR3        apCpusR3[VMM_MAX_CPU_COUNT];
} VM;



/** @} */


