/** * @callback_method_impl{PFNVMMEMTRENDEZVOUS, * Worker for gimR3KvmEnableWallClock} */ static DECLCALLBACK(VBOXSTRICTRC) gimR3KvmEnableWallClockCallback(PVM pVM, PVMCPU pVCpu, void *pvData) { Assert(pvData); PKVMWALLCLOCKINFO pWallClockInfo = (PKVMWALLCLOCKINFO)pvData; RTGCPHYS GCPhysWallClock = pWallClockInfo->GCPhysWallClock; /* * Read the wall-clock version (sequence) from the guest. */ uint32_t uVersion; Assert(PGMPhysIsGCPhysNormal(pVM, GCPhysWallClock)); int rc = PGMPhysSimpleReadGCPhys(pVM, &uVersion, GCPhysWallClock, sizeof(uVersion)); if (RT_FAILURE(rc)) { LogRel(("GIM: KVM: Failed to read wall-clock struct. version at %#RGp. rc=%Rrc\n", GCPhysWallClock, rc)); return rc; } /* * Ensure the version is incrementally even. */ if (!(uVersion & 1)) ++uVersion; ++uVersion; /* * Update wall-clock guest struct. with UTC information. */ RTTIMESPEC TimeSpec; int32_t iSec; int32_t iNano; TMR3UtcNow(pVM, &TimeSpec); RTTimeSpecGetSecondsAndNano(&TimeSpec, &iSec, &iNano); GIMKVMWALLCLOCK WallClock; RT_ZERO(WallClock); AssertCompile(sizeof(uVersion) == sizeof(WallClock.u32Version)); WallClock.u32Version = uVersion; WallClock.u32Sec = iSec; WallClock.u32Nano = iNano; /* * Write out the wall-clock struct. to guest memory. */ Assert(!(WallClock.u32Version & 1)); rc = PGMPhysSimpleWriteGCPhys(pVM, GCPhysWallClock, &WallClock, sizeof(GIMKVMWALLCLOCK)); if (RT_SUCCESS(rc)) { LogRel(("GIM: KVM: Enabled wall-clock struct. at %#RGp - u32Sec=%u u32Nano=%u uVersion=%#RU32\n", GCPhysWallClock, WallClock.u32Sec, WallClock.u32Nano, WallClock.u32Version)); } else LogRel(("GIM: KVM: Failed to write wall-clock struct. at %#RGp. rc=%Rrc\n", GCPhysWallClock, rc)); return rc; }
/** * Writes guest memory. * * @returns VBox status code. * * @param pUVM The user mode VM handle. * @param idCpu The ID of the target CPU context (for the address). * @param pAddress Where to start writing. * @param pvBuf The data to write. * @param cbWrite The number of bytes to write. */ static DECLCALLBACK(int) dbgfR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbWrite) { /* * Validate the input we use, PGM does the rest. */ if (!DBGFR3AddrIsValid(pUVM, pAddress)) return VERR_INVALID_POINTER; if (!VALID_PTR(pvBuf)) return VERR_INVALID_POINTER; PVM pVM = pUVM->pVM; VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE); /* * HMA is always special. */ int rc; if (DBGFADDRESS_IS_HMA(pAddress)) { /** @todo write to HMA. */ rc = VERR_ACCESS_DENIED; } else { /* * Select PGM function by addressing mode. */ PVMCPU pVCpu = VMMGetCpuById(pVM, idCpu); PGMMODE enmMode = PGMGetGuestMode(pVCpu); if ( enmMode == PGMMODE_REAL || enmMode == PGMMODE_PROTECTED || DBGFADDRESS_IS_PHYS(pAddress) ) rc = PGMPhysSimpleWriteGCPhys(pVM, pAddress->FlatPtr, pvBuf, cbWrite); else { #if GC_ARCH_BITS > 32 if ( ( pAddress->FlatPtr >= _4G || pAddress->FlatPtr + cbWrite > _4G) && enmMode != PGMMODE_AMD64 && enmMode != PGMMODE_AMD64_NX) return VERR_PAGE_TABLE_NOT_PRESENT; #endif rc = PGMPhysSimpleWriteGCPtr(pVCpu, pAddress->FlatPtr, pvBuf, cbWrite); } } return rc; }
/** * Enables the KVM VCPU system-time structure. * * @returns VBox status code. * @param pVM Pointer to the VM. * @param pVCpu Pointer to the VMCPU. * * @remarks Don't do any release assertions here, these can be triggered by * guest R0 code. */ VMMR3_INT_DECL(int) gimR3KvmEnableSystemTime(PVM pVM, PVMCPU pVCpu) { PGIMKVM pKvm = &pVM->gim.s.u.Kvm; PGIMKVMCPU pKvmCpu = &pVCpu->gim.s.u.KvmCpu; /* * Validate the mapping address first. */ if (!PGMPhysIsGCPhysNormal(pVM, pKvmCpu->GCPhysSystemTime)) { LogRel(("GIM: KVM: VCPU%3d: Invalid physical addr requested for mapping system-time struct. GCPhysSystemTime=%#RGp\n", pVCpu->idCpu, pKvmCpu->GCPhysSystemTime)); return VERR_GIM_OPERATION_FAILED; } /* * Construct the system-time struct. */ GIMKVMSYSTEMTIME SystemTime; RT_ZERO(SystemTime); SystemTime.u32Version = pKvmCpu->u32SystemTimeVersion; SystemTime.u64NanoTS = pKvmCpu->uVirtNanoTS; SystemTime.u64Tsc = pKvmCpu->uTsc; SystemTime.fFlags = pKvmCpu->fSystemTimeFlags | GIM_KVM_SYSTEM_TIME_FLAGS_TSC_STABLE; /* * How the guest calculates the system time (nanoseconds): * * tsc = rdtsc - SysTime.u64Tsc * if (SysTime.i8TscShift >= 0) * tsc <<= i8TscShift; * else * tsc >>= -i8TscShift; * time = ((tsc * SysTime.u32TscScale) >> 32) + SysTime.u64NanoTS */ uint64_t u64TscFreq = pKvm->cTscTicksPerSecond; SystemTime.i8TscShift = 0; while (u64TscFreq > 2 * RT_NS_1SEC_64) { u64TscFreq >>= 1; SystemTime.i8TscShift--; } uint32_t uTscFreqLo = (uint32_t)u64TscFreq; while (uTscFreqLo <= RT_NS_1SEC) { uTscFreqLo <<= 1; SystemTime.i8TscShift++; } SystemTime.u32TscScale = ASMDivU64ByU32RetU32(RT_NS_1SEC_64 << 32, uTscFreqLo); /* * Update guest memory with the system-time struct. */ Assert(!(SystemTime.u32Version & UINT32_C(1))); int rc = PGMPhysSimpleWriteGCPhys(pVM, pKvmCpu->GCPhysSystemTime, &SystemTime, sizeof(GIMKVMSYSTEMTIME)); if (RT_SUCCESS(rc)) { LogRel(("GIM: KVM: VCPU%3d: Enabled system-time struct. at %#RGp - u32TscScale=%#RX32 i8TscShift=%d uVersion=%#RU32 " "fFlags=%#x uTsc=%#RX64 uVirtNanoTS=%#RX64\n", pVCpu->idCpu, pKvmCpu->GCPhysSystemTime, SystemTime.u32TscScale, SystemTime.i8TscShift, SystemTime.u32Version, SystemTime.fFlags, pKvmCpu->uTsc, pKvmCpu->uVirtNanoTS)); TMR3CpuTickParavirtEnable(pVM); } else LogRel(("GIM: KVM: VCPU%3d: Failed to write system-time struct. at %#RGp. rc=%Rrc\n", pVCpu->idCpu, pKvmCpu->GCPhysSystemTime, rc)); return rc; }