diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/VMM/VMMR0/GIMR0Hv.cpp | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/VMM/VMMR0/GIMR0Hv.cpp')
-rw-r--r-- | src/VBox/VMM/VMMR0/GIMR0Hv.cpp | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMR0/GIMR0Hv.cpp b/src/VBox/VMM/VMMR0/GIMR0Hv.cpp new file mode 100644 index 00000000..cbf23de1 --- /dev/null +++ b/src/VBox/VMM/VMMR0/GIMR0Hv.cpp @@ -0,0 +1,182 @@ +/* $Id: GIMR0Hv.cpp $ */ +/** @file + * Guest Interface Manager (GIM), Hyper-V - Host Context Ring-0. + */ + +/* + * Copyright (C) 2014-2019 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. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_GIM +#include <VBox/vmm/gim.h> +#include <VBox/vmm/tm.h> +#include "GIMInternal.h" +#include "GIMHvInternal.h" +#include <VBox/vmm/vm.h> + +#include <VBox/err.h> + +#include <iprt/spinlock.h> + + +#if 0 +/** + * Allocates and maps one physically contiguous page. The allocated page is + * zero'd out. + * + * @returns IPRT status code. + * @param pMemObj Pointer to the ring-0 memory object. + * @param ppVirt Where to store the virtual address of the + * allocation. + * @param pPhys Where to store the physical address of the + * allocation. + */ +static int gimR0HvPageAllocZ(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys) +{ + AssertPtr(pMemObj); + AssertPtr(ppVirt); + AssertPtr(pHCPhys); + + int rc = RTR0MemObjAllocCont(pMemObj, PAGE_SIZE, false /* fExecutable */); + if (RT_FAILURE(rc)) + return rc; + *ppVirt = RTR0MemObjAddress(*pMemObj); + *pHCPhys = RTR0MemObjGetPagePhysAddr(*pMemObj, 0 /* iPage */); + ASMMemZero32(*ppVirt, PAGE_SIZE); + return VINF_SUCCESS; +} + + +/** + * Frees and unmaps an allocated physical page. + * + * @param pMemObj Pointer to the ring-0 memory object. + * @param ppVirt Where to re-initialize the virtual address of + * allocation as 0. + * @param pHCPhys Where to re-initialize the physical address of the + * allocation as 0. + */ +static void gimR0HvPageFree(PRTR0MEMOBJ pMemObj, PRTR0PTR ppVirt, PRTHCPHYS pHCPhys) +{ + AssertPtr(pMemObj); + AssertPtr(ppVirt); + AssertPtr(pHCPhys); + if (*pMemObj != NIL_RTR0MEMOBJ) + { + int rc = RTR0MemObjFree(*pMemObj, true /* fFreeMappings */); + AssertRC(rc); + *pMemObj = NIL_RTR0MEMOBJ; + *ppVirt = 0; + *pHCPhys = 0; + } +} +#endif + +/** + * Updates Hyper-V's reference TSC page. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param u64Offset The computed TSC offset. + * @thread EMT. + */ +VMM_INT_DECL(int) gimR0HvUpdateParavirtTsc(PVM pVM, uint64_t u64Offset) +{ + Assert(GIMIsEnabled(pVM)); + bool fHvTscEnabled = MSR_GIM_HV_REF_TSC_IS_ENABLED(pVM->gim.s.u.Hv.u64TscPageMsr); + if (RT_UNLIKELY(!fHvTscEnabled)) + return VERR_GIM_PVTSC_NOT_ENABLED; + + /** @todo this is buggy when large pages are used due to a PGM limitation, see + * @bugref{7532}. + * + * In any case, we do not ever update this page while the guest is + * running after setting it up (in ring-3, see gimR3HvEnableTscPage()) as + * the TSC offset is handled in the VMCS/VMCB (HM) or by trapping RDTSC + * (raw-mode). */ +#if 0 + PCGIMHV pcHv = &pVM->gim.s.u.Hv; + PCGIMMMIO2REGION pcRegion = &pcHv->aMmio2Regions[GIM_HV_REF_TSC_PAGE_REGION_IDX]; + PGIMHVREFTSC pRefTsc = (PGIMHVREFTSC)pcRegion->CTX_SUFF(pvPage); + Assert(pRefTsc); + + /* + * Hyper-V reports the reference time in 100 nanosecond units. + */ + uint64_t u64Tsc100Ns = pcHv->cTscTicksPerSecond / RT_NS_10MS; + int64_t i64TscOffset = (int64_t)u64Offset / u64Tsc100Ns; + + /* + * The TSC page can be simulatenously read by other VCPUs in the guest. The + * spinlock is only for protecting simultaneous hypervisor writes from other + * EMTs. + */ + RTSpinlockAcquire(pcHv->hSpinlockR0); + if (pRefTsc->i64TscOffset != i64TscOffset) + { + if (pRefTsc->u32TscSequence < UINT32_C(0xfffffffe)) + ASMAtomicIncU32(&pRefTsc->u32TscSequence); + else + ASMAtomicWriteU32(&pRefTsc->u32TscSequence, 1); + ASMAtomicWriteS64(&pRefTsc->i64TscOffset, i64TscOffset); + } + RTSpinlockRelease(pcHv->hSpinlockR0); + + Assert(pRefTsc->u32TscSequence != 0); + Assert(pRefTsc->u32TscSequence != UINT32_C(0xffffffff)); +#else + NOREF(u64Offset); +#endif + return VINF_SUCCESS; +} + + +/** + * Does ring-0 per-VM GIM Hyper-V initialization. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + */ +VMMR0_INT_DECL(int) gimR0HvInitVM(PVM pVM) +{ + AssertPtr(pVM); + Assert(GIMIsEnabled(pVM)); + + PGIMHV pHv = &pVM->gim.s.u.Hv; + Assert(pHv->hSpinlockR0 == NIL_RTSPINLOCK); + + int rc = RTSpinlockCreate(&pHv->hSpinlockR0, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "Hyper-V"); + return rc; +} + + +/** + * Does ring-0 per-VM GIM Hyper-V termination. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + */ +VMMR0_INT_DECL(int) gimR0HvTermVM(PVM pVM) +{ + AssertPtr(pVM); + Assert(GIMIsEnabled(pVM)); + + PGIMHV pHv = &pVM->gim.s.u.Hv; + RTSpinlockDestroy(pHv->hSpinlockR0); + pHv->hSpinlockR0 = NIL_RTSPINLOCK; + + return VINF_SUCCESS; +} + |