/** * Pauses the CPU timestamp counter ticking. * * @returns VBox status code. * @param pVCpu The cross context virtual CPU structure. * @internal */ int tmCpuTickPause(PVMCPU pVCpu) { if (pVCpu->tm.s.fTSCTicking) { pVCpu->tm.s.u64TSC = TMCpuTickGetNoCheck(pVCpu); pVCpu->tm.s.fTSCTicking = false; return VINF_SUCCESS; } AssertFailed(); return VERR_TM_TSC_ALREADY_PAUSED; }
/** * Pauses the CPU timestamp counter ticking. * * @returns VBox status code. * @param pVM The cross context VM structure. * @param pVCpu The cross context virtual CPU structure. * @internal */ int tmCpuTickPauseLocked(PVM pVM, PVMCPU pVCpu) { if (pVCpu->tm.s.fTSCTicking) { pVCpu->tm.s.u64TSC = TMCpuTickGetNoCheck(pVCpu); pVCpu->tm.s.fTSCTicking = false; uint32_t c = ASMAtomicDecU32(&pVM->tm.s.cTSCsTicking); AssertMsgReturn(c < pVM->cCpus, ("%u vs %u\n", c, pVM->cCpus), VERR_TM_VIRTUAL_TICKING_IPE); if (c == 0) { /* When the last TSC stops, remember the value. */ STAM_COUNTER_INC(&pVM->tm.s.StatTSCPause); pVM->tm.s.u64LastPausedTSC = pVCpu->tm.s.u64TSC; } return VINF_SUCCESS; } AssertFailed(); return VERR_TM_TSC_ALREADY_PAUSED; }
/** * MSR write handler for KVM. * * @returns Strict VBox status code like CPUMSetGuestMsr(). * @retval VINF_CPUM_R3_MSR_WRITE * @retval VERR_CPUM_RAISE_GP_0 * * @param pVCpu Pointer to the VMCPU. * @param idMsr The MSR being written. * @param pRange The range this MSR belongs to. * @param uRawValue The raw value with the ignored bits not masked. */ VMM_INT_DECL(VBOXSTRICTRC) gimKvmWriteMsr(PVMCPU pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uRawValue) { NOREF(pRange); PVM pVM = pVCpu->CTX_SUFF(pVM); PGIMKVM pKvm = &pVM->gim.s.u.Kvm; PGIMKVMCPU pKvmCpu = &pVCpu->gim.s.u.KvmCpu; switch (idMsr) { case MSR_GIM_KVM_SYSTEM_TIME: case MSR_GIM_KVM_SYSTEM_TIME_OLD: { bool fEnable = RT_BOOL(uRawValue & MSR_GIM_KVM_SYSTEM_TIME_ENABLE_BIT); #ifdef IN_RING0 gimR0KvmUpdateSystemTime(pVM, pVCpu); return VINF_CPUM_R3_MSR_WRITE; #elif defined(IN_RC) Assert(pVM->cCpus == 1); if (fEnable) { RTCCUINTREG fEFlags = ASMIntDisableFlags(); pKvmCpu->uTsc = TMCpuTickGetNoCheck(pVCpu) | UINT64_C(1); pKvmCpu->uVirtNanoTS = TMVirtualGetNoCheck(pVM) | UINT64_C(1); ASMSetFlags(fEFlags); } return VINF_CPUM_R3_MSR_WRITE; #else /* IN_RING3 */ if (!fEnable) { gimR3KvmDisableSystemTime(pVM); pKvmCpu->u64SystemTimeMsr = uRawValue; return VINF_SUCCESS; } /* Is the system-time struct. already enabled? If so, get flags that need preserving. */ uint8_t fFlags = 0; GIMKVMSYSTEMTIME SystemTime; RT_ZERO(SystemTime); if ( MSR_GIM_KVM_SYSTEM_TIME_IS_ENABLED(pKvmCpu->u64SystemTimeMsr) && MSR_GIM_KVM_SYSTEM_TIME_GUEST_GPA(uRawValue) == pKvmCpu->GCPhysSystemTime) { int rc2 = PGMPhysSimpleReadGCPhys(pVM, &SystemTime, pKvmCpu->GCPhysSystemTime, sizeof(GIMKVMSYSTEMTIME)); if (RT_SUCCESS(rc2)) pKvmCpu->fSystemTimeFlags = (SystemTime.fFlags & GIM_KVM_SYSTEM_TIME_FLAGS_GUEST_PAUSED); } /* Enable and populate the system-time struct. */ pKvmCpu->u64SystemTimeMsr = uRawValue; pKvmCpu->GCPhysSystemTime = MSR_GIM_KVM_SYSTEM_TIME_GUEST_GPA(uRawValue); pKvmCpu->u32SystemTimeVersion += 2; int rc = gimR3KvmEnableSystemTime(pVM, pVCpu); if (RT_FAILURE(rc)) { pKvmCpu->u64SystemTimeMsr = 0; return VERR_CPUM_RAISE_GP_0; } return VINF_SUCCESS; #endif } case MSR_GIM_KVM_WALL_CLOCK: case MSR_GIM_KVM_WALL_CLOCK_OLD: { #ifndef IN_RING3 return VINF_CPUM_R3_MSR_WRITE; #else /* Enable the wall-clock struct. */ RTGCPHYS GCPhysWallClock = MSR_GIM_KVM_WALL_CLOCK_GUEST_GPA(uRawValue); if (RT_LIKELY(RT_ALIGN_64(GCPhysWallClock, 4) == GCPhysWallClock)) { int rc = gimR3KvmEnableWallClock(pVM, GCPhysWallClock); if (RT_SUCCESS(rc)) { pKvm->u64WallClockMsr = uRawValue; return VINF_SUCCESS; } } return VERR_CPUM_RAISE_GP_0; #endif /* IN_RING3 */ } default: { #ifdef IN_RING3 static uint32_t s_cTimes = 0; if (s_cTimes++ < 20) LogRel(("GIM: KVM: Unknown/invalid WrMsr (%#x,%#x`%08x) -> #GP(0)\n", idMsr, uRawValue & UINT64_C(0xffffffff00000000), uRawValue & UINT64_C(0xffffffff))); #endif LogFunc(("Unknown/invalid WrMsr (%#RX32,%#RX64) -> #GP(0)\n", idMsr, uRawValue)); break; } } return VERR_CPUM_RAISE_GP_0; }