summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/VMMAll/VMMAll.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/VBox/VMM/VMMAll/VMMAll.cpp296
1 files changed, 296 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMAll/VMMAll.cpp b/src/VBox/VMM/VMMAll/VMMAll.cpp
new file mode 100644
index 00000000..b8ba8eb8
--- /dev/null
+++ b/src/VBox/VMM/VMMAll/VMMAll.cpp
@@ -0,0 +1,296 @@
+/* $Id: VMMAll.cpp $ */
+/** @file
+ * VMM All Contexts.
+ */
+
+/*
+ * Copyright (C) 2006-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
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_VMM
+#include <VBox/vmm/vmm.h>
+#include "VMMInternal.h"
+#include <VBox/vmm/vmcc.h>
+#ifdef IN_RING0
+# include <VBox/vmm/gvm.h>
+#endif
+#include <VBox/vmm/hm.h>
+#include <VBox/vmm/vmcpuset.h>
+#include <VBox/param.h>
+#include <iprt/thread.h>
+#include <iprt/mp.h>
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** User counter for the vmmInitFormatTypes function (pro forma). */
+static volatile uint32_t g_cFormatTypeUsers = 0;
+
+
+/**
+ * Helper that formats a decimal number in the range 0..9999.
+ *
+ * @returns The length of the formatted number.
+ * @param pszBuf Output buffer with sufficient space.
+ * @param uNumber The number to format.
+ */
+static unsigned vmmFormatTypeShortNumber(char *pszBuf, uint32_t uNumber)
+{
+ unsigned off = 0;
+ if (uNumber >= 10)
+ {
+ if (uNumber >= 100)
+ {
+ if (uNumber >= 1000)
+ pszBuf[off++] = ((uNumber / 1000) % 10) + '0';
+ pszBuf[off++] = ((uNumber / 100) % 10) + '0';
+ }
+ pszBuf[off++] = ((uNumber / 10) % 10) + '0';
+ }
+ pszBuf[off++] = (uNumber % 10) + '0';
+ pszBuf[off] = '\0';
+ return off;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRFORMATTYPE, vmsetcpu}
+ */
+static DECLCALLBACK(size_t) vmmFormatTypeVmCpuSet(PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
+ const char *pszType, void const *pvValue,
+ int cchWidth, int cchPrecision, unsigned fFlags,
+ void *pvUser)
+{
+ NOREF(pszType); NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags);
+
+ PCVMCPUSET pSet = (PCVMCPUSET)pvValue;
+ uint32_t cCpus = 0;
+ uint32_t iCpu = RT_ELEMENTS(pSet->au32Bitmap) * 32;
+ while (iCpu--)
+ if (VMCPUSET_IS_PRESENT(pSet, iCpu))
+ cCpus++;
+
+ char szTmp[32];
+ AssertCompile(RT_ELEMENTS(pSet->au32Bitmap) * 32 < 999);
+ if (cCpus == 1)
+ {
+ iCpu = RT_ELEMENTS(pSet->au32Bitmap) * 32;
+ while (iCpu--)
+ if (VMCPUSET_IS_PRESENT(pSet, iCpu))
+ {
+ szTmp[0] = 'c';
+ szTmp[1] = 'p';
+ szTmp[2] = 'u';
+ return pfnOutput(pvArgOutput, szTmp, 3 + vmmFormatTypeShortNumber(&szTmp[3], iCpu));
+ }
+ cCpus = 0;
+ }
+ if (cCpus == 0)
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<empty>"));
+ if (cCpus == RT_ELEMENTS(pSet->au32Bitmap) * 32)
+ return pfnOutput(pvArgOutput, RT_STR_TUPLE("<full>"));
+
+ /*
+ * Print cpus that are present: {1,2,7,9 ... }
+ */
+ size_t cchRet = pfnOutput(pvArgOutput, "{", 1);
+
+ cCpus = 0;
+ iCpu = 0;
+ while (iCpu < RT_ELEMENTS(pSet->au32Bitmap) * 32)
+ {
+ if (VMCPUSET_IS_PRESENT(pSet, iCpu))
+ {
+ /* Output the first cpu number. */
+ int off = 0;
+ if (cCpus != 0)
+ szTmp[off++] = ',';
+ cCpus++;
+ off += vmmFormatTypeShortNumber(&szTmp[off], iCpu);
+
+ /* Check for sequence. */
+ uint32_t const iStart = ++iCpu;
+ while ( iCpu < RT_ELEMENTS(pSet->au32Bitmap) * 32
+ && VMCPUSET_IS_PRESENT(pSet, iCpu))
+ {
+ iCpu++;
+ cCpus++;
+ }
+ if (iCpu != iStart)
+ {
+ szTmp[off++] = '-';
+ off += vmmFormatTypeShortNumber(&szTmp[off], iCpu);
+ }
+
+ /* Terminate and output. */
+ szTmp[off] = '\0';
+ cchRet += pfnOutput(pvArgOutput, szTmp, off);
+ }
+ iCpu++;
+ }
+
+ cchRet += pfnOutput(pvArgOutput, "}", 1);
+ NOREF(pvUser);
+ return cchRet;
+}
+
+
+/**
+ * Registers the VMM wide format types.
+ *
+ * Called by VMMR3Init, VMMR0Init and VMMRCInit.
+ */
+int vmmInitFormatTypes(void)
+{
+ int rc = VINF_SUCCESS;
+ if (ASMAtomicIncU32(&g_cFormatTypeUsers) == 1)
+ rc = RTStrFormatTypeRegister("vmcpuset", vmmFormatTypeVmCpuSet, NULL);
+ return rc;
+}
+
+
+/**
+ * Counterpart to vmmInitFormatTypes, called by VMMR3Term and VMMR0Term.
+ */
+void vmmTermFormatTypes(void)
+{
+ if (ASMAtomicDecU32(&g_cFormatTypeUsers) == 0)
+ RTStrFormatTypeDeregister("vmcpuset");
+}
+
+
+/**
+ * Gets the ID of the virtual CPU associated with the calling thread.
+ *
+ * @returns The CPU ID. NIL_VMCPUID if the thread isn't an EMT.
+ *
+ * @param pVM The cross context VM structure.
+ * @internal
+ */
+VMMDECL(VMCPUID) VMMGetCpuId(PVMCC pVM)
+{
+#if defined(IN_RING3)
+ return VMR3GetVMCPUId(pVM);
+
+#elif defined(IN_RING0)
+ PVMCPUCC pVCpu = GVMMR0GetGVCpuByGVMandEMT(pVM, NIL_RTNATIVETHREAD);
+ return pVCpu ? pVCpu->idCpu : NIL_VMCPUID;
+
+#else /* RC: Always EMT(0) */
+ NOREF(pVM);
+ return 0;
+#endif
+}
+
+
+/**
+ * Returns the VMCPU of the calling EMT.
+ *
+ * @returns The VMCPU pointer. NULL if not an EMT.
+ *
+ * @param pVM The cross context VM structure.
+ * @internal
+ */
+VMMDECL(PVMCPUCC) VMMGetCpu(PVMCC pVM)
+{
+#ifdef IN_RING3
+ VMCPUID idCpu = VMR3GetVMCPUId(pVM);
+ if (idCpu == NIL_VMCPUID)
+ return NULL;
+ Assert(idCpu < pVM->cCpus);
+ return VMCC_GET_CPU(pVM, idCpu);
+
+#elif defined(IN_RING0)
+ return GVMMR0GetGVCpuByGVMandEMT(pVM, NIL_RTNATIVETHREAD);
+
+#else /* RC: Always EMT(0) */
+ RT_NOREF(pVM);
+ return &g_VCpu0;
+#endif /* IN_RING0 */
+}
+
+
+/**
+ * Returns the VMCPU of the first EMT thread.
+ *
+ * @returns The VMCPU pointer.
+ * @param pVM The cross context VM structure.
+ * @internal
+ */
+VMMDECL(PVMCPUCC) VMMGetCpu0(PVMCC pVM)
+{
+ Assert(pVM->cCpus == 1);
+ return VMCC_GET_CPU_0(pVM);
+}
+
+
+/**
+ * Returns the VMCPU of the specified virtual CPU.
+ *
+ * @returns The VMCPU pointer. NULL if idCpu is invalid.
+ *
+ * @param pVM The cross context VM structure.
+ * @param idCpu The ID of the virtual CPU.
+ * @internal
+ */
+VMMDECL(PVMCPUCC) VMMGetCpuById(PVMCC pVM, RTCPUID idCpu)
+{
+ AssertReturn(idCpu < pVM->cCpus, NULL);
+ return VMCC_GET_CPU(pVM, idCpu);
+}
+
+
+/**
+ * Gets the VBOX_SVN_REV.
+ *
+ * This is just to avoid having to compile a bunch of big files
+ * and requires less Makefile mess.
+ *
+ * @returns VBOX_SVN_REV.
+ */
+VMM_INT_DECL(uint32_t) VMMGetSvnRev(void)
+{
+ return VBOX_SVN_REV;
+}
+
+
+/**
+ * Returns the build type for matching components.
+ *
+ * @returns Build type value.
+ */
+uint32_t vmmGetBuildType(void)
+{
+ uint32_t uRet = 0xbeef0000;
+#ifdef DEBUG
+ uRet |= RT_BIT_32(0);
+#endif
+#ifdef VBOX_WITH_STATISTICS
+ uRet |= RT_BIT_32(1);
+#endif
+ return uRet;
+}
+