9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/* $Id$ */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** @file
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * VBoxDrv - The VirtualBox Support Driver - Common code for GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Copyright (C) 2006-2015 Oracle Corporation
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * available from http://www.virtualbox.org. This file is free software;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * General Public License (GPL) as published by the Free Software
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * The contents of this file may alternatively be used under the terms
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * of the Common Development and Distribution License Version 1.0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * VirtualBox OSE distribution, in which case the provisions of the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * CDDL are applicable instead of those of the GPL.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * You may elect to license modified versions of this file under the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * terms and conditions of either the GPL or the CDDL or both.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/*******************************************************************************
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync* Header Files *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync*******************************************************************************/
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define LOG_GROUP LOG_GROUP_SUP_DRV
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define SUPDRV_AGNOSTIC
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include "SUPDrvInternal.h"
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifndef PAGE_SHIFT
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# include <iprt/param.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/asm.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/asm-amd64-x86.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/asm-math.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/cpuset.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/handletable.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/mem.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/mp.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/power.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/process.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/semaphore.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/spinlock.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/thread.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/uuid.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/net.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/crc.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/string.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/timer.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#if defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# include <iprt/rand.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# include <iprt/path.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/uint128.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <iprt/x86.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <VBox/param.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <VBox/log.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#include <VBox/err.h>
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#if defined(RT_OS_SOLARIS) || defined(RT_OS_DARWIN)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# include "dtrace/SUPDrv.h"
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/* ... */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/*******************************************************************************
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync* Defined Constants And Macros *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync*******************************************************************************/
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The frequency by which we recalculate the u32UpdateHz and
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * u32UpdateIntervalNS GIP members. The value must be a power of 2.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Warning: Bumping this too high might overflow u32UpdateIntervalNS.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_UPDATEHZ_RECALC_FREQ 0x800
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** A reserved TSC value used for synchronization as well as measurement of
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * TSC deltas. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_RSVD UINT64_MAX
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The number of TSC delta measurement loops in total (includes primer and
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * read-time loops). */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_LOOPS 96
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The number of cache primer loops. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_PRIMER_LOOPS 4
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The number of loops until we keep computing the minumum read time. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_READ_TIME_LOOPS 24
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync/** The TSC frequency refinement period in seconds.
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync * The timer fires after 200ms, then every second, this value just says when
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync * to stop it after that. */
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync#define GIP_TSC_REFINE_PERIOD_IN_SECS 12
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 32
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The TSC-delta threshold for the SUPGIPUSETSCDELTA_ROUGHLY_ZERO rating */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#define GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 448
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** The TSC delta value for the initial GIP master - 0 in regular builds.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * To test the delta code this can be set to a non-zero value. */
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync#if 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define GIP_TSC_DELTA_INITIAL_MASTER_VALUE INT64_C(170139095182512) /* 0x00009abd9854acb0 */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define GIP_TSC_DELTA_INITIAL_MASTER_VALUE INT64_C(0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncAssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS < GIP_TSC_DELTA_READ_TIME_LOOPS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncAssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS < GIP_TSC_DELTA_LOOPS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** @def VBOX_SVN_REV
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * The makefile should define this if it can. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifndef VBOX_SVN_REV
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define VBOX_SVN_REV 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#if 0 /* Don't start the GIP timers. Useful when debugging the IPRT timer code. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define DO_NOT_START_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/*******************************************************************************
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync* Internal Functions *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync*******************************************************************************/
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncstatic void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic void supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll);
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync#else
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsyncstatic int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt);
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsyncstatic int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/*******************************************************************************
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync* Global Variables *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync*******************************************************************************/
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncDECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage = NULL;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Misc Common GIP Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Misc Common GIP Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Misc Common GIP Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Finds the GIP CPU index corresponding to @a idCpu.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns GIP CPU array index, UINT32_MAX if not found.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGip The GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic uint32_t supdrvGipFindCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < pGip->cCpus; i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->aCPUs[i].idCpu == idCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return UINT32_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Mapping and Unmapping Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Mapping and Unmapping Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Mapping and Unmapping Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * (Re-)initializes the per-cpu structure prior to starting or resuming the GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * updating.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pGip Pointer to the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pGipCpu The per CPU structure for this CPU.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param u64NanoTS The current time.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic void supdrvGipReInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Here we don't really care about applying the TSC delta. The re-initialization of this
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * value is not relevant especially while (re)starting the GIP as the first few ones will
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * be ignored anyway, see supdrvGipDoUpdateCpu().
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpu->u64TSC = ASMReadTSC() - pGipCpu->u32UpdateIntervalTSC;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpu->u64NanoTS = u64NanoTS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Set the current TSC and NanoTS value for the CPU.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param idCpu The CPU ID. Unused - we have to use the APIC ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pvUser1 Pointer to the ring-0 GIP mapping.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pvUser2 Pointer to the variable holding the current time.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic DECLCALLBACK(void) supdrvGipReInitCpuCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser1;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync unsigned iCpu = pGip->aiCpuFromApicId[ASMGetApicId()];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_LIKELY(iCpu < pGip->cCpus && pGip->aCPUs[iCpu].idCpu == idCpu))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipReInitCpu(pGip, &pGip->aCPUs[iCpu], *(uint64_t *)pvUser2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync NOREF(pvUser2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync NOREF(idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * State structure for supdrvGipDetectGetGipCpuCallback.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef struct SUPDRVGIPDETECTGETCPU
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** Bitmap of APIC IDs that has been seen (initialized to zero).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Used to detect duplicate APIC IDs (paranoia). */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint8_t volatile bmApicId[256 / 8];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** Mask of supported GIP CPU getter methods (SUPGIPGETCPU_XXX) (all bits set
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * initially). The callback clears the methods not detected. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t volatile fSupported;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** The first callback detecting any kind of range issues (initialized to
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * NIL_RTCPUID). */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTCPUID volatile idCpuProblem;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync} SUPDRVGIPDETECTGETCPU;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** Pointer to state structure for supdrvGipDetectGetGipCpuCallback. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef SUPDRVGIPDETECTGETCPU *PSUPDRVGIPDETECTGETCPU;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Checks for alternative ways of getting the CPU ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * This also checks the APIC ID, CPU ID and CPU set index values against the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * GIP tables.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param idCpu The CPU ID. Unused - we have to use the APIC ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pvUser1 Pointer to the state structure.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pvUser2 Pointer to the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic DECLCALLBACK(void) supdrvGipDetectGetGipCpuCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPDRVGIPDETECTGETCPU pState = (PSUPDRVGIPDETECTGETCPU)pvUser1;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t fSupported = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint16_t idApic;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int iCpuSet;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertMsg(idCpu == RTMpCpuId(), ("idCpu=%#x RTMpCpuId()=%#x\n", idCpu, RTMpCpuId())); /* paranoia^3 */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check that the CPU ID and CPU set index are interchangable.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync iCpuSet = RTMpCpuIdToSetIndex(idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ((RTCPUID)iCpuSet == idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( iCpuSet >= 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && iCpuSet < RTCPUSET_MAX_CPUS
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check whether the IDTR.LIMIT contains a CPU number.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef RT_ARCH_X86
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint16_t const cbIdt = sizeof(X86DESC64SYSTEM) * 256;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint16_t const cbIdt = sizeof(X86DESCGATE) * 256;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTIDTR Idtr;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMGetIDTR(&Idtr);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (Idtr.cbIdt >= cbIdt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t uTmp = Idtr.cbIdt - cbIdt;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uTmp &= RTCPUSET_MAX_CPUS - 1;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (uTmp == idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTIDTR Idtr2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMGetIDTR(&Idtr2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (Idtr2.cbIdt == Idtr.cbIdt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync fSupported |= SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check whether RDTSCP is an option.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (ASMHasCpuId())
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( ASMIsValidExtRange(ASMCpuId_EAX(UINT32_C(0x80000000)))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && (ASMCpuId_EDX(UINT32_C(0x80000001)) & X86_CPUID_EXT_FEATURE_EDX_RDTSCP) )
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t uAux;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMReadTscWithAux(&uAux);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMNopPause();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMReadTscWithAux(&uAux);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync fSupported |= SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check that the APIC ID is unique.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idApic = ASMGetApicId();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_LIKELY( idApic < RT_ELEMENTS(pGip->aiCpuFromApicId)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && !ASMAtomicBitTestAndSet(pState->bmApicId, idApic)))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync fSupported |= SUPGIPGETCPU_APIC_ID;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertCompile(sizeof(pState->bmApicId) * 8 == RT_ELEMENTS(pGip->aiCpuFromApicId));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - duplicate APIC ID.\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idCpu, iCpuSet, idApic));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check that the iCpuSet is within the expected range.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_UNLIKELY( iCpuSet < 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || (unsigned)iCpuSet >= RTCPUSET_MAX_CPUS
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || (unsigned)iCpuSet >= RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU set index is out of range.\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idCpu, iCpuSet, idApic));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTCPUID idCpu2 = RTMpCpuIdFromSetIndex(iCpuSet);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_UNLIKELY(idCpu2 != idCpu))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU id/index roundtrip problem: %#x\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idCpu, iCpuSet, idApic, idCpu2));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Update the supported feature mask before we return.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicAndU32(&pState->fSupported, fSupported);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync NOREF(pvUser2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Increase the timer freqency on hosts where this is possible (NT).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * The idea is that more interrupts is better for us... Also, it's better than
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * we increase the timer frequence, because we might end up getting inaccurate
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * callbacks if someone else does it.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pDevExt Sets u32SystemTimerGranularityGrant if increased.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic void supdrvGipRequestHigherTimerFrequencyFromSystem(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->u32SystemTimerGranularityGrant == 0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t u32SystemResolution;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 976563 /* 1024 HZ */, &u32SystemResolution))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 1000000 /* 1000 HZ */, &u32SystemResolution))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 1953125 /* 512 HZ */, &u32SystemResolution))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || RT_SUCCESS_NP(RTTimerRequestSystemGranularity( 2000000 /* 500 HZ */, &u32SystemResolution))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync )
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(RTTimerGetSystemGranularity() <= u32SystemResolution);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->u32SystemTimerGranularityGrant = u32SystemResolution;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Undoes supdrvGipRequestHigherTimerFrequencyFromSystem.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pDevExt Clears u32SystemTimerGranularityGrant.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic void supdrvGipReleaseHigherTimerFrequencyFromSystem(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->u32SystemTimerGranularityGrant)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc2 = RTTimerReleaseSystemGranularity(pDevExt->u32SystemTimerGranularityGrant);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertRC(rc2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->u32SystemTimerGranularityGrant = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Maps the GIP into userspace and/or get the physical address of the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns IPRT status code.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pSession Session to which the GIP mapping should belong.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param ppGipR3 Where to store the address of the ring-3 mapping. (optional)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pHCPhysGip Where to store the physical address. (optional)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @remark There is no reference counting on the mapping, so one call to this function
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * count globally as one reference. One call to SUPR0GipUnmap() is will unmap GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * and remove the session as a GIP user.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncSUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTR3PTR pGipR3 = NIL_RTR3PTR;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTHCPHYS HCPhys = NIL_RTHCPHYS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(("SUPR0GipMap: pSession=%p ppGipR3=%p pHCPhysGip=%p\n", pSession, ppGipR3, pHCPhysGip));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Validate
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertPtrNullReturn(ppGipR3, VERR_INVALID_POINTER);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertPtrNullReturn(pHCPhysGip, VERR_INVALID_POINTER);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemMutexRequest(pDevExt->mtxGip, RT_INDEFINITE_WAIT);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemFastMutexRequest(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->pGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Map it?
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (ppGipR3)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTR0MemObjMapUser(&pSession->GipMapObjR3, pDevExt->GipMemObj, (RTR3PTR)-1, 0,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTMEM_PROT_READ, RTR0ProcHandleSelf());
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipR3 = RTR0MemObjAddressR3(pSession->GipMapObjR3);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Get physical address.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pHCPhysGip && RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync HCPhys = pDevExt->HCPhysGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Reference globally.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (!pSession->fGipReferenced && RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->fGipReferenced = 1;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->cGipUsers++;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->cGipUsers == 1)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGipR0 = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint64_t u64NanoTS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * GIP starts/resumes updating again. On windows we bump the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * host timer frequency to make sure we don't get stuck in guest
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * mode and to get better timer (and possibly clock) accuracy.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(("SUPR0GipMap: Resumes GIP updating\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipRequestHigherTimerFrequencyFromSystem(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * document me
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGipR0->aCPUs[0].u32TransactionId != 2 /* not the first time */)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync unsigned i;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (i = 0; i < pGipR0->cCpus; i++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicUoWriteU32(&pGipR0->aCPUs[i].u32TransactionId,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync (pGipR0->aCPUs[i].u32TransactionId + GIP_UPDATEHZ_RECALC_FREQ * 2)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync & ~(GIP_UPDATEHZ_RECALC_FREQ * 2 - 1));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicWriteU64(&pGipR0->u64NanoTSLastUpdateHz, 0);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * document me
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync u64NanoTS = RTTimeSystemNanoTS() - pGipR0->u32UpdateIntervalNS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( pGipR0->u32Mode == SUPGIPMODE_INVARIANT_TSC
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || pGipR0->u32Mode == SUPGIPMODE_SYNC_TSC
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || RTMpGetOnlineCount() == 1)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipReInitCpu(pGipR0, &pGipR0->aCPUs[0], u64NanoTS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTMpOnAll(supdrvGipReInitCpuCallback, pGipR0, &u64NanoTS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Detect alternative ways to figure the CPU ID in ring-3 and
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * raw-mode context. Check the sanity of the APIC IDs, CPU IDs,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * and CPU set indexes while we're at it.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync SUPDRVGIPDETECTGETCPU DetectState;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RT_BZERO((void *)&DetectState.bmApicId, sizeof(DetectState.bmApicId));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync DetectState.fSupported = UINT32_MAX;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync DetectState.idCpuProblem = NIL_RTCPUID;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTMpOnAll(supdrvGipDetectGetGipCpuCallback, &DetectState, pGipR0);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (DetectState.idCpuProblem == NIL_RTCPUID)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( DetectState.fSupported != UINT32_MAX
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && DetectState.fSupported != 0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGipR0->fGetGipCpu != DetectState.fSupported)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipR0->fGetGipCpu = DetectState.fSupported;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("SUPR0GipMap: fGetGipCpu=%#x\n", DetectState.fSupported));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("SUPR0GipMap: No supported ways of getting the APIC ID or CPU number in ring-3! (%#x)\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync DetectState.fSupported));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_UNSUPPORTED_CPU;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("SUPR0GipMap: APIC ID, CPU ID or CPU set index problem detected on CPU #%u (%#x)!\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync DetectState.idCpuProblem, DetectState.idCpuProblem));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_INVALID_CPU_ID;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Start the GIP timer if all is well..
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifndef DO_NOT_START_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Bail out on error.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_FAILURE(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogRel(("SUPR0GipMap: failed rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->cGipUsers = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->fGipReferenced = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc2 = RTR0MemObjFree(pSession->GipMapObjR3, false); AssertRC(rc2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc2))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->GipMapObjR3 = NIL_RTR0MEMOBJ;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync HCPhys = NIL_RTHCPHYS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipR3 = NIL_RTR3PTR;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_GENERAL_FAILURE;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Log(("SUPR0GipMap: GIP is not available!\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemMutexRelease(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemFastMutexRelease(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Write returns.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pHCPhysGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *pHCPhysGip = HCPhys;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (ppGipR3)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *ppGipR3 = pGipR3;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef DEBUG_DARWIN_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync OSDBGPRINT(("SUPR0GipMap: returns %d *pHCPhysGip=%lx pGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)pGipR3));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(( "SUPR0GipMap: returns %d *pHCPhysGip=%lx pGipR3=%p\n", rc, (unsigned long)HCPhys, (void *)pGipR3));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Unmaps any user mapping of the GIP and terminates all GIP access
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * from this session.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns IPRT status code.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pSession Session to which the GIP mapping should belong.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncSUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPDRVDEVEXT pDevExt = pSession->pDevExt;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef DEBUG_DARWIN_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync OSDBGPRINT(("SUPR0GipUnmap: pSession=%p pGip=%p GipMapObjR3=%p\n",
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->GipMapObjR3 != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pSession->GipMapObjR3) : NULL,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->GipMapObjR3));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(("SUPR0GipUnmap: pSession=%p\n", pSession));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemMutexRequest(pDevExt->mtxGip, RT_INDEFINITE_WAIT);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemFastMutexRequest(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Unmap anything?
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTR0MemObjFree(pSession->GipMapObjR3, false);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertRC(rc);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->GipMapObjR3 = NIL_RTR0MEMOBJ;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Dereference global GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pSession->fGipReferenced && !rc)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pSession->fGipReferenced = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( pDevExt->cGipUsers > 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && !--pDevExt->cGipUsers)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(("SUPR0GipUnmap: Suspends GIP updating\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifndef DO_NOT_START_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTTimerStop(pDevExt->pGipTimer); AssertRC(rc); rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipReleaseHigherTimerFrequencyFromSystem(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemMutexRelease(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTSemFastMutexRelease(pDevExt->mtxGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Gets the GIP pointer.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns Pointer to the GIP or NULL.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncSUPDECL(PSUPGLOBALINFOPAGE) SUPGetGIP(void)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return g_pSUPGlobalInfoPage;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Initialization, Termination and CPU Offline / Online Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Initialization, Termination and CPU Offline / Online Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Initialization, Termination and CPU Offline / Online Related Code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync/**
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * Used by supdrvInitRefineInvariantTscFreqTimer and supdrvGipInitMeasureTscFreq
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * to update the TSC frequency related GIP variables.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync *
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * @param pGip The GIP.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * @param nsElapsed The number of nano seconds elapsed.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * @param cElapsedTscTicks The corresponding number of TSC ticks.
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync * @param iTick The tick number for debugging.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsyncstatic void supdrvGipInitSetCpuFreq(PSUPGLOBALINFOPAGE pGip, uint64_t nsElapsed, uint64_t cElapsedTscTicks, uint32_t iTick)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Calculate the frequency.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t uCpuHz;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if ( cElapsedTscTicks < UINT64_MAX / RT_NS_1SEC
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync && nsElapsed < UINT32_MAX)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uCpuHz = ASMMultU64ByU32DivByU32(cElapsedTscTicks, RT_NS_1SEC, (uint32_t)nsElapsed);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTUINT128U CpuHz, Tmp, Divisor;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync CpuHz.s.Lo = CpuHz.s.Hi = 0;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTUInt128MulU64ByU64(&Tmp, cElapsedTscTicks, RT_NS_1SEC_64);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, nsElapsed));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uCpuHz = CpuHz.s.Lo;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Update the GIP.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ASMAtomicWriteU64(&pGip->u64CpuHz, uCpuHz);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ASMAtomicWriteU64(&pGip->aCPUs[0].u64CpuHz, uCpuHz);
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync /* For inspecting the frequency calcs using tstGIP-2, debugger or similar. */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync if (iTick + 1 < pGip->cCpus)
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync ASMAtomicWriteU64(&pGip->aCPUs[iTick + 1].u64CpuHz, uCpuHz);
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync}
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Timer callback function for TSC frequency refinement in invariant GIP mode.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * This is started during driver init and fires once
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * GIP_TSC_REFINE_PERIOD_IN_SECS seconds later.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pTimer The timer.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser Opaque pointer to the device instance data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The timer tick.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsyncstatic DECLCALLBACK(void) supdrvInitRefineInvariantTscFreqTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTCPUID idCpu;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t cNsElapsed;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t cTscTicksElapsed;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t nsNow;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t uTsc;
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Paranoia. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync AssertReturnVoid(pGip);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync AssertReturnVoid(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync /*
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync * If we got a power event, stop the refinement process.
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync */
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync if (pDevExt->fInvTscRefinePowerEvent)
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync {
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync int rc = RTTimerStop(pTimer); AssertRC(rc);
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync return;
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync }
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync * Read the TSC and time, noting which CPU we are on.
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync *
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync * Don't bother spinning until RTTimeSystemNanoTS changes, since on
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync * systems where it matters we're in a context where we cannot waste that
5acdcd39dfd0adec57d6e85838e999ba952ee49dvboxsync * much time (DPC watchdog, called from clock interrupt).
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync */
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync fEFlags = ASMIntDisableFlags();
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync uTsc = ASMReadTSC();
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync nsNow = RTTimeSystemNanoTS();
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync idCpu = RTMpCpuId();
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync ASMSetFlags(fEFlags);
d2bf529b7f81219efcdc932bee290467a2b04e24vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync cNsElapsed = nsNow - pDevExt->nsStartInvarTscRefine;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync cTscTicksElapsed = uTsc - pDevExt->uTscStartInvarTscRefine;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If the above measurement was taken on a different CPU than the one we
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * started the process on, cTscTicksElapsed will need to be adjusted with
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * the TSC deltas of both the CPUs.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * We ASSUME that the delta calculation process takes less time than the
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * TSC frequency refinement timer. If it doesn't, we'll complain and
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * drop the frequency refinement.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Note! We cannot entirely trust enmUseTscDelta here because it's
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * downgraded after each delta calculation.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if ( idCpu != pDevExt->idCpuInvarTscRefine
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync && pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t iStartCpuSet = RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t iStopCpuSet = RTMpCpuIdToSetIndex(idCpu);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint16_t iStartGipCpu = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint16_t iStopGipCpu = iStopCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet] : UINT16_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int64_t iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int64_t iStopTscDelta = iStopGipCpu < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta : INT64_MAX;
874970279c503ed890db044712b8e5eaa6f6f82avboxsync if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopTscDelta != INT64_MAX))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /* cTscTicksElapsed = (uTsc - iStopTscDelta) - (pDevExt->uTscStartInvarTscRefine - iStartTscDelta); */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync cTscTicksElapsed += iStartTscDelta - iStopTscDelta;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Allow 5 times the refinement period to elapse before we give up on the TSC delta
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * calculations.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync else if (cNsElapsed > GIP_TSC_REFINE_PERIOD_IN_SECS * 5 * RT_NS_1SEC_64)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync SUPR0Printf("vboxdrv: Failed to refine invariant TSC frequency because deltas are unavailable after %u (%u) seconds\n",
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PERIOD_IN_SECS);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync SUPR0Printf("vboxdrv: start: %u, %u, %#llx stop: %u, %u, %#llx\n",
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta);
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync int rc = RTTimerStop(pTimer); AssertRC(rc);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync return;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Calculate and update the CPU frequency variables in GIP.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If there is a GIP user already and we've already refined the frequency
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * a couple of times, don't update it as we want a stable frequency value
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * for all VMs.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if ( pDevExt->cGipUsers == 0
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync || cNsElapsed < RT_NS_1SEC * 2)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
b0deb52d71d46987430324c2e39de46a2791a738vboxsync supdrvGipInitSetCpuFreq(pGip, cNsElapsed, cTscTicksElapsed, (uint32_t)iTick);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync * Stop the timer once we've reached the defined refinement period.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync if (cNsElapsed > GIP_TSC_REFINE_PERIOD_IN_SECS * RT_NS_1SEC_64)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync int rc = RTTimerStop(pTimer);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync AssertRC(rc);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync else
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync {
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync int rc = RTTimerStop(pTimer);
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync AssertRC(rc);
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync/**
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync * @callback_method_impl{FNRTPOWERNOTIFICATION}
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync */
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsyncstatic DECLCALLBACK(void) supdrvGipPowerNotificationCallback(RTPOWEREVENT enmEvent, void *pvUser)
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync{
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync /*
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * If the TSC frequency refinement timer is running, we need to cancel it so it
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * doesn't screw up the frequency after a long suspend.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * Recalculate all TSC-deltas on host resume as it may have changed, seen
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * on Windows 7 running on the Dell Optiplex Intel Core i5-3570.
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (enmEvent == RTPOWEREVENT_RESUME)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync ASMAtomicWriteBool(&pDevExt->fInvTscRefinePowerEvent, true);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if ( RT_LIKELY(pGip)
6f8f54585e02c203bef2e7ec2f59829163fdc971vboxsync && pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED
6f8f54585e02c203bef2e7ec2f59829163fdc971vboxsync && !supdrvOSAreCpusOfflinedOnSuspend())
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync supdrvTscDeltaThreadStartMeasurement(pDevExt, true /* fForceAll */);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync#else
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync RTCpuSetCopy(&pDevExt->TscDeltaCpuSet, &pGip->OnlineCpuSet);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync supdrvMeasureInitialTscDeltas(pDevExt);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync#endif
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync }
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync }
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync else if (enmEvent == RTPOWEREVENT_SUSPEND)
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync ASMAtomicWriteBool(&pDevExt->fInvTscRefinePowerEvent, true);
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync}
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Start the TSC-frequency refinment timer for the invariant TSC GIP mode.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * We cannot use this in the synchronous and asynchronous tsc GIP modes because
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * the CPU may change the TSC frequence between now and when the timer fires
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * (supdrvInitAsyncRefineTscTimer).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param pDevExt Pointer to the device instance data.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param pGip Pointer to the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncstatic void supdrvGipInitStartTimerForRefiningInvariantTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t u64NanoTS;
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync /*
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync * Register a power management callback.
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync */
5cb0813f7ea960345b7bc247add053f4aa5841aavboxsync pDevExt->fInvTscRefinePowerEvent = false;
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync rc = RTPowerNotificationRegister(supdrvGipPowerNotificationCallback, pDevExt);
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync AssertRC(rc); /* ignore */
e3ca1fe5aceb4641ff101c920fc09c74754e3e46vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Record the TSC and NanoTS as the starting anchor point for refinement
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * of the TSC. We try get as close to a clock tick as possible on systems
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * which does not provide high resolution time.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u64NanoTS = RTTimeSystemNanoTS();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync while (RTTimeSystemNanoTS() == u64NanoTS)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMNopPause();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync fEFlags = ASMIntDisableFlags();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pDevExt->uTscStartInvarTscRefine = ASMReadTSC();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pDevExt->nsStartInvarTscRefine = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pDevExt->idCpuInvarTscRefine = RTMpCpuId();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Create a timer that runs on the same CPU so we won't have a depencency
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * on the TSC-delta and can run in parallel to it. On systems that does not
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * implement CPU specific timers we'll apply deltas in the timer callback,
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * just like we do for CPUs going offline.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * The longer the refinement interval the better the accuracy, at least in
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * theory. If it's too long though, ring-3 may already be starting its
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * first VMs before we're done. On most systems we will be loading the
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * support driver during boot and VMs won't be started for a while yet,
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * it is really only a problem during development (especially with
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * on-demand driver starting on windows).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq() call
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * to calculate the frequency during driver loading, the timer is set
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * to fire after 200 ms the first time. It will then reschedule itself
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * to fire every second until GIP_TSC_REFINE_PERIOD_IN_SECS has been
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * reached or it notices that there is a user land client with GIP
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * mapped (we want a stable frequency for all VMs).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, RT_NS_1SEC,
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTTIMER_FLAGS_CPU(RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine)),
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync supdrvInitRefineInvariantTscFreqTimer, pDevExt);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (RT_SUCCESS(rc))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync return;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (rc == VERR_CPU_OFFLINE || rc == VERR_NOT_SUPPORTED)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, RT_NS_1SEC, RTTIMER_FLAGS_CPU_ANY,
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync supdrvInitRefineInvariantTscFreqTimer, pDevExt);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (RT_SUCCESS(rc))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (RT_SUCCESS(rc))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync return;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pDevExt->pInvarTscRefineTimer = NULL;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync OSDBGPRINT(("vboxdrv: Failed to create or start TSC frequency refinement timer: rc=%Rrc\n", rc));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync}
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync/**
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @callback_method_impl{PFNRTMPWORKER,
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * RTMpOnSpecific callback for reading TSC and time on the CPU we started
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * the measurements on.}
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncDECLCALLBACK(void) supdrvGipInitReadTscAndNanoTsOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync{
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags = ASMIntDisableFlags();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t *puTscStop = (uint64_t *)pvUser1;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t *pnsStop = (uint64_t *)pvUser2;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *puTscStop = ASMReadTSC();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *pnsStop = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Measures the TSC frequency of the system.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * The TSC frequency can vary on systems which are not reported as invariant.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * On such systems the object of this function is to find out what the nominal,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * maximum TSC frequency under 'normal' CPU operation.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns VBox status code.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param pDevExt Pointer to the device instance.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param pGip Pointer to the GIP.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param fRough Set if we're doing the rough calculation that the
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * TSC measuring code needs, where accuracy isn't all
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * that important (too high is better than to low).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * When clear we try for best accuracy that we can
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * achieve in reasonably short time.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncstatic int supdrvGipInitMeasureTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, bool fRough)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t nsTimerIncr = RTTimerGetSystemGranularity();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int cTriesLeft = fRough ? 4 : 2;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync while (cTriesLeft-- > 0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t nsStart;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t nsStop;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t uTscStart;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t uTscStop;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTCPUID idCpuStart;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTCPUID idCpuStop;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Synchronize with the host OS clock tick on systems without high
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * resolution time API (older Windows version for example).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync nsStart = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync while (RTTimeSystemNanoTS() == nsStart)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMNopPause();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Read the TSC and current time, noting which CPU we're on.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync fEFlags = ASMIntDisableFlags();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uTscStart = ASMReadTSC();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync nsStart = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync idCpuStart = RTMpCpuId();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Delay for a while.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Sleep-wait since the TSC frequency is constant, it eases host load.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Shorter interval produces more variance in the frequency (esp. Windows).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t msElapsed = 0;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t msDelay = ( ((fRough ? 16 : 200) * RT_NS_1MS + nsTimerIncr - 1) / nsTimerIncr * nsTimerIncr - RT_NS_100US )
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync / RT_NS_1MS;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync do
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTThreadSleep((RTMSINTERVAL)(msDelay - msElapsed));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync nsStop = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync msElapsed = (nsStop - nsStart) / RT_NS_1MS;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync } while (msElapsed < msDelay);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync while (RTTimeSystemNanoTS() == nsStop)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMNopPause();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Busy-wait keeping the frequency up.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync do
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ASMNopPause();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync nsStop = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync } while (nsStop - nsStart < RT_NS_100MS);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Read the TSC and time again.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync fEFlags = ASMIntDisableFlags();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uTscStop = ASMReadTSC();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync nsStop = RTTimeSystemNanoTS();
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync idCpuStop = RTMpCpuId();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If the CPU changes things get a bit complicated and what we
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * can get away with depends on the GIP mode / TSC reliablity.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (idCpuStop != idCpuStart)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync bool fDoXCall = false;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Synchronous TSC mode: we're probably fine as it's unlikely
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * that we were rescheduled because of TSC throttling or power
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * management reasons, so just go ahead.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->u32Mode == SUPGIPMODE_SYNC_TSC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /* Probably ok, maybe we should retry once?. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync Assert(pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_NOT_APPLICABLE);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If we're just doing the rough measurement, do the cross call and
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * get on with things (we don't have deltas!).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else if (fRough)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync fDoXCall = true;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Invariant TSC mode: It doesn't matter if we have delta available
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * for both CPUs. That is not something we can assume at this point.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Note! We cannot necessarily trust enmUseTscDelta here because it's
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * downgraded after each delta calculation and the delta
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * calculations may not be complete yet.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync/** @todo This section of code is never reached atm, consider dropping it later on... */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t iStartCpuSet = RTMpCpuIdToSetIndex(idCpuStart);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t iStopCpuSet = RTMpCpuIdToSetIndex(idCpuStop);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint16_t iStartGipCpu = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint16_t iStopGipCpu = iStopCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet] : UINT16_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int64_t iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int64_t iStopTscDelta = iStopGipCpu < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta : INT64_MAX;
874970279c503ed890db044712b8e5eaa6f6f82avboxsync if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopTscDelta != INT64_MAX))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uTscStart -= iStartTscDelta;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uTscStop -= iStopTscDelta;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Invalid CPU indexes are not caused by online/offline races, so
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * we have to trigger driver load failure if that happens as GIP
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * and IPRT assumptions are busted on this system.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else if (iStopGipCpu >= pGip->cCpus || iStartGipCpu >= pGip->cCpus)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync SUPR0Printf("vboxdrv: Unexpected CPU index in supdrvGipInitMeasureTscFreq.\n");
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync SUPR0Printf("vboxdrv: start: %u, %u, %#llx stop: %u, %u, %#llx\n",
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync return VERR_INVALID_CPU_INDEX;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * No valid deltas. We retry, if we're on our last retry
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * we do the cross call instead just to get a result. The
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * frequency will be refined in a few seconds anyways.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else if (cTriesLeft > 0)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync continue;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync fDoXCall = true;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Asynchronous TSC mode: This is bad as the reason we usually
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * use this mode is to deal with variable TSC frequencies and
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * deltas. So, we need to get the TSC from the same CPU as
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * started it, we also need to keep that CPU busy. So, retry
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * and fall back to the cross call on the last attempt.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync Assert(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (cTriesLeft > 0)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync continue;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync fDoXCall = true;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (fDoXCall)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Try read the TSC and timestamp on the start CPU.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int rc = RTMpOnSpecific(idCpuStart, supdrvGipInitReadTscAndNanoTsOnCpu, &uTscStop, &nsStop);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (RT_FAILURE(rc) && (!fRough || cTriesLeft > 0))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync continue;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Calculate the TSC frequency and update it (shared with the refinement timer).
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
27fcebf3d224cda980acb78bc44349da8cde9d37vboxsync supdrvGipInitSetCpuFreq(pGip, nsStop - nsStart, uTscStop - uTscStart, 0);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync Assert(!fRough);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Finds our (@a idCpu) entry, or allocates a new one if not found.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns Index of the CPU in the cache set.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGip The GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic uint32_t supdrvGipFindOrAllocCpuIndexForCpuId(PSUPGLOBALINFOPAGE pGip, RTCPUID idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t i, cTries;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * ASSUMES that CPU IDs are constant.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < pGip->cCpus; i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->aCPUs[i].idCpu == idCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync cTries = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync do
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < pGip->cCpus; i++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync bool fRc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicCmpXchgSize(&pGip->aCPUs[i].idCpu, idCpu, NIL_RTCPUID, fRc);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (fRc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return i;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync } while (cTries++ < 32);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertReleaseFailed();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return i - 1;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * The calling CPU should be accounted as online, update GIP accordingly.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * This is used by supdrvGipCreate() as well as supdrvGipMpEvent().
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipMpEventOnlineOrInitOnCpu(PSUPDRVDEVEXT pDevExt, RTCPUID idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int iCpuSet = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint16_t idApic = UINT16_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t i = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64NanoTS = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertPtrReturnVoid(pGip);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertRelease(idCpu == RTMpCpuId());
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Assert(pGip->cPossibleCpus == RTMpGetCount());
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Do this behind a spinlock with interrupts disabled as this can fire
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * on all CPUs simultaneously, see @bugref{6110}.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hGipSpinlock);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the globals.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pGip->cPresentCpus, RTMpGetPresentCount());
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pGip->cOnlineCpus, RTMpGetOnlineCount());
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync iCpuSet = RTMpCpuIdToSetIndex(idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (iCpuSet >= 0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Assert(RTCpuSetIsMemberByIndex(&pGip->PossibleCpuSet, iCpuSet));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetAddByIndex(&pGip->OnlineCpuSet, iCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetAddByIndex(&pGip->PresentCpuSet, iCpuSet);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the entry.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u64NanoTS = RTTimeSystemNanoTS() - pGip->u32UpdateIntervalNS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync i = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, pGip->u64CpuHz);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync idApic = ASMGetApicId();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pGip->aCPUs[i].idApic, idApic);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS16(&pGip->aCPUs[i].iCpuSet, (int16_t)iCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteSize(&pGip->aCPUs[i].idCpu, idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the APIC ID and CPU set index mappings.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pGip->aiCpuFromApicId[idApic], i);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pGip->aiCpuFromCpuSetIdx[iCpuSet], i);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /* Add this CPU to this set of CPUs we need to calculate the TSC-delta for. */
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, RTMpCpuIdToSetIndex(idCpu));
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Update the Mp online/offline counter. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pDevExt->cMpOnOffEvents);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /* Commit it. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_ONLINE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hGipSpinlock);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync/**
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * RTMpOnSpecific callback wrapper for supdrvGipMpEventOnlineOrInitOnCpu().
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync *
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * @param idCpu The CPU ID we are running on.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * @param pvUser1 Opaque pointer to the device instance data.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * @param pvUser2 Not used.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync */
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsyncstatic DECLCALLBACK(void) supdrvGipMpEventOnlineCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync{
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync NOREF(pvUser2);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync}
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * The CPU should be accounted as offline, update the GIP accordingly.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * This is used by supdrvGipMpEvent.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipMpEventOffline(PSUPDRVDEVEXT pDevExt, RTCPUID idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int iCpuSet;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned i;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertPtrReturnVoid(pGip);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hGipSpinlock);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync iCpuSet = RTMpCpuIdToSetIndex(idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertReturnVoid(iCpuSet >= 0);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync i = pGip->aiCpuFromCpuSetIdx[iCpuSet];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertReturnVoid(i < pGip->cCpus);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertReturnVoid(pGip->aCPUs[i].idCpu == idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Assert(RTCpuSetIsMemberByIndex(&pGip->PossibleCpuSet, iCpuSet));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetDelByIndex(&pGip->OnlineCpuSet, iCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Update the Mp online/offline counter. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pDevExt->cMpOnOffEvents);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Reset the TSC delta, we will recalculate it lazily. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /* Commit it. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_OFFLINE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hGipSpinlock);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Multiprocessor event notification callback.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * This is used to make sure that the GIP master gets passed on to
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * another CPU. It also updates the associated CPU data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param enmEvent The event.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The cpu it applies to.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser Pointer to the device extension.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync switch (enmEvent)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case RTMPEVENT_ONLINE:
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTThreadPreemptDisable(&PreemptState);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync if (idCpu == RTMpCpuId())
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTThreadPreemptRestore(&PreemptState);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync else
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTThreadPreemptRestore(&PreemptState);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTMpOnSpecific(idCpu, supdrvGipMpEventOnlineCallback, pDevExt, NULL /* pvUser2 */);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /*
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * Recompute TSC-delta for the newly online'd CPU.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync */
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync supdrvTscDeltaThreadStartMeasurement(pDevExt, false /* fForceAll */);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync#else
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync uint32_t iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync supdrvMeasureTscDeltaOne(pDevExt, iCpu);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync#endif
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case RTMPEVENT_OFFLINE:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipMpEventOffline(pDevExt, idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Make sure there is a master GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (enmEvent == RTMPEVENT_OFFLINE)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUID idGipMaster = ASMAtomicReadU32(&pDevExt->idGipMaster);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (idGipMaster == idCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * The GIP master is going offline, find a new one.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync bool fIgnored;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUID idNewGipMaster = NIL_RTCPUID;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUSET OnlineCpus;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTMpGetOnlineSet(&OnlineCpus);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < RTCPUSET_MAX_CPUS; i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RTCpuSetIsMemberByIndex(&OnlineCpus, i))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (idCurCpu != idGipMaster)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync idNewGipMaster = idCurCpu;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Log(("supdrvGipMpEvent: Gip master %#lx -> %#lx\n", (long)idGipMaster, (long)idNewGipMaster));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync NOREF(fIgnored);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * On CPU initialization callback for RTMpOnAll.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser1 The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser2 The GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(void) supdrvGipInitOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* This is good enough, even though it will update some of the globals a
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync bit to much. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipMpEventOnlineOrInitOnCpu((PSUPDRVDEVEXT)pvUser1, idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Callback used by supdrvDetermineAsyncTSC to read the TSC on a CPU.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu Ignored.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser1 Where to put the TSC.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser2 Ignored.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(void) supdrvGipInitDetermineAsyncTscWorker(RTCPUID idCpu, void *pvUser1, void *pvUser2)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
b0deb52d71d46987430324c2e39de46a2791a738vboxsync Assert(RTMpCpuIdToSetIndex(idCpu) == (intptr_t)pvUser2);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU64((uint64_t volatile *)pvUser1, ASMReadTSC());
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Determine if Async GIP mode is required because of TSC drift.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * When using the default/normal timer code it is essential that the time stamp counter
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * (TSC) runs never backwards, that is, a read operation to the counter should return
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * a bigger value than any previous read operation. This is guaranteed by the latest
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * AMD CPUs and by newer Intel CPUs which never enter the C2 state (P4). In any other
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * case we have to choose the asynchronous timer mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param poffMin Pointer to the determined difference between different
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * cores (optional, can be NULL).
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @return false if the time stamp counters appear to be synchronized, true otherwise.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic bool supdrvGipInitDetermineAsyncTsc(uint64_t *poffMin)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Just iterate all the cpus 8 times and make sure that the TSC is
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * ever increasing. We don't bother taking TSC rollover into account.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int iEndCpu = RTMpGetArraySize();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int iCpu;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int cLoops = 8;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync bool fAsync = false;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc = VINF_SUCCESS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t offMax = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t offMin = ~(uint64_t)0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t PrevTsc = ASMReadTSC();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync while (cLoops-- > 0)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (iCpu = 0; iCpu < iEndCpu; iCpu++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t CurTsc;
b0deb52d71d46987430324c2e39de46a2791a738vboxsync rc = RTMpOnSpecific(RTMpCpuIdFromSetIndex(iCpu), supdrvGipInitDetermineAsyncTscWorker,
b0deb52d71d46987430324c2e39de46a2791a738vboxsync &CurTsc, (void *)(uintptr_t)iCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (CurTsc <= PrevTsc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync fAsync = true;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync offMin = offMax = PrevTsc - CurTsc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Log(("supdrvGipInitDetermineAsyncTsc: iCpu=%d cLoops=%d CurTsc=%llx PrevTsc=%llx\n",
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync iCpu, cLoops, CurTsc, PrevTsc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Gather statistics (except the first time). */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (iCpu != 0 || cLoops != 7)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t off = CurTsc - PrevTsc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (off < offMin)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync offMin = off;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (off > offMax)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync offMax = off;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Log2(("%d/%d: off=%llx\n", cLoops, iCpu, off));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Next */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PrevTsc = CurTsc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else if (rc == VERR_NOT_SUPPORTED)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertMsg(rc == VERR_CPU_NOT_FOUND || rc == VERR_CPU_OFFLINE, ("%d\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* broke out of the loop. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (iCpu < iEndCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (poffMin)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *poffMin = offMin; /* Almost RTMpOnSpecific profiling. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Log(("supdrvGipInitDetermineAsyncTsc: returns %d; iEndCpu=%d rc=%d offMin=%llx offMax=%llx\n",
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync fAsync, iEndCpu, rc, offMin, offMax));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("vboxdrv: fAsync=%d offMin=%#lx offMax=%#lx\n", fAsync, (long)offMin, (long)offMax));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#endif
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return fAsync;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * supdrvGipInit() worker that determines the GIP TSC mode.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns The most suitable TSC mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic SUPGIPMODE supdrvGipInitDetermineTscMode(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64DiffCoresIgnored;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t uEAX, uEBX, uECX, uEDX;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Establish whether the CPU advertises TSC as invariant, we need that in
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * a couple of places below.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync bool fInvariantTsc = false;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (ASMHasCpuId())
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uEAX = ASMCpuId_EAX(0x80000000);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (ASMIsValidExtRange(uEAX) && uEAX >= 0x80000007)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uEDX = ASMCpuId_EDX(0x80000007);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (uEDX & X86_CPUID_AMD_ADVPOWER_EDX_TSCINVAR)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync fInvariantTsc = true;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * On single CPU systems, we don't need to consider ASYNC mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RTMpGetCount() <= 1)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return fInvariantTsc ? SUPGIPMODE_INVARIANT_TSC : SUPGIPMODE_SYNC_TSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Allow the user and/or OS specific bits to force async mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (supdrvOSGetForcedAsyncTscMode(pDevExt))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return SUPGIPMODE_ASYNC_TSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Use invariant mode if the CPU says TSC is invariant.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (fInvariantTsc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return SUPGIPMODE_INVARIANT_TSC;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * TSC is not invariant and we're on SMP, this presents two problems:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * (1) There might be a skew between the CPU, so that cpu0
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * returns a TSC that is slightly different from cpu1.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * This screw may be due to (2), bad TSC initialization
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * or slightly different TSC rates.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * (2) Power management (and other things) may cause the TSC
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * to run at a non-constant speed, and cause the speed
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * to be different on the cpus. This will result in (1).
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * If any of the above is detected, we will have to use ASYNC mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* (1). Try check for current differences between the cpus. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (supdrvGipInitDetermineAsyncTsc(&u64DiffCoresIgnored))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return SUPGIPMODE_ASYNC_TSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* (2) If it's an AMD CPU with power management, we won't trust its TSC. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMCpuId(0, &uEAX, &uEBX, &uECX, &uEDX);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( ASMIsValidStdRange(uEAX)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && ASMIsAmdCpuEx(uEBX, uECX, uEDX))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Check for APM support. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uEAX = ASMCpuId_EAX(0x80000000);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (ASMIsValidExtRange(uEAX) && uEAX >= 0x80000007)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uEDX = ASMCpuId_EDX(0x80000007);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (uEDX & 0x3e) /* STC|TM|THERMTRIP|VID|FID. Ignore TS. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return SUPGIPMODE_ASYNC_TSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return SUPGIPMODE_SYNC_TSC;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Initializes per-CPU GIP information.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGip Pointer to the GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pCpu Pointer to which GIP CPU to initalize.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64NanoTS The current nanosecond timestamp.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @param uCpuHz The CPU frequency to set, 0 if the caller doesn't know.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncstatic void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pCpu->u32TransactionId = 2;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pCpu->u64NanoTS = u64NanoTS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pCpu->u64TSC = ASMReadTSC();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pCpu->u64TSCSample = GIP_TSC_DELTA_RSVD;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pCpu->i64TSCDelta = pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED ? INT64_MAX : 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteSize(&pCpu->enmState, SUPGIPCPUSTATE_INVALID);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteSize(&pCpu->idCpu, NIL_RTCPUID);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS16(&pCpu->iCpuSet, -1);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU16(&pCpu->idApic, UINT16_MAX);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * The first time we're called, we don't have a CPU frequency handy,
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * so pretend it's a 4 GHz CPU. On CPUs that are online, we'll get
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * called again and at that point we have a more plausible CPU frequency
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * value handy. The frequency history will also be adjusted again on
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * the 2nd timer callout (maybe we can skip that now?).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (!uCpuHz)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pCpu->u64CpuHz = _4G - 1;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pCpu->u32UpdateIntervalTSC = (uint32_t)((_4G - 1) / pGip->u32UpdateHz);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pCpu->u64CpuHz = uCpuHz;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pCpu->u32UpdateIntervalTSC = (uint32_t)(uCpuHz / pGip->u32UpdateHz);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pCpu->au32TSCHistory[0]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[1]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[2]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[3]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[4]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[5]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[6]
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync = pCpu->au32TSCHistory[7]
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync = pCpu->u32UpdateIntervalTSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Initializes the GIP data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGip Pointer to the read-write kernel mapping of the GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param HCPhys The physical address of the GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64NanoTS The current nanosecond timestamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param uUpdateHz The update frequency.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param uUpdateIntervalNS The update interval in nanoseconds.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param cCpus The CPU count.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64NanoTS, unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync size_t const cbGip = RT_ALIGN_Z(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[cCpus]), PAGE_SIZE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#ifdef DEBUG_DARWIN_GIP
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d cCpus=%u\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz, cCpus));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync LogFlow(("supdrvGipInit: pGip=%p HCPhys=%lx u64NanoTS=%llu uUpdateHz=%d cCpus=%u\n", pGip, (long)HCPhys, u64NanoTS, uUpdateHz, cCpus));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Initialize the structure.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync memset(pGip, 0, cbGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32Version = SUPGLOBALINFOPAGE_VERSION;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32Mode = supdrvGipInitDetermineTscMode(pDevExt);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*|| pGip->u32Mode == SUPGIPMODE_SYNC_TSC */)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->enmUseTscDelta = supdrvOSAreTscDeltasInSync() /* Allow OS override (windows). */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ? SUPGIPUSETSCDELTA_ZERO_CLAIMED : SUPGIPUSETSCDELTA_PRACTICALLY_ZERO /* downgrade later */;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->enmUseTscDelta = SUPGIPUSETSCDELTA_NOT_APPLICABLE;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->cCpus = (uint16_t)cCpus;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->cPages = (uint16_t)(cbGip / PAGE_SIZE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32UpdateHz = uUpdateHz;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32UpdateIntervalNS = uUpdateIntervalNS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->fGetGipCpu = SUPGIPGETCPU_APIC_ID;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetEmpty(&pGip->OnlineCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCpuSetEmpty(&pGip->PresentCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTMpGetSet(&pGip->PossibleCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->cOnlineCpus = RTMpGetOnlineCount();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->cPresentCpus = RTMpGetPresentCount();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->cPossibleCpus = RTMpGetCount();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->idCpuMax = RTMpGetMaxCpuId();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < RT_ELEMENTS(pGip->aiCpuFromApicId); i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aiCpuFromApicId[i] = UINT16_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx); i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aiCpuFromCpuSetIdx[i] = UINT16_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < cCpus; i++)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, 0 /*uCpuHz*/);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Link it to the device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->pGip = pGip;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->HCPhysGip = HCPhys;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cGipUsers = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Creates the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns VBox status code.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pDevExt Instance data. GIP stuff may be updated.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncint VBOXCALL supdrvGipCreate(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTHCPHYS HCPhysGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t u32SystemResolution;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t u32Interval;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t u32MinInterval;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t uMod;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync unsigned cCpus;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync LogFlow(("supdrvGipCreate:\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync /*
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * Assert order.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(pDevExt->u32SystemTimerGranularityGrant == 0);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(pDevExt->GipMemObj == NIL_RTR0MEMOBJ);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(!pDevExt->pGipTimer);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync Assert(pDevExt->mtxGip != NIL_RTSEMMUTEX);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync Assert(pDevExt->mtxTscDelta != NIL_RTSEMMUTEX);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#else
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync Assert(pDevExt->mtxGip != NIL_RTSEMFASTMUTEX);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync Assert(pDevExt->mtxTscDelta != NIL_RTSEMFASTMUTEX);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Check the CPU count.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync cCpus = RTMpGetArraySize();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( cCpus > RTCPUSET_MAX_CPUS
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync || cCpus > 256 /* ApicId is used for the mappings */)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync SUPR0Printf("VBoxDrv: Too many CPUs (%u) for the GIP (max %u)\n", cCpus, RT_MIN(RTCPUSET_MAX_CPUS, 256));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VERR_TOO_MANY_CPUS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Allocate a contiguous set of pages with a default kernel mapping.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTR0MemObjAllocCont(&pDevExt->GipMemObj, RT_UOFFSETOF(SUPGLOBALINFOPAGE, aCPUs[cCpus]), false /*fExecutable*/);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_FAILURE(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync OSDBGPRINT(("supdrvGipCreate: failed to allocate the GIP page. rc=%d\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGip = (PSUPGLOBALINFOPAGE)RTR0MemObjAddress(pDevExt->GipMemObj); AssertPtr(pGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync HCPhysGip = RTR0MemObjGetPagePhysAddr(pDevExt->GipMemObj, 0); Assert(HCPhysGip != NIL_RTHCPHYS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Find a reasonable update interval and initialize the structure.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipRequestHigherTimerFrequencyFromSystem(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** @todo figure out why using a 100Ms interval upsets timekeeping in VMs.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * See @bugref{6710}. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync u32MinInterval = RT_NS_10MS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync u32SystemResolution = RTTimerGetSystemGranularity();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync u32Interval = u32MinInterval;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uMod = u32MinInterval % u32SystemResolution;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (uMod)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync u32Interval += u32SystemResolution - uMod;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Important sanity check...
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_UNLIKELY( pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_ZERO_CLAIMED
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && !supdrvOSGetForcedAsyncTscMode(pDevExt)))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync OSDBGPRINT(("supdrvGipCreate: Host-OS/user claims the TSC-deltas are zero but we detected async. TSC! Bad.\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VERR_INTERNAL_ERROR_2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync /* It doesn't make sense to do TSC-delta detection on systems we detect as async. */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync AssertReturn( pGip->u32Mode != SUPGIPMODE_ASYNC_TSC
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED, VERR_INTERNAL_ERROR_3);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Do the TSC frequency measurements.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If we're in invariant TSC mode, just to a quick preliminary measurement
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * that the TSC-delta measurement code can use to yield cross calls.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If we're in any of the other two modes, neither which require MP init,
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * notifications or deltas for the job, do the full measurement now so
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * that supdrvGipInitOnCpu() can populate the TSC interval and history
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * array with more reasonable values.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /*fRough*/); /* cannot fail */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync supdrvGipInitStartTimerForRefiningInvariantTscFreq(pDevExt, pGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /*fRough*/);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Start TSC-delta measurement thread before we start getting MP
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * events that will try kick it into action (includes the
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * RTMpOnAll/supdrvGipInitOnCpu call below).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = supdrvTscDeltaThreadInit(pDevExt);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Do GIP initialization on all online CPUs. Wake up the
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * TSC-delta thread afterwards.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = RTMpOnAll(supdrvGipInitOnCpu, pDevExt, pGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync supdrvTscDeltaThreadStartMeasurement(pDevExt, true /* fForceAll */);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint16_t iCpu;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Measure the TSC deltas now that we have MP notifications.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync int cTries = 5;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync do
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = supdrvMeasureInitialTscDeltas(pDevExt);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if ( rc != VERR_TRY_AGAIN
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync && rc != VERR_CPU_OFFLINE)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync break;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync } while (--cTries > 0);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync AssertMsg(!pGip->aCPUs[iCpu].i64TSCDelta, ("iCpu=%u %lld mode=%d\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta, pGip->u32Mode));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Create the timer.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * If CPU_ALL isn't supported we'll have to fall back to synchronous mode.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipAsyncTimer, pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (rc == VERR_NOT_SUPPORTED)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n"));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGip->u32Mode = SUPGIPMODE_SYNC_TSC;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipSyncAndInvariantTimer, pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * We're good.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Log(("supdrvGipCreate: %u ns interval.\n", u32Interval));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipReleaseHigherTimerFrequencyFromSystem(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync g_pSUPGlobalInfoPage = pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(!pDevExt->pGipTimer);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /* Releases timer frequency increase too. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync supdrvGipDestroy(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Invalidates the GIP data upon termination.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGip Pointer to the read-write kernel mapping of the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipTerm(PSUPGLOBALINFOPAGE pGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned i;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->u32Magic = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (i = 0; i < pGip->cCpus; i++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aCPUs[i].u64NanoTS = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aCPUs[i].u64TSC = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aCPUs[i].iTSCHistoryHead = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aCPUs[i].u64TSCSample = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGip->aCPUs[i].i64TSCDelta = INT64_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Terminates the GIP.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Instance data. GIP stuff may be updated.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncvoid VBOXCALL supdrvGipDestroy(PSUPDRVDEVEXT pDevExt)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#ifdef DEBUG_DARWIN_GIP
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvGipDestroy: pDevExt=%p pGip=%p pGipTimer=%p GipMemObj=%p\n", pDevExt,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->GipMemObj != NIL_RTR0MEMOBJ ? RTR0MemObjAddress(pDevExt->GipMemObj) : NULL,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->pGipTimer, pDevExt->GipMemObj));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Stop receiving MP notifications before tearing anything else down.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTMpNotificationDeregister(supdrvGipMpEvent, pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Terminate the TSC-delta measurement thread and resources.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvTscDeltaTerm(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Destroy the TSC-refinement timer.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if (pDevExt->pInvarTscRefineTimer)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync pDevExt->pInvarTscRefineTimer = NULL;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Invalid the GIP data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->pGip)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipTerm(pDevExt->pGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->pGip = NULL;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync g_pSUPGlobalInfoPage = NULL;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Destroy the timer and free the GIP memory object.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->pGipTimer)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTTimerDestroy(pDevExt->pGipTimer); AssertRC(rc);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->pGipTimer = NULL;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pDevExt->GipMemObj != NIL_RTR0MEMOBJ)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = RTR0MemObjFree(pDevExt->GipMemObj, true /* free mappings */); AssertRC(rc);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pDevExt->GipMemObj = NIL_RTR0MEMOBJ;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Finally, make sure we've release the system timer resolution request
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * if one actually succeeded and is still pending.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync supdrvGipReleaseHigherTimerFrequencyFromSystem(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Update Timer Related Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Update Timer Related Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * GIP Update Timer Related Code
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Worker routine for supdrvGipUpdate() and supdrvGipUpdatePerCpu() that
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * updates all the per cpu data except the transaction id.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pGipCpu Pointer to the per cpu data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64NanoTS The current time stamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64TSC The current TSC.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The current timer tick.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @remarks Can be called with interrupts disabled!
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipDoUpdateCpu(PSUPDRVDEVEXT pDevExt, PSUPGIPCPU pGipCpu, uint64_t u64NanoTS, uint64_t u64TSC, uint64_t iTick)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64TSCDelta;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t u32UpdateIntervalTSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t u32UpdateIntervalTSCSlack;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned iTSCHistoryHead;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64CpuHz;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t u32TransactionId;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertPtrReturnVoid(pGip);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Delta between this and the previous update. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicUoWriteU32(&pGipCpu->u32PrevUpdateIntervalNS, (uint32_t)(u64NanoTS - pGipCpu->u64NanoTS));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the NanoTS.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU64(&pGipCpu->u64NanoTS, u64NanoTS);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Calc TSC delta.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u64TSCDelta = u64TSC - pGipCpu->u64TSC;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU64(&pGipCpu->u64TSC, u64TSC);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * We don't need to keep realculating the frequency when it's invariant, so
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * the remainder of this function is only for the sync and async TSC modes.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if (pGip->u32Mode != SUPGIPMODE_INVARIANT_TSC)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if (u64TSCDelta >> 32)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta = pGipCpu->u32UpdateIntervalTSC;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync pGipCpu->cErrors++;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * On the 2nd and 3rd callout, reset the history with the current TSC
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * interval since the values entered by supdrvGipInit are totally off.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * The interval on the 1st callout completely unreliable, the 2nd is a bit
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * better, while the 3rd should be most reliable.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /** @todo Could we drop this now that we initializes the history
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * with nominal TSC frequency values? */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32TransactionId = pGipCpu->u32TransactionId;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if (RT_UNLIKELY( ( u32TransactionId == 5
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync || u32TransactionId == 7)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync && ( iTick == 2
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync || iTick == 3) ))
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync unsigned i;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync for (i = 0; i < RT_ELEMENTS(pGipCpu->au32TSCHistory); i++)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync ASMAtomicUoWriteU32(&pGipCpu->au32TSCHistory[i], (uint32_t)u64TSCDelta);
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * Validate the NanoTS deltas between timer fires with an arbitrary threshold of 0.5%.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * Wait until we have at least one full history since the above history reset. The
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * assumption is that the majority of the previous history values will be tolerable.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * See @bugref{6710} comment #67.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /** @todo Could we drop the fuding there now that we initializes the history
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * with nominal TSC frequency values? */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if ( u32TransactionId > 23 /* 7 + (8 * 2) */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync && pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync uint32_t uNanoTsThreshold = pGip->u32UpdateIntervalNS / 200;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if ( pGipCpu->u32PrevUpdateIntervalNS > pGip->u32UpdateIntervalNS + uNanoTsThreshold
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync || pGipCpu->u32PrevUpdateIntervalNS < pGip->u32UpdateIntervalNS - uNanoTsThreshold)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync uint32_t u32;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32 = pGipCpu->au32TSCHistory[0];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32 += pGipCpu->au32TSCHistory[1];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32 += pGipCpu->au32TSCHistory[2];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32 += pGipCpu->au32TSCHistory[3];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32 >>= 2;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta = pGipCpu->au32TSCHistory[4];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta += pGipCpu->au32TSCHistory[5];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta += pGipCpu->au32TSCHistory[6];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta += pGipCpu->au32TSCHistory[7];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta >>= 2;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta += u32;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64TSCDelta >>= 1;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * TSC History.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync Assert(RT_ELEMENTS(pGipCpu->au32TSCHistory) == 8);
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync ASMAtomicWriteU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead);
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync ASMAtomicWriteU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta);
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync *
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * On Windows, we have an occasional (but recurring) sour value that messed up
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * the history but taking only 1 interval reduces the precision overall.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync || pGip->u32UpdateHz >= 1000)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t u32;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u32 = pGipCpu->au32TSCHistory[0];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u32 += pGipCpu->au32TSCHistory[1];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u32 += pGipCpu->au32TSCHistory[2];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u32 += pGipCpu->au32TSCHistory[3];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync u32 >>= 2;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC >>= 2;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC += u32;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC >>= 1;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /* Value chosen for a 2GHz Athlon64 running linux 2.6.10/11. */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync else if (pGip->u32UpdateHz >= 90)
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7];
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC >>= 1;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /* value chosen on a 2GHz thinkpad running windows */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync else
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync {
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync }
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync /*
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync * CpuHz.
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync */
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC);
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync u64CpuHz /= pGip->u32UpdateIntervalNS;
8689d10cc9774b5c64bbfcf02b8ae32e4c321aa6vboxsync ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Updates the GIP.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64NanoTS The current nanosecond timesamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64TSC The current TSC timesamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The current timer tick.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @remarks Can be called with interrupts disabled!
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipUpdate(PSUPDRVDEVEXT pDevExt, uint64_t u64NanoTS, uint64_t u64TSC, RTCPUID idCpu, uint64_t iTick)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Determine the relevant CPU data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGIPCPU pGipCpu;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertPtrReturnVoid(pGip);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGipCpu = &pGip->aCPUs[0];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned iCpu = pGip->aiCpuFromApicId[ASMGetApicId()];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_UNLIKELY(iCpu >= pGip->cCpus))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGipCpu = &pGip->aCPUs[iCpu];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_UNLIKELY(pGipCpu->idCpu != idCpu))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Start update transaction.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* this can happen on win32 if we're taking to long and there are more CPUs around. shouldn't happen though. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pGipCpu->u32TransactionId);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGipCpu->cErrors++;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Recalc the update frequency every 0x800th time.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( pGip->u32Mode != SUPGIPMODE_INVARIANT_TSC /* cuz we're not recalculating the frequency on invariants hosts. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && !(pGipCpu->u32TransactionId & (GIP_UPDATEHZ_RECALC_FREQ * 2 - 2)))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->u64NanoTSLastUpdateHz)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#ifdef RT_ARCH_AMD64 /** @todo fix 64-bit div here to work on x86 linux. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64Delta = u64NanoTS - pGip->u64NanoTSLastUpdateHz;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t u32UpdateHz = (uint32_t)((RT_NS_1SEC_64 * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (u32UpdateHz <= 2000 && u32UpdateHz >= 30)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /** @todo r=ramshankar: Changing u32UpdateHz might screw up TSC frequency
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * calculation on non-invariant hosts if it changes the history decision
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * taken in supdrvGipDoUpdateCpu(). */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64Interval = u64Delta / GIP_UPDATEHZ_RECALC_FREQ;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU32(&pGip->u32UpdateHz, u32UpdateHz);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU32(&pGip->u32UpdateIntervalNS, (uint32_t)u64Interval);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#endif
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteU64(&pGip->u64NanoTSLastUpdateHz, u64NanoTS | 1);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipDoUpdateCpu(pDevExt, pGipCpu, u64NanoTS, u64TSC, iTick);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Complete transaction.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pGipCpu->u32TransactionId);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Updates the per cpu GIP data for the calling cpu.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt The device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64NanoTS The current nanosecond timesamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param u64TSC The current TSC timesamp.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idCpu The CPU ID.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param idApic The APIC id for the CPU index.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The current timer tick.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @remarks Can be called with interrupts disabled!
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvGipUpdatePerCpu(PSUPDRVDEVEXT pDevExt, uint64_t u64NanoTS, uint64_t u64TSC,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUID idCpu, uint8_t idApic, uint64_t iTick)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t iCpu;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Avoid a potential race when a CPU online notification doesn't fire on
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * the onlined CPU but the tick creeps in before the event notification is
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * run.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_UNLIKELY(iTick == 1))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_OFFLINE)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync iCpu = pGip->aiCpuFromApicId[idApic];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_LIKELY(iCpu < pGip->cCpus))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu];
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGipCpu->idCpu == idCpu)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Start update transaction.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (!(ASMAtomicIncU32(&pGipCpu->u32TransactionId) & 1))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync AssertMsgFailed(("Invalid transaction id, %#x, not odd!\n", pGipCpu->u32TransactionId));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pGipCpu->u32TransactionId);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pGipCpu->cErrors++;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Update the data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipDoUpdateCpu(pDevExt, pGipCpu, u64NanoTS, u64TSC, iTick);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Complete transaction.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicIncU32(&pGipCpu->u32TransactionId);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Timer callback function for the sync and invariant GIP modes.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pTimer The timer.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser Opaque pointer to the device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The timer tick.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync uint64_t u64TSC = ASMReadTSC();
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync uint64_t u64NanoTS = RTTimeSystemNanoTS();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * The calculations in supdrvGipUpdate() is somewhat timing sensitive,
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * missing timer ticks is not an option for GIP because the GIP users
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * will end up incrementing the time in 1ns per time getter call until
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * there is a complete timer update. So, if the delta has yet to be
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * calculated, we just pretend it is zero for now (the GIP users
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * probably won't have it for a wee while either and will do the same).
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * We could maybe on some platforms try cross calling a CPU with a
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * working delta here, but it's not worth the hassle since the
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * likelyhood of this happening is really low. On Windows, Linux, and
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * Solaris timers fire on the CPU they were registered/started on.
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * Darwin timers doesn't necessarily (they are high priority threads).
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync uint32_t iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId());
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync uint16_t iGipCpu = RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync ? pGip->aiCpuFromCpuSetIdx[iCpuSet] : UINT16_MAX;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Assert(!ASMIntAreEnabled());
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync if (RT_LIKELY(iGipCpu < pGip->cCpus))
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync {
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync int64_t iTscDelta = pGip->aCPUs[iGipCpu].i64TSCDelta;
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync if (iTscDelta != INT64_MAX)
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync u64TSC -= iTscDelta;
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipUpdate(pDevExt, u64NanoTS, u64TSC, NIL_RTCPUID, iTick);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync ASMSetFlags(fOldFlags);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Timer callback function for async GIP mode.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pTimer The timer.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser Opaque pointer to the device extension.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param iTick The timer tick.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync RTCCUINTREG fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTCPUID idCpu = RTMpCpuId();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t u64TSC = ASMReadTSC();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint64_t NanoTS = RTTimeSystemNanoTS();
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /** @todo reset the transaction number and whatnot when iTick == 1. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->idGipMaster == idCpu)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipUpdate(pDevExt, NanoTS, u64TSC, idCpu, iTick);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvGipUpdatePerCpu(pDevExt, NanoTS, u64TSC, idCpu, ASMGetApicId(), iTick);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMSetFlags(fOldFlags);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * TSC Delta Measurements And Related Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * TSC Delta Measurements And Related Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * TSC Delta Measurements And Related Code
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Select TSC delta measurement algorithm.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
8f507027ddf8199099a107a263964ec7560b1a9evboxsync#if 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define GIP_TSC_DELTA_METHOD_1
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync# define GIP_TSC_DELTA_METHOD_2
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync/** For padding variables to keep them away from other cache lines. Better too
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * large than too small!
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * @remarks Current AMD64 and x86 CPUs seems to use 64 bytes. There are claims
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * that NetBurst had 128 byte cache lines while the 486 thru Pentium
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * III had 32 bytes cache lines. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync#define GIP_TSC_DELTA_CACHE_LINE_SIZE 128
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * TSC delta measurment algorithm \#2 result entry.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef struct SUPDRVTSCDELTAMETHOD2ENTRY
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t iSeqMine;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t iSeqOther;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint64_t uTsc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync} SUPDRVTSCDELTAMETHOD2ENTRY;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * TSC delta measurment algorithm \#2 Data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef struct SUPDRVTSCDELTAMETHOD2
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Padding to make sure the iCurSeqNo is in its own cache line. */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** The current sequence number of this worker. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t volatile iCurSeqNo;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Padding to make sure the iCurSeqNo is in its own cache line. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint32_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint32_t) - 1];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /** Result table. */
8f507027ddf8199099a107a263964ec7560b1a9evboxsync SUPDRVTSCDELTAMETHOD2ENTRY aResults[64];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync} SUPDRVTSCDELTAMETHOD2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/** Pointer to the data for TSC delta mesurment algorithm \#2 .*/
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef SUPDRVTSCDELTAMETHOD2 *PSUPDRVTSCDELTAMETHOD2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync/**
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * The TSC delta synchronization struct, version 2.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync *
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * The syncrhonization variable is completely isolated in its own cache line
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * (provided our max cache line size estimate is correct).
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsynctypedef struct SUPTSCDELTASYNC2
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Padding to make sure the uVar1 is in its own cache line. */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** The synchronization variable, holds values GIP_TSC_DELTA_SYNC_*. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync volatile uint32_t uSyncVar;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /** Sequence synchronizing variable used for post 'GO' synchronization. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync volatile uint32_t uSyncSeq;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Padding to make sure the uVar1 is in its own cache line. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint64_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 2];
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /** Start RDTSC value. Put here mainly to save stack space. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync uint64_t uTscStart;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /** Copy of SUPDRVGIPTSCDELTARGS::cMaxTscTicks. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint64_t cMaxTscTicks;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync} SUPTSCDELTASYNC2;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsyncAssertCompileSize(SUPTSCDELTASYNC2, GIP_TSC_DELTA_CACHE_LINE_SIZE * 2 + sizeof(uint64_t));
87c5113417e917cdf64545d4f8e0a27047cea783vboxsynctypedef SUPTSCDELTASYNC2 *PSUPTSCDELTASYNC2;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** Prestart wait. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT UINT32_C(0x0ffe)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** Prestart aborted. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_PRESTART_ABORT UINT32_C(0x0fff)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** Ready (on your mark). */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_READY UINT32_C(0x1000)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** Steady (get set). */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_STEADY UINT32_C(0x1001)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** Go! */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_GO UINT32_C(0x1002)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync/** Used by the verfication test. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync#define GIP_TSC_DELTA_SYNC2_GO_GO UINT32_C(0x1003)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** We reached the time limit. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_TIMEOUT UINT32_C(0x1ffe)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync/** The other party won't touch the sync struct ever again. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#define GIP_TSC_DELTA_SYNC2_FINAL UINT32_C(0x1fff)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * Argument package/state passed by supdrvMeasureTscDeltaOne() to the RTMpOn
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * callback worker.
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * @todo add
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef struct SUPDRVGIPTSCDELTARGS
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** The device extension. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPDRVDEVEXT pDevExt;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Pointer to the GIP CPU array entry for the worker. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGIPCPU pWorker;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /** Pointer to the GIP CPU array entry for the master. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGIPCPU pMaster;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /** The maximum number of ticks to spend in supdrvMeasureTscDeltaCallback.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * (This is what we need a rough TSC frequency for.) */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync uint64_t cMaxTscTicks;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /** Used to abort synchronization setup. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync bool volatile fAbortSetup;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** Padding to make sure the master variables live in its own cache lines. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
b9efc54979b7ee83352754810d59d75543b474a1vboxsync
b9efc54979b7ee83352754810d59d75543b474a1vboxsync /** @name Master
b9efc54979b7ee83352754810d59d75543b474a1vboxsync * @{ */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync /** The time the master spent in the MP worker. */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync uint64_t cElapsedMasterTscTicks;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync /** The iTry value when stopped at. */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync uint32_t iTry;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync /** Set if the run timed out. */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync bool volatile fTimedOut;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** Pointer to the master's synchronization struct (on stack). */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync PSUPTSCDELTASYNC2 volatile pSyncMaster;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Master data union. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync union
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data (master) for delta verification. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync struct
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Verification test TSC values for the master. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync uint64_t volatile auTscs[32];
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } Verify;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data (master) for measurement method \#2. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync struct
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data and sequence number. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync SUPDRVTSCDELTAMETHOD2 Data;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** The lag setting for the next run. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync bool fLag;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Number of hits. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync uint32_t cHits;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } M2;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } uMaster;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** The verifier verdict, VINF_SUCCESS if ok, VERR_OUT_OF_RANGE if not,
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * VERR_TRY_AGAIN on timeout. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int32_t rcVerify;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** The maximum difference between TSC read during delta verification. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int64_t cMaxVerifyTscTicks;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** The minimum difference between two TSC reads during verification. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int64_t cMinVerifyTscTicks;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** The bad TSC diff, worker relative to master (= worker - master).
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Negative value means the worker is behind the master. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int64_t iVerifyBadTscDiff;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
b9efc54979b7ee83352754810d59d75543b474a1vboxsync /** @} */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync /** Padding to make sure the worker variables live is in its own cache line. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t au64CacheLinePaddingBetween[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
b9efc54979b7ee83352754810d59d75543b474a1vboxsync
b9efc54979b7ee83352754810d59d75543b474a1vboxsync /** @name Proletarian
b9efc54979b7ee83352754810d59d75543b474a1vboxsync * @{ */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** Pointer to the worker's synchronization struct (on stack). */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync PSUPTSCDELTASYNC2 volatile pSyncWorker;
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync /** The time the worker spent in the MP worker. */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync uint64_t cElapsedWorkerTscTicks;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Worker data union. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync union
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data (worker) for delta verification. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync struct
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Verification test TSC values for the worker. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync uint64_t volatile auTscs[32];
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } Verify;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data (worker) for measurement method \#2. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync struct
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** Data and sequence number. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync SUPDRVTSCDELTAMETHOD2 Data;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** The lag setting for the next run (set by master). */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync bool fLag;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } M2;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync } uWorker;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync /** @} */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /** Padding to make sure the above is in its own cache line. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync} SUPDRVGIPTSCDELTARGS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsynctypedef SUPDRVGIPTSCDELTARGS *PSUPDRVGIPTSCDELTARGS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/** @name Macros that implements the basic synchronization steps common to
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * the algorithms.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * Must be used from loop as the timeouts are implemented via 'break' statements
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * at the moment.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync#if defined(DEBUG_bird) /* || defined(VBOX_STRICT) */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync# define TSCDELTA_DBG_VARS() uint32_t iDbgCounter
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync# define TSCDELTA_DBG_START_LOOP() do { iDbgCounter = 0; } while (0)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync# define TSCDELTA_DBG_CHECK_LOOP() \
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync do { iDbgCounter++; if ((iDbgCounter & UINT32_C(0x01ffffff)) == 0) RT_BREAKPOINT(); } while (0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync# define TSCDELTA_DBG_VARS() ((void)0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync# define TSCDELTA_DBG_START_LOOP() ((void)0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync# define TSCDELTA_DBG_CHECK_LOOP() ((void)0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#endif
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#if 0
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG(a_Args) SUPR0Printf a_Args
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG(a_Args) ((void)0)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#endif
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#if 0
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG2(a_Args) SUPR0Printf a_Args
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG2(a_Args) ((void)0)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#endif
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#if 0
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG9(a_Args) SUPR0Printf a_Args
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync# define TSCDELTA_DBG_SYNC_MSG9(a_Args) ((void)0)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#endif
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsyncstatic bool supdrvTscDeltaSync2_Before(PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync,
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync bool fIsMaster, PRTCCUINTREG pfEFlags, PSUPDRVGIPTSCDELTARGS pArgs)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync{
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint32_t iMySeq = fIsMaster ? 0 : 256;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint32_t const iMaxSeq = iMySeq + 16; /* For the last loop, darn linux/freebsd C-ishness. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint32_t u32Tmp;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint32_t iSync2Loops = 0;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync RTCCUINTREG fEFlags;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync TSCDELTA_DBG_VARS();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *pfEFlags = X86_EFL_IF | X86_EFL_1; /* should shut up most nagging compilers. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * The master tells the worker to get on it's mark.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (fIsMaster)
874970279c503ed890db044712b8e5eaa6f6f82avboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_STEADY, GIP_TSC_DELTA_SYNC2_READY)))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { /* likely*/ }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #1 uSyncVar=%#x\n", fIsMaster ? "master" : "worker", pOtherSync->uSyncVar));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync }
874970279c503ed890db044712b8e5eaa6f6f82avboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * Wait for the on your mark signal (ack in the master case). We process timeouts here.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMAtomicWriteU32(&(pMySync)->uSyncSeq, 0);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync for (;;)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync fEFlags = ASMIntDisableFlags();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync u32Tmp = ASMAtomicReadU32(&pMySync->uSyncVar);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (u32Tmp == GIP_TSC_DELTA_SYNC2_STEADY)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync break;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSetFlags(fEFlags);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMNopPause();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /* Abort? */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (u32Tmp != GIP_TSC_DELTA_SYNC2_READY)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #2 u32Tmp=%#x\n", fIsMaster ? "master" : "worker", u32Tmp));
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync return false;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
357175321a45346fc98b70f7644399f412ee9c3evboxsync /* Check for timeouts every so often (not every loop in case RDTSC is
357175321a45346fc98b70f7644399f412ee9c3evboxsync trapping or something). Must check the first time around. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#if 0 /* For debugging the timeout paths. */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync static uint32_t volatile xxx;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#endif
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if ( ( (iSync2Loops & 0x3ff) == 0
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && ASMReadTSC() - pMySync->uTscStart > pMySync->cMaxTscTicks)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#if 0 /* This is crazy, I know, but enable this code and the results are markedly better when enabled on the 1.4GHz AMD (debug). */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync || (!fIsMaster && (++xxx & 0xf) == 0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync#endif
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync )
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /* Try switch our own state into timeout mode so the master cannot tell us to 'GO',
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ignore the timeout if we've got the go ahead already (simpler). */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (ASMAtomicCmpXchgU32(&pMySync->uSyncVar, GIP_TSC_DELTA_SYNC2_TIMEOUT, GIP_TSC_DELTA_SYNC2_READY))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: timeout\n", fIsMaster ? "master" : "worker"));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_TIMEOUT, GIP_TSC_DELTA_SYNC2_STEADY);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync ASMAtomicWriteBool(&pArgs->fTimedOut, true);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
357175321a45346fc98b70f7644399f412ee9c3evboxsync iSync2Loops++;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * Interrupts are now disabled and will remain disabled until we do
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * TSCDELTA_MASTER_SYNC_AFTER / TSCDELTA_OTHER_SYNC_AFTER.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *pfEFlags = fEFlags;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * The worker tells the master that it is on its mark and that the master
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * need to get into position as well.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (!fIsMaster)
874970279c503ed890db044712b8e5eaa6f6f82avboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_STEADY, GIP_TSC_DELTA_SYNC2_READY)))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { /* likely */ }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSetFlags(fEFlags);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #3 uSyncVar=%#x\n", fIsMaster ? "master" : "worker", pOtherSync->uSyncVar));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
874970279c503ed890db044712b8e5eaa6f6f82avboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * The master sends the 'go' to the worker and wait for ACK.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (fIsMaster)
874970279c503ed890db044712b8e5eaa6f6f82avboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO, GIP_TSC_DELTA_SYNC2_STEADY)))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { /* likely */ }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSetFlags(fEFlags);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #4 uSyncVar=%#x\n", fIsMaster ? "master" : "worker", pOtherSync->uSyncVar));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
874970279c503ed890db044712b8e5eaa6f6f82avboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * Wait for the 'go' signal (ack in the master case).
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync TSCDELTA_DBG_START_LOOP();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync for (;;)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync u32Tmp = ASMAtomicReadU32(&pMySync->uSyncVar);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (u32Tmp == GIP_TSC_DELTA_SYNC2_GO)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync break;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_LIKELY(u32Tmp == GIP_TSC_DELTA_SYNC2_STEADY))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { /* likely */ }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSetFlags(fEFlags);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #5 u32Tmp=%#x\n", fIsMaster ? "master" : "worker", u32Tmp));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync TSCDELTA_DBG_CHECK_LOOP();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMNopPause();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * The worker acks the 'go' (shouldn't fail).
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (!fIsMaster)
874970279c503ed890db044712b8e5eaa6f6f82avboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO, GIP_TSC_DELTA_SYNC2_STEADY)))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { /* likely */ }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSetFlags(fEFlags);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/before/%s: #6 uSyncVar=%#x\n", fIsMaster ? "master" : "worker", pOtherSync->uSyncVar));
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return false;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
874970279c503ed890db044712b8e5eaa6f6f82avboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * Try enter mostly lockstep execution with it.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync for (;;)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync uint32_t iOtherSeq1, iOtherSeq2;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMCompilerBarrier();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMSerializeInstruction();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMAtomicWriteU32(&pMySync->uSyncSeq, iMySeq);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMNopPause();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync iOtherSeq1 = ASMAtomicXchgU32(&pOtherSync->uSyncSeq, iMySeq);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMNopPause();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync iOtherSeq2 = ASMAtomicReadU32(&pMySync->uSyncSeq);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMCompilerBarrier();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (iOtherSeq1 == iOtherSeq2)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return true;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /* Did the other guy give up? Should we give up? */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if ( iOtherSeq1 == UINT32_MAX
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync || iOtherSeq2 == UINT32_MAX)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return true;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (++iMySeq >= iMaxSeq)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMAtomicWriteU32(&pMySync->uSyncSeq, UINT32_MAX);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync return true;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync ASMNopPause();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync}
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#define TSCDELTA_MASTER_SYNC_BEFORE(a_pMySync, a_pOtherSync, a_pfEFlags, a_pArgs) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (RT_LIKELY(supdrvTscDeltaSync2_Before(a_pMySync, a_pOtherSync, true /*fIsMaster*/, a_pfEFlags, a_pArgs))) \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync { /*likely*/ } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else if (true) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG9(("sync/before/master: #89\n")); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break; \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } else do {} while (0)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync#define TSCDELTA_OTHER_SYNC_BEFORE(a_pMySync, a_pOtherSync, a_pfEFlags, a_pArgs) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (RT_LIKELY(supdrvTscDeltaSync2_Before(a_pMySync, a_pOtherSync, false /*fIsMaster*/, a_pfEFlags, a_pArgs))) \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync { /*likely*/ } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else if (true) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG9(("sync/before/other: #89\n")); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break; \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } else do {} while (0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsyncstatic bool supdrvTscDeltaSync2_After(PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync,
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync bool fIsMaster, RTCCUINTREG fEFlags)
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync{
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_VARS();
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync /*
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * Wait for the 'ready' signal. In the master's case, this means the
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * worker has completed its data collection, while in the worker's case it
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * means the master is done processing the data and it's time for the next
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * loop iteration (or whatever).
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync ASMSetFlags(fEFlags);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_START_LOOP();
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync for (;;)
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync {
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync uint32_t u32Tmp = ASMAtomicReadU32(&pMySync->uSyncVar);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if ( u32Tmp == GIP_TSC_DELTA_SYNC2_READY
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync || (u32Tmp == GIP_TSC_DELTA_SYNC2_STEADY && !fIsMaster) /* kicked twice => race */ )
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync return true;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync ASMNopPause();
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (RT_LIKELY(u32Tmp == GIP_TSC_DELTA_SYNC2_GO))
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { /* likely */}
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/after/other: #1 u32Tmp=%#x\n", u32Tmp));
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync return false; /* shouldn't ever happen! */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync }
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_CHECK_LOOP();
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync ASMNopPause();
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync }
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync}
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync#define TSCDELTA_MASTER_SYNC_AFTER(a_pMySync, a_pOtherSync, a_fEFlags) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (RT_LIKELY(supdrvTscDeltaSync2_After(a_pMySync, a_pOtherSync, true /*fIsMaster*/, a_fEFlags))) \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync { /* likely */ } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else if (true) \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG9(("sync/after/master: #97\n")); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break; \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } else do {} while (0)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#define TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(a_pMySync, a_pOtherSync) \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync /* \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync * Tell the worker that we're done processing the data and ready for the next round. \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync */ \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&(a_pOtherSync)->uSyncVar, GIP_TSC_DELTA_SYNC2_READY, GIP_TSC_DELTA_SYNC2_GO))) \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync { /* likely */ } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else if (true)\
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/after/master: #99 uSyncVar=%#x\n", (a_pOtherSync)->uSyncVar)); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break; \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } else do {} while (0)
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync#define TSCDELTA_OTHER_SYNC_AFTER(a_pMySync, a_pOtherSync, a_fEFlags) \
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync if (true) { \
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /* \
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * Tell the master that we're done collecting data and wait for the next round to start. \
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */ \
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync if (RT_LIKELY(ASMAtomicCmpXchgU32(&(a_pOtherSync)->uSyncVar, GIP_TSC_DELTA_SYNC2_READY, GIP_TSC_DELTA_SYNC2_GO))) \
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync { /* likely */ } \
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync else \
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync { \
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(a_fEFlags); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/after/other: #0 uSyncVar=%#x\n", (a_pOtherSync)->uSyncVar)); \
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync break; \
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (RT_LIKELY(supdrvTscDeltaSync2_After(a_pMySync, a_pOtherSync, false /*fIsMaster*/, a_fEFlags))) \
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync { /* likely */ } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync else \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync { \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG9(("sync/after/other: #98\n")); \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break; \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } \
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync } else do {} while (0)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/** @} */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync#ifdef GIP_TSC_DELTA_METHOD_1
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/**
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * TSC delta measurment algorithm \#1 (GIP_TSC_DELTA_METHOD_1).
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * We ignore the first few runs of the loop in order to prime the
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * cache. Also, we need to be careful about using 'pause' instruction
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * in critical busy-wait loops in this code - it can cause undesired
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * behaviour with hyperthreading.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * We try to minimize the measurement error by computing the minimum
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * read time of the compare statement in the worker by taking TSC
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * measurements across it.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * It must be noted that the computed minimum read time is mostly to
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * eliminate huge deltas when the worker is too early and doesn't by
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * itself help produce more accurate deltas. We allow two times the
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * computed minimum as an arbibtrary acceptable threshold. Therefore,
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * it is still possible to get negative deltas where there are none
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * when the worker is earlier. As long as these occasional negative
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * deltas are lower than the time it takes to exit guest-context and
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * the OS to reschedule EMT on a different CPU we won't expose a TSC
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * that jumped backwards. It is because of the existence of the
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * negative deltas we don't recompute the delta with the master and
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * worker interchanged to eliminate the remaining measurement error.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param pArgs The argument/state data.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * @param pMySync My synchronization structure.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * @param pOtherSync My partner's synchronization structure.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param fIsMaster Set if master, clear if worker.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param iTry The attempt number.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsyncstatic void supdrvTscDeltaMethod1Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync,
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync bool fIsMaster, uint32_t iTry)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync PSUPGIPCPU pGipCpuWorker = pArgs->pWorker;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync PSUPGIPCPU pGipCpuMaster = pArgs->pMaster;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint64_t uMinCmpReadTime = UINT64_MAX;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync unsigned iLoop;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync NOREF(iTry);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync for (iLoop = 0; iLoop < GIP_TSC_DELTA_LOOPS; iLoop++)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (fIsMaster)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The master.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync AssertMsg(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD,
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ("%#llx idMaster=%#x idWorker=%#x (idGipMaster=%#x)\n",
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pGipCpuMaster->u64TSCSample, pGipCpuMaster->idCpu, pGipCpuWorker->idCpu, pArgs->pDevExt->idGipMaster));
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_MASTER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync do
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, ASMReadTSC());
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_MASTER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* Process the data. */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (iLoop > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (pGipCpuWorker->u64TSCSample != GIP_TSC_DELTA_RSVD)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync int64_t iDelta = pGipCpuWorker->u64TSCSample
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync - (pGipCpuMaster->u64TSCSample - pGipCpuMaster->i64TSCDelta);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if ( iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ? iDelta < pGipCpuWorker->i64TSCDelta
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync : iDelta > pGipCpuWorker->i64TSCDelta || pGipCpuWorker->i64TSCDelta == INT64_MAX)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pGipCpuWorker->i64TSCDelta = iDelta;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* Reset our TSC sample and tell the worker to move on. */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, GIP_TSC_DELTA_RSVD);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pMySync, pOtherSync);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The worker.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint64_t uTscWorker;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint64_t uTscWorkerFlushed;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint64_t uCmpReadTime;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicReadU64(&pGipCpuMaster->u64TSCSample); /* Warm the cache line. */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_OTHER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * Keep reading the TSC until we notice that the master has read his. Reading
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * the TSC -after- the master has updated the memory is way too late. We thus
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * compensate by trying to measure how long it took for the worker to notice
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * the memory flushed from the master.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync do
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uTscWorker = ASMReadTSC();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uTscWorkerFlushed = ASMReadTSC();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uCmpReadTime = uTscWorkerFlushed - uTscWorker;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (iLoop > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* This is totally arbitrary a.k.a I don't like it but I have no better ideas for now. */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (uCmpReadTime < (uMinCmpReadTime << 1))
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU64(&pGipCpuWorker->u64TSCSample, uTscWorker);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (uCmpReadTime < uMinCmpReadTime)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uMinCmpReadTime = uCmpReadTime;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync else
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU64(&pGipCpuWorker->u64TSCSample, GIP_TSC_DELTA_RSVD);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync else if (iLoop > GIP_TSC_DELTA_PRIMER_LOOPS)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (uCmpReadTime < uMinCmpReadTime)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uMinCmpReadTime = uCmpReadTime;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_OTHER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG9(("sync/method1loop/%s: #92 iLoop=%u MyState=%#x\n", fIsMaster ? "master" : "worker", iLoop,
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync pMySync->uSyncVar));
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * We must reset the worker TSC sample value in case it gets picked as a
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * GIP master later on (it's trashed above, naturally).
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (!fIsMaster)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU64(&pGipCpuWorker->u64TSCSample, GIP_TSC_DELTA_RSVD);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync#endif /* GIP_TSC_DELTA_METHOD_1 */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync#ifdef GIP_TSC_DELTA_METHOD_2
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * TSC delta measurement algorithm \#2 configuration and code - Experimental!!
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
8f507027ddf8199099a107a263964ec7560b1a9evboxsync# define GIP_TSC_DELTA_M2_LOOPS (7 + GIP_TSC_DELTA_M2_PRIMER_LOOPS)
8f507027ddf8199099a107a263964ec7560b1a9evboxsync# define GIP_TSC_DELTA_M2_PRIMER_LOOPS 0
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsyncstatic void supdrvTscDeltaMethod2ProcessDataOnMaster(PSUPDRVGIPTSCDELTARGS pArgs, uint32_t iLoop)
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync{
b9efc54979b7ee83352754810d59d75543b474a1vboxsync int64_t iMasterTscDelta = pArgs->pMaster->i64TSCDelta;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync int64_t iBestDelta = pArgs->pWorker->i64TSCDelta;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync uint32_t idxResult;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync uint32_t cHits = 0;
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync /*
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync * Look for matching entries in the master and worker tables.
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync */
b9efc54979b7ee83352754810d59d75543b474a1vboxsync for (idxResult = 0; idxResult < RT_ELEMENTS(pArgs->uMaster.M2.Data.aResults); idxResult++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
b9efc54979b7ee83352754810d59d75543b474a1vboxsync uint32_t idxOther = pArgs->uMaster.M2.Data.aResults[idxResult].iSeqOther;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (idxOther & 1)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idxOther >>= 1;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync if (idxOther < RT_ELEMENTS(pArgs->uWorker.M2.Data.aResults))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
b9efc54979b7ee83352754810d59d75543b474a1vboxsync if (pArgs->uWorker.M2.Data.aResults[idxOther].iSeqOther == pArgs->uMaster.M2.Data.aResults[idxResult].iSeqMine)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int64_t iDelta;
b9efc54979b7ee83352754810d59d75543b474a1vboxsync iDelta = pArgs->uWorker.M2.Data.aResults[idxOther].uTsc
b9efc54979b7ee83352754810d59d75543b474a1vboxsync - (pArgs->uMaster.M2.Data.aResults[idxResult].uTsc - iMasterTscDelta);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ? iDelta < iBestDelta
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync : iDelta > iBestDelta || iBestDelta == INT64_MAX)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync iBestDelta = iDelta;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync cHits++;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync /*
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync * Save the results.
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync */
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync if (cHits > 2)
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync pArgs->pWorker->i64TSCDelta = iBestDelta;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.M2.cHits += cHits;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/**
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The core function of the 2nd TSC delta mesurment algorithm.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The idea here is that we have the two CPUs execute the exact same code
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * collecting a largish set of TSC samples. The code has one data dependency on
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * the other CPU which intention it is to synchronize the execution as well as
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync * help cross references the two sets of TSC samples (the sequence numbers).
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The @a fLag parameter is used to modify the execution a tiny bit on one or
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * both of the CPUs. When @a fLag differs between the CPUs, it is thought that
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * it will help with making the CPUs enter lock step execution occationally.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsyncstatic void supdrvTscDeltaMethod2CollectData(PSUPDRVTSCDELTAMETHOD2 pMyData, uint32_t volatile *piOtherSeqNo, bool fLag)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync{
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync SUPDRVTSCDELTAMETHOD2ENTRY *pEntry = &pMyData->aResults[0];
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint32_t cLeft = RT_ELEMENTS(pMyData->aResults);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicWriteU32(&pMyData->iCurSeqNo, 0);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync while (cLeft-- > 0)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint64_t uTsc;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint32_t iSeqMine = ASMAtomicIncU32(&pMyData->iCurSeqNo);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uint32_t iSeqOther = ASMAtomicReadU32(piOtherSeqNo);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMCompilerBarrier();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction(); /* Way better result than with ASMMemoryFenceSSE2() in this position! */
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync uTsc = ASMReadTSC();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMAtomicIncU32(&pMyData->iCurSeqNo);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMCompilerBarrier();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pEntry->iSeqMine = iSeqMine;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pEntry->iSeqOther = iSeqOther;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pEntry->uTsc = uTsc;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync pEntry++;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMSerializeInstruction();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (fLag)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync ASMNopPause();
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync}
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync/**
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * TSC delta measurment algorithm \#2 (GIP_TSC_DELTA_METHOD_2).
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * See supdrvTscDeltaMethod2CollectData for algorithm details.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync *
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param pArgs The argument/state data.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * @param pMySync My synchronization structure.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * @param pOtherSync My partner's synchronization structure.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param fIsMaster Set if master, clear if worker.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * @param iTry The attempt number.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsyncstatic void supdrvTscDeltaMethod2Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync,
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync bool fIsMaster, uint32_t iTry)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync{
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync unsigned iLoop;
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync for (iLoop = 0; iLoop < GIP_TSC_DELTA_M2_LOOPS; iLoop++)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync if (fIsMaster)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * Adjust the loop lag fudge.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync# if GIP_TSC_DELTA_M2_PRIMER_LOOPS > 0
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync if (iLoop < GIP_TSC_DELTA_M2_PRIMER_LOOPS)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* Lag during the priming to be nice to everyone.. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.M2.fLag = true;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.M2.fLag = true;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync else
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync# endif
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync if (iLoop < (GIP_TSC_DELTA_M2_LOOPS - GIP_TSC_DELTA_M2_PRIMER_LOOPS) / 4)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* 25 % of the body without lagging. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.M2.fLag = false;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.M2.fLag = false;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync else if (iLoop < (GIP_TSC_DELTA_M2_LOOPS - GIP_TSC_DELTA_M2_PRIMER_LOOPS) / 4 * 2)
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* 25 % of the body with both lagging. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.M2.fLag = true;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.M2.fLag = true;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync else
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /* 50% of the body with alternating lag. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.M2.fLag = (iLoop & 1) == 0;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.M2.fLag= (iLoop & 1) == 1;
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * Sync up with the worker and collect data.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_MASTER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync supdrvTscDeltaMethod2CollectData(&pArgs->uMaster.M2.Data, &pArgs->uWorker.M2.Data.iCurSeqNo, pArgs->uMaster.M2.fLag);
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_MASTER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * Process the data.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync# if GIP_TSC_DELTA_M2_PRIMER_LOOPS > 0
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync if (iLoop >= GIP_TSC_DELTA_M2_PRIMER_LOOPS)
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync# endif
dc45a8f3e936581748c248e00ce572cfe3ea331evboxsync supdrvTscDeltaMethod2ProcessDataOnMaster(pArgs, iLoop);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pMySync, pOtherSync);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync else
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync {
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync /*
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync * The worker.
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_OTHER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync supdrvTscDeltaMethod2CollectData(&pArgs->uWorker.M2.Data, &pArgs->uMaster.M2.Data.iCurSeqNo, pArgs->uWorker.M2.fLag);
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_OTHER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync }
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync}
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif /* GIP_TSC_DELTA_METHOD_2 */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsyncstatic int supdrvTscDeltaVerify(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync,
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, int64_t iWorkerTscDelta)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync{
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync /*PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; - unused */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync PSUPGIPCPU pGipCpuMaster = pArgs->pMaster;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint32_t i;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_VARS();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync for (;;)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync AssertCompile((RT_ELEMENTS(pArgs->uMaster.Verify.auTscs) & 1) == 0);
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync AssertCompile(RT_ELEMENTS(pArgs->uMaster.Verify.auTscs) == RT_ELEMENTS(pArgs->uWorker.Verify.auTscs));
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (fIsMaster)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t uTscWorker;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_MASTER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Collect TSC, master goes first.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync for (i = 0; i < RT_ELEMENTS(pArgs->uMaster.Verify.auTscs); i += 2)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Read, kick & wait #1. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t register uTsc = ASMReadTSC();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO_GO);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMSerializeInstruction();
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.Verify.auTscs[i] = uTsc;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_START_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_CHECK_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMNopPause();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Read, kick & wait #2. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uTsc = ASMReadTSC();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMSerializeInstruction();
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uMaster.Verify.auTscs[i + 1] = uTsc;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_START_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO_GO)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_CHECK_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMNopPause();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_MASTER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Process the data.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMaxVerifyTscTicks = INT64_MIN;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMinVerifyTscTicks = INT64_MAX;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->iVerifyBadTscDiff = 0;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteS32(&pArgs->rcVerify, VINF_SUCCESS);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uTscWorker = 0;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync for (i = 0; i < RT_ELEMENTS(pArgs->uMaster.Verify.auTscs); i++)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Master vs previous worker entry. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync uint64_t uTscMaster = pArgs->uMaster.Verify.auTscs[i] - pGipCpuMaster->i64TSCDelta;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int64_t iDiff;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (i > 0)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync iDiff = uTscMaster - uTscWorker;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff > pArgs->cMaxVerifyTscTicks)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMaxVerifyTscTicks = iDiff;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff < pArgs->cMinVerifyTscTicks)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMinVerifyTscTicks = iDiff;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff < 0)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->iVerifyBadTscDiff = -iDiff;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteS32(&pArgs->rcVerify, VERR_OUT_OF_RANGE);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync break;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Worker vs master. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync uTscWorker = pArgs->uWorker.Verify.auTscs[i] - iWorkerTscDelta;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync iDiff = uTscWorker - uTscMaster;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff > pArgs->cMaxVerifyTscTicks)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMaxVerifyTscTicks = iDiff;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff < pArgs->cMinVerifyTscTicks)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->cMinVerifyTscTicks = iDiff;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (iDiff < 0)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#ifdef TSCDELTA_VERIFY_WITH_STATS
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync pArgs->iVerifyBadTscDiff = iDiff;
3a3aa7a4d81818decb78355caff674e6c616ef85vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteS32(&pArgs->rcVerify, VERR_OUT_OF_RANGE);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync break;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Done. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pMySync, pOtherSync);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync else
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * The worker, master leads.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_OTHER_SYNC_BEFORE(pMySync, pOtherSync, &fEFlags, pArgs);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync for (i = 0; i < RT_ELEMENTS(pArgs->uWorker.Verify.auTscs); i += 2)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uint64_t register uTsc;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Wait, Read and Kick #1. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_START_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_CHECK_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMNopPause();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uTsc = ASMReadTSC();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO_GO);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMSerializeInstruction();
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.Verify.auTscs[i] = uTsc;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /* Wait, Read and Kick #2. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_START_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO_GO)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync TSCDELTA_DBG_CHECK_LOOP();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMNopPause();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync uTsc = ASMReadTSC();
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMSerializeInstruction();
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->uWorker.Verify.auTscs[i + 1] = uTsc;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync TSCDELTA_OTHER_SYNC_AFTER(pMySync, pOtherSync, fEFlags);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync return pArgs->rcVerify;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Timed out, please retry.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteS32(&pArgs->rcVerify, VERR_TRY_AGAIN);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync return VERR_TIMEOUT;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync}
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync/**
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Handles the special abort procedure during synchronization setup in
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * supdrvMeasureTscDeltaCallbackUnwrapped().
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync *
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * @returns 0 (dummy, ignored)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * @param pArgs Pointer to argument/state data.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * @param pMySync Pointer to my sync structure.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * @param fIsMaster Set if we're the master, clear if worker.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * @param fTimeout Set if it's a timeout.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsyncDECL_NO_INLINE(static, int)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsyncsupdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, bool fIsMaster, bool fTimeout)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync{
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPTSCDELTASYNC2 volatile *ppMySync = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPTSCDELTASYNC2 volatile *ppOtherSync = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_VARS();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /*
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * Clear our sync pointer and make sure the abort flag is set.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteNullPtr(ppMySync);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteBool(&pArgs->fAbortSetup, true);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (fTimeout)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync ASMAtomicWriteBool(&pArgs->fTimedOut, true);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /*
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * Make sure the other party is out of there and won't be touching our
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * sync state again (would cause stack corruption).
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_START_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync while (ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2) != NULL)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_CHECK_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync }
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return 0;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync}
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * This is used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * and compute the delta between them.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * To reduce code size a good when timeout handling was added, a dummy return
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * value had to be added (saves 1-3 lines per timeout case), thus this
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * 'Unwrapped' function and the dummy 0 return value.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync *
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * @returns 0 (dummy, ignored)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param idCpu The CPU we are current scheduled on.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * @param pArgs Pointer to a parameter package.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @remarks Measuring TSC deltas between the CPUs is tricky because we need to
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * read the TSC at exactly the same time on both the master and the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * worker CPUs. Due to DMA, bus arbitration, cache locality,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * contention, SMI, pipelining etc. there is no guaranteed way of
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * doing this on x86 CPUs.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsyncstatic int supdrvMeasureTscDeltaCallbackUnwrapped(RTCPUID idCpu, PSUPDRVGIPTSCDELTARGS pArgs)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPDRVDEVEXT pDevExt = pArgs->pDevExt;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGIPCPU pGipCpuWorker = pArgs->pWorker;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGIPCPU pGipCpuMaster = pArgs->pMaster;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync bool const fIsMaster = idCpu == pGipCpuMaster->idCpu;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync uint32_t iTry;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPTSCDELTASYNC2 volatile *ppMySync = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPTSCDELTASYNC2 volatile *ppOtherSync = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync SUPTSCDELTASYNC2 MySync;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPTSCDELTASYNC2 pOtherSync;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync int rc;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_VARS();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /* A bit of paranoia first. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (!pGipCpuMaster || !pGipCpuWorker)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * If the CPU isn't part of the measurement, return immediately.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync if ( !fIsMaster
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && idCpu != pGipCpuWorker->idCpu)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync /*
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync * Set up my synchronization stuff and wait for the other party to show up.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync *
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * We don't wait forever since the other party may be off fishing (offline,
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * spinning with ints disables, whatever), we must play nice to the rest of
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * the system as this context generally isn't one in which we will get
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * preempted and we may hold up a number of lower priority interrupts.
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWritePtr(ppMySync, &MySync);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync MySync.uTscStart = ASMReadTSC();
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync MySync.cMaxTscTicks = pArgs->cMaxTscTicks;
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /* Look for the partner, might not be here yet... Special abort considerations. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync iTry = 0;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_START_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync while ((pOtherSync = ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2)) == NULL)
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if ( ASMAtomicReadBool(&pArgs->fAbortSetup)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync || !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu) )
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if ( (iTry++ & 0xff) == 0
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_CHECK_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync }
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /* I found my partner, waiting to be found... Special abort considerations. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if (fIsMaster)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_READY, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* parnaoia */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync iTry = 0;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_START_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync while (ASMAtomicReadU32(&MySync.uSyncVar) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if (ASMAtomicReadBool(&pArgs->fAbortSetup))
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if ( (iTry++ & 0xff) == 0
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if ( fIsMaster
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync && !ASMAtomicCmpXchgU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_ABORT, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT))
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync break; /* race #1: slave has moved on, handle timeout in loop instead. */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_CHECK_LOOP();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if (!fIsMaster)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_READY, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* race #1 */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync/** @todo Add a resumable state to pArgs so we don't waste time if we time
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * out or something. Timeouts are legit, any of the two CPUs may get
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * interrupted. */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Start by seeing if we have a zero delta between the two CPUs.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * This should normally be the case.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync rc = supdrvTscDeltaVerify(pArgs, &MySync, pOtherSync, fIsMaster, GIP_TSC_DELTA_INITIAL_MASTER_VALUE);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (fIsMaster)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, GIP_TSC_DELTA_INITIAL_MASTER_VALUE);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * If the verification didn't time out, do regular delta measurements.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * We retry this until we get a reasonable value.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync else if (rc != VERR_TIMEOUT)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync Assert(pGipCpuWorker->i64TSCDelta == INT64_MAX);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync for (iTry = 0; iTry < 12; iTry++)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync /*
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync * Check the state before we start.
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync uint32_t u32Tmp = ASMAtomicReadU32(&MySync.uSyncVar);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if ( u32Tmp != GIP_TSC_DELTA_SYNC2_READY
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync && (fIsMaster || u32Tmp != GIP_TSC_DELTA_SYNC2_STEADY) /* worker may be late prepping for the next round */ )
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/loop/%s: #0 iTry=%u MyState=%#x\n", fIsMaster ? "master" : "worker", iTry, u32Tmp));
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync break;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync }
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync * Do the measurements.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#ifdef GIP_TSC_DELTA_METHOD_1
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync supdrvTscDeltaMethod1Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#elif defined(GIP_TSC_DELTA_METHOD_2)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync supdrvTscDeltaMethod2Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#else
c9c755c35cd95c006f7ecdb07f2fa8d64686ae3dvboxsync# error "huh??"
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync /*
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync * Check the state.
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync u32Tmp = ASMAtomicReadU32(&MySync.uSyncVar);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if ( u32Tmp != GIP_TSC_DELTA_SYNC2_READY
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync && (fIsMaster || u32Tmp != GIP_TSC_DELTA_SYNC2_STEADY) /* worker may be late prepping for the next round */ )
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync if (fIsMaster)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG(("sync/loop/master: #1 iTry=%u MyState=%#x\n", iTry, u32Tmp));
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync else
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG2(("sync/loop/worker: #1 iTry=%u MyState=%#x\n", iTry, u32Tmp));
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break;
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync }
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync /*
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync * Success? If so, stop trying. Master decides.
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync */
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (fIsMaster)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync {
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync {
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync TSCDELTA_DBG_SYNC_MSG2(("sync/loop/master: #9 iTry=%u MyState=%#x\n", iTry, MySync.uSyncVar));
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync break;
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync if (fIsMaster)
6e1cd642b67bf605db524a9919e28138aeaedba9vboxsync pArgs->iTry = iTry;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /*
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * End the synchroniziation dance. We tell the other that we're done,
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * then wait for the same kind of reply.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_FINAL);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteNullPtr(ppMySync);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync iTry = 0;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_START_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync while (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_FINAL)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync iTry++;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if ( iTry == 0
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync && !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu))
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync break; /* this really shouldn't happen. */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync TSCDELTA_DBG_CHECK_LOOP();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMNopPause();
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync }
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync /*
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync * Collect some runtime stats.
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync */
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync if (fIsMaster)
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync pArgs->cElapsedMasterTscTicks = ASMReadTSC() - MySync.uTscStart;
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync else
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync pArgs->cElapsedWorkerTscTicks = ASMReadTSC() - MySync.uTscStart;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync return 0;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * and compute the delta between them.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * @param idCpu The CPU we are current scheduled on.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * @param pvUser1 Pointer to a parameter package (SUPDRVGIPTSCDELTARGS).
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync * @param pvUser2 Unused.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsyncstatic DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync supdrvMeasureTscDeltaCallbackUnwrapped(idCpu, (PSUPDRVGIPTSCDELTARGS)pvUser1);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Measures the TSC delta between the master GIP CPU and one specified worker
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * CPU.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns VBox status code.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @retval VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED on pure measurement
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * failure.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pDevExt Pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param idxWorker The index of the worker CPU from the GIP's array of
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * CPUs.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @remarks This must be called with preemption enabled!
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncstatic int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync int rc2;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync RTCPUID idMaster = pDevExt->idGipMaster;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGIPCPU pGipCpuMaster;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t iGipCpuMaster;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /* Validate input a bit. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(pGip, VERR_INVALID_PARAMETER);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(RTThreadPreemptIsEnabled(NIL_RTTHREAD));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Don't attempt measuring the delta for the GIP master.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGipCpuWorker->idCpu == idMaster)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGipCpuWorker->i64TSCDelta == INT64_MAX) /* This shouldn't happen, but just in case. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, GIP_TSC_DELTA_INITIAL_MASTER_VALUE);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync /*
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * One measurement at at time, at least for now. We might be using
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * broadcast IPIs so, so be nice to the rest of the system.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync rc = RTSemMutexRequest(pDevExt->mtxTscDelta, RT_INDEFINITE_WAIT);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#else
874970279c503ed890db044712b8e5eaa6f6f82avboxsync rc = RTSemFastMutexRequest(pDevExt->mtxTscDelta);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#endif
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync if (RT_FAILURE(rc))
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync return rc;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * If the CPU has hyper-threading and the APIC IDs of the master and worker are adjacent,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * try pick a different master. (This fudge only works with multi core systems.)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * ASSUMES related threads have adjacent APIC IDs. ASSUMES two threads per core.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * We skip this on AMDs for now as their HTT is different from intel's and
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * it doesn't seem to have any favorable effect on the results.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync *
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * If the master is offline, we need a new master too, so share the code.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync iGipCpuMaster = supdrvGipFindCpuIndexForCpuId(pGip, idMaster);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(iGipCpuMaster < pGip->cCpus, VERR_INVALID_CPU_ID);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpuMaster = &pGip->aCPUs[iGipCpuMaster];
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if ( ( (pGipCpuMaster->idApic & ~1) == (pGipCpuWorker->idApic & ~1)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && ASMHasCpuId()
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && ASMIsValidStdRange(ASMCpuId_EAX(0))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_HTT)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && !ASMIsAmdCpu()
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && pGip->cOnlineCpus > 2)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync || !RTMpIsCpuOnline(idMaster) )
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t i;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (i = 0; i < pGip->cCpus; i++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( i != iGipCpuMaster
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && i != idxWorker
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].enmState == SUPGIPCPUSTATE_ONLINE
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].i64TSCDelta != INT64_MAX
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].idCpu != NIL_RTCPUID
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].idCpu != idMaster /* paranoia starts here... */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].idCpu != pGipCpuWorker->idCpu
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && pGip->aCPUs[i].idApic != pGipCpuWorker->idApic
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && pGip->aCPUs[i].idApic != pGipCpuMaster->idApic
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync && RTMpIsCpuOnline(pGip->aCPUs[i].idCpu))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync iGipCpuMaster = i;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpuMaster = &pGip->aCPUs[i];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idMaster = pGipCpuMaster->idCpu;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpuWorker->iCpuSet))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
e413b055bbccf1f99a47bcf7ef49846ca02781a1vboxsync * Initialize data package for the RTMpOnPair callback.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)RTMemAllocZ(sizeof(*pArgs));
81c6115ff3bb02e166ee8f762d30c4ba5e3db08avboxsync if (pArgs)
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync {
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync pArgs->pWorker = pGipCpuWorker;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync pArgs->pMaster = pGipCpuMaster;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync pArgs->pDevExt = pDevExt;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync pArgs->pSyncMaster = NULL;
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync pArgs->pSyncWorker = NULL;
b0deb52d71d46987430324c2e39de46a2791a738vboxsync pArgs->cMaxTscTicks = ASMAtomicReadU64(&pGip->u64CpuHz) / 512; /* 1953 us */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /*
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * Do the RTMpOnPair call. We reset i64TSCDelta first so we
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * and supdrvMeasureTscDeltaCallback can use it as a success check.
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** @todo Store the i64TSCDelta result in pArgs first? Perhaps deals with
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * that when doing the restart loop reorg. */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync rc = RTMpOnPair(pGipCpuMaster->idCpu, pGipCpuWorker->idCpu, RTMPON_F_CONCURRENT_EXEC,
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync supdrvMeasureTscDeltaCallback, pArgs, NULL);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync#if 0
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync SUPR0Printf("mponpair ticks: %9llu %9llu max: %9llu iTry: %u%s\n", pArgs->cElapsedMasterTscTicks,
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->cElapsedWorkerTscTicks, pArgs->cMaxTscTicks, pArgs->iTry,
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->fTimedOut ? " timed out" :"");
fcaae7b928d7e61427e8b624046a785507e5a3b6vboxsync#endif
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync#if 0
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync SUPR0Printf("rcVerify=%d iVerifyBadTscDiff=%lld cMinVerifyTscTicks=%lld cMaxVerifyTscTicks=%lld\n",
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync pArgs->rcVerify, pArgs->iVerifyBadTscDiff, pArgs->cMinVerifyTscTicks, pArgs->cMaxVerifyTscTicks);
ea0f9836d9efcee2e0cabf403a61d6310939c310vboxsync#endif
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX))
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /*
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * Work the TSC delta applicability rating. It starts
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync * optimistic in supdrvGipInit, we downgrade it here.
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync */
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync SUPGIPUSETSCDELTA enmRating;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO)
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync enmRating = SUPGIPUSETSCDELTA_NOT_ZERO;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO)
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync else
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO;
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync if (pGip->enmUseTscDelta < enmRating)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t));
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync else
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
ccf651c487e8410e36b2bd79a406a202c02c417fvboxsync /** @todo return try-again if we get an offline CPU error. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync RTMemFree(pArgs);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync }
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync else
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync rc = VERR_NO_MEMORY;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_CPU_OFFLINE;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync /*
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync * We're done now.
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync */
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#ifdef SUPDRV_USE_MUTEX_FOR_GIP
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync rc2 = RTSemMutexRelease(pDevExt->mtxTscDelta); AssertRC(rc2);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#else
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync rc2 = RTSemFastMutexRelease(pDevExt->mtxTscDelta); AssertRC(rc2);
d5dbc72216583ef566ba070ac5613e0bca155f82vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync/**
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * Resets the TSC-delta related TSC samples and optionally the deltas
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * themselves.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param pDevExt Pointer to the device instance data.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param fResetTscDeltas Whether the TSC-deltas are also to be reset.
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @remarks This might be called while holding a spinlock!
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic void supdrvTscResetSamples(PSUPDRVDEVEXT pDevExt, bool fResetTscDeltas)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync{
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync unsigned iCpu;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync {
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu];
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (fResetTscDeltas)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpu->iCpuSet);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync }
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync }
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync}
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * Picks an online CPU as the master TSC for TSC-delta computations.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns VBox status code.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param pDevExt Pointer to the device instance data.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param pidxMaster Where to store the CPU array index of the chosen
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * master. Optional, can be NULL.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic int supdrvTscPickMaster(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Pick the first CPU online as the master TSC and make it the new GIP master based
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * on the APIC ID.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Technically we can simply use "idGipMaster" but doing this gives us master as CPU 0
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * in most cases making it nicer/easier for comparisons. It is safe to update the GIP
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * master as this point since the sync/async timer isn't created yet.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync unsigned iCpu;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync uint32_t idxMaster = UINT32_MAX;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (iCpu = 0; iCpu < RT_ELEMENTS(pGip->aiCpuFromApicId); iCpu++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint16_t idxCpu = pGip->aiCpuFromApicId[iCpu];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (idxCpu != UINT16_MAX)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGIPCPU pGipCpu = &pGip->aCPUs[idxCpu];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpu->iCpuSet))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync idxMaster = idxCpu;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpu->i64TSCDelta = GIP_TSC_DELTA_INITIAL_MASTER_VALUE;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpu->idCpu);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (pidxMaster)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync *pidxMaster = idxMaster;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync return VERR_CPU_OFFLINE;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync}
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync/**
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * Performs the initial measurements of the TSC deltas between CPUs.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * This is called by supdrvGipCreate(), supdrvGipPowerNotificationCallback() or
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * triggered by it if threaded.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @returns VBox status code.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param pDevExt Pointer to the device instance data.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync *
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @remarks Must be called only after supdrvGipInitOnCpu() as this function uses
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * idCpu, GIP's online CPU set which are populated in
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * supdrvGipInitOnCpu().
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync{
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPGIPCPU pGipCpuMaster;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync unsigned iCpu;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync unsigned iOddEven;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync uint32_t idxMaster = UINT32_MAX;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync uint32_t cMpOnOffEvents = ASMAtomicReadU32(&pDevExt->cMpOnOffEvents);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync supdrvTscResetSamples(pDevExt, true /* fClearDeltas */);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync int rc = supdrvTscPickMaster(pDevExt, &idxMaster);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (RT_FAILURE(rc))
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync SUPR0Printf("Failed to pick a CPU master for TSC-delta measurements rc=%Rrc\n", rc);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync return rc;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync }
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync AssertReturn(idxMaster < pGip->cCpus, VERR_INVALID_CPU_INDEX);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpuMaster = &pGip->aCPUs[idxMaster];
d5d73d91f3aba093b9737fc51ccf3c7a31501d80vboxsync Assert(pDevExt->idGipMaster == pGipCpuMaster->idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * If there is only a single CPU online we have nothing to do.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGip->cOnlineCpus <= 1)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(pGip->cOnlineCpus > 0, VERR_INTERNAL_ERROR_5);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Loop thru the GIP CPU array and get deltas for each CPU (except the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * master). We do the CPUs with the even numbered APIC IDs first so that
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * we've got alternative master CPUs to pick from on hyper-threaded systems.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (iOddEven = 0; iOddEven < 2; iOddEven++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if ( iCpu != idxMaster
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && (iOddEven > 0 || (pGipCpuWorker->idApic & 1) == 0)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && RTCpuSetIsMemberByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_FAILURE(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu,
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (ASMAtomicReadU32(&pDevExt->cMpOnOffEvents) != cMpOnOffEvents)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync SUPR0Printf("One or more CPUs transitioned between online & offline states. I'm confused, retry...\n");
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_TRY_AGAIN;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Switches the TSC-delta measurement thread into the butchered state.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns VBox status code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param fSpinlockHeld Whether the TSC-delta spinlock is held or not.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pszFailed An error message to log.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param rcFailed The error code to exit the thread with.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic int supdrvTscDeltaThreadButchered(PSUPDRVDEVEXT pDevExt, bool fSpinlockHeld, const char *pszFailed, int rcFailed)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (!fSpinlockHeld)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Butchered;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaThreadButchered: %s. rc=%Rrc\n", rcFailed));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return rcFailed;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * The TSC-delta measurement thread.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns VBox status code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param hThread The thread handle.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pvUser Opaque pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic DECLCALLBACK(int) supdrvTscDeltaThread(RTTHREAD hThread, void *pvUser)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync uint32_t cConsecutiveTimeouts = 0;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc = VERR_INTERNAL_ERROR_2;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (;;)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Switch on the current state.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync SUPDRVTSCDELTATHREADSTATE enmState;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync enmState = pDevExt->enmTscDeltaThreadState;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync switch (enmState)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_Creating:
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Listening;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTSemEventSignal(pDevExt->hTscDeltaEvent);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_FAILURE(rc))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* fall thru */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_Listening:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Simple adaptive timeout. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (cConsecutiveTimeouts++ == 10)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->cMsTscDeltaTimeout == 1) /* 10 ms */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cMsTscDeltaTimeout = 10;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else if (pDevExt->cMsTscDeltaTimeout == 10) /* +100 ms */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cMsTscDeltaTimeout = 100;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else if (pDevExt->cMsTscDeltaTimeout == 100) /* +1000 ms */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cMsTscDeltaTimeout = 500;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync cConsecutiveTimeouts = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTThreadUserWait(pDevExt->hTscDeltaThread, pDevExt->cMsTscDeltaTimeout);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( RT_FAILURE(rc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && rc != VERR_TIMEOUT)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return supdrvTscDeltaThreadButchered(pDevExt, false /* fSpinlockHeld */, "RTThreadUserWait", rc);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTThreadUserReset(pDevExt->hTscDeltaThread);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_WaitAndMeasure:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Measuring;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTSemEventSignal(pDevExt->hTscDeltaEvent); /* (Safe on windows as long as spinlock isn't IRQ safe.) */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_FAILURE(rc))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "RTSemEventSignal", rc);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cMsTscDeltaTimeout = 1;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTThreadSleep(1);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* fall thru */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_Measuring:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync cConsecutiveTimeouts = 0;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (pDevExt->fTscThreadRecomputeAllDeltas)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int cTries = 8;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int cMsWaitPerTry = 10;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync Assert(pGip);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync do
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync RTCpuSetCopy(&pDevExt->TscDeltaCpuSet, &pGip->OnlineCpuSet);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = supdrvMeasureInitialTscDeltas(pDevExt);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( RT_SUCCESS(rc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync || ( RT_FAILURE(rc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && rc != VERR_TRY_AGAIN
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && rc != VERR_CPU_OFFLINE))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTThreadSleep(cMsWaitPerTry);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync } while (cTries-- > 0);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync pDevExt->fTscThreadRecomputeAllDeltas = false;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync unsigned iCpu;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Measure TSC-deltas only for the CPUs that are in the set. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VINF_SUCCESS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RTCpuSetIsMemberByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (pGipCpuWorker->i64TSCDelta == INT64_MAX)
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync int rc2 = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync rc = rc2;
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync else
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync {
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync /*
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * The thread/someone must've called SUPR0TscDeltaMeasureBySetIndex(),
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync * mark the delta as fine to get the timer thread off our back.
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync */
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
ddcb64df779903f563ad28b5b018bcf94ba22a56vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Listening;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync Assert(rc != VERR_NOT_AVAILABLE); /* VERR_NOT_AVAILABLE is used as init value, see supdrvTscDeltaThreadInit(). */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS32(&pDevExt->rcTscDelta, rc);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_Terminating:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Destroyed;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync case kTscDeltaThreadState_Butchered:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync default:
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return supdrvTscDeltaThreadButchered(pDevExt, true /* fSpinlockHeld */, "Invalid state", VERR_INVALID_STATE);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Waits for the TSC-delta measurement thread to respond to a state change.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns VINF_SUCCESS on success, VERR_TIMEOUT if it doesn't respond in time,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * other error code on internal error.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pThis Pointer to the grant service instance data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param enmCurState The current state.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param enmNewState The new state we're waiting for it to enter.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic int supdrvTscDeltaThreadWait(PSUPDRVDEVEXT pDevExt, SUPDRVTSCDELTATHREADSTATE enmCurState,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync SUPDRVTSCDELTATHREADSTATE enmNewState)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Wait a short while for the expected state transition.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSemEventWait(pDevExt->hTscDeltaEvent, RT_MS_1SEC);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->enmTscDeltaThreadState == enmNewState)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else if (pDevExt->enmTscDeltaThreadState == enmCurState)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Wait longer if the state has not yet transitioned to the one we want.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTSemEventWait(pDevExt->hTscDeltaEvent, 50 * RT_MS_1SEC);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( RT_SUCCESS(rc)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync || rc == VERR_TIMEOUT)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /*
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Check the state whether we've succeeded.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync SUPDRVTSCDELTATHREADSTATE enmState;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync enmState = pDevExt->enmTscDeltaThreadState;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (enmState == enmNewState)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VINF_SUCCESS;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else if (enmState == enmCurState)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VERR_TIMEOUT;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaThreadWait: timed out state transition. enmState=%d enmNewState=%d\n", enmState,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync enmNewState));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VERR_INTERNAL_ERROR;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaThreadWait: invalid state transition from %d to %d, expected %d\n", enmCurState,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync enmState, enmNewState));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaThreadWait: RTSemEventWait failed. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaThreadWait: invalid state transition from %d to %d\n", enmCurState, enmNewState));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = VERR_INTERNAL_ERROR;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * Signals the TSC-delta thread to start measuring TSC-deltas.
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync *
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * @param pDevExt Pointer to the device instance data.
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync * @param fForceAll Force re-calculating TSC-deltas on all CPUs.
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync */
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsyncstatic void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt, bool fForceAll)
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync{
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (pDevExt->hTscDeltaThread != NIL_RTTHREAD)
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync {
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync if (fForceAll)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync pDevExt->fTscThreadRecomputeAllDeltas = true;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync }
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync else if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_WaitAndMeasure
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync && fForceAll)
b07cf09ce59f674b9c085bcd7ae77927cd551804vboxsync pDevExt->fTscThreadRecomputeAllDeltas = true;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync RTThreadUserSignal(pDevExt->hTscDeltaThread);
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync }
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync}
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync/**
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync * Terminates the actual thread running supdrvTscDeltaThread().
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync *
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync * This is an internal worker function for supdrvTscDeltaThreadInit() and
ece539e847eaf73e9a1910b562d998dc0afc5580vboxsync * supdrvTscDeltaTerm().
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvTscDeltaThreadTerminate(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Terminating;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTThreadUserSignal(pDevExt->hTscDeltaThread);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTThreadWait(pDevExt->hTscDeltaThread, 50 * RT_MS_1SEC, NULL /* prc */);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_FAILURE(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync /* Signal a few more times before giving up. */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int cTriesLeft = 5;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync while (--cTriesLeft > 0)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTThreadUserSignal(pDevExt->hTscDeltaThread);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTThreadWait(pDevExt->hTscDeltaThread, 2 * RT_MS_1SEC, NULL /* prc */);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (rc != VERR_TIMEOUT)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync break;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Initializes and spawns the TSC-delta measurement thread.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * A thread is required for servicing re-measurement requests from events like
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * CPUs coming online, suspend/resume etc. as it cannot be done synchronously
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * under all contexts on all OSs.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @returns VBox status code.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @remarks Must only be called -after- initializing GIP and setting up MP
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * notifications!
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync int rc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync Assert(pDevExt->pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck");
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTSemEventCreate(&pDevExt->hTscDeltaEvent);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_Creating;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->cMsTscDeltaTimeout = 1;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = RTThreadCreate(&pDevExt->hTscDeltaThread, supdrvTscDeltaThread, pDevExt, 0 /* cbStack */,
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "VBoxTscThread");
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync rc = supdrvTscDeltaThreadWait(pDevExt, kTscDeltaThreadState_Creating, kTscDeltaThreadState_Listening);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (RT_SUCCESS(rc))
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS32(&pDevExt->rcTscDelta, VERR_NOT_AVAILABLE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return rc;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaInit: supdrvTscDeltaThreadWait failed. rc=%Rrc\n", rc));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvTscDeltaThreadTerminate(pDevExt);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaInit: RTThreadCreate failed. rc=%Rrc\n", rc));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSemEventDestroy(pDevExt->hTscDeltaEvent);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->hTscDeltaEvent = NIL_RTSEMEVENT;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaInit: RTSemEventCreate failed. rc=%Rrc\n", rc));
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockDestroy(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->hTscDeltaSpinlock = NIL_RTSPINLOCK;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync else
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync OSDBGPRINT(("supdrvTscDeltaInit: RTSpinlockCreate failed. rc=%Rrc\n", rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * Terminates the TSC-delta measurement thread and cleanup.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync * @param pDevExt Pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsyncstatic void supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if ( pDevExt->hTscDeltaSpinlock != NIL_RTSPINLOCK
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync && pDevExt->hTscDeltaEvent != NIL_RTSEMEVENT)
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync supdrvTscDeltaThreadTerminate(pDevExt);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->hTscDeltaSpinlock != NIL_RTSPINLOCK)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSpinlockDestroy(pDevExt->hTscDeltaSpinlock);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->hTscDeltaSpinlock = NIL_RTSPINLOCK;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync if (pDevExt->hTscDeltaEvent != NIL_RTSEMEVENT)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync RTSemEventDestroy(pDevExt->hTscDeltaEvent);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync pDevExt->hTscDeltaEvent = NIL_RTSEMEVENT;
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync ASMAtomicWriteS32(&pDevExt->rcTscDelta, VERR_NOT_AVAILABLE);
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
50671c30431539dd7d6ff6a5f2ceb6c9f9f471b2vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Measure the TSC delta for the CPU given by its CPU set index.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns VBox status code.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @retval VERR_INTERRUPTED if interrupted while waiting.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @retval VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED if we were unable to get a
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * measurment.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @retval VERR_CPU_OFFLINE if the specified CPU is offline.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync *
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param pSession The caller's session. GIP must've been mapped.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param iCpuSet The CPU set index of the CPU to measure.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param fFlags Flags, SUP_TSCDELTA_MEASURE_F_XXX.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param cMsWaitRetry Number of milliseconds to wait between each retry.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param cMsWaitThread Number of milliseconds to wait for the thread to get
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * ready.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param cTries Number of times to try, pass 0 for the default.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsyncSUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags,
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync PSUPDRVDEVEXT pDevExt;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync PSUPGLOBALINFOPAGE pGip;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint16_t iGipCpu;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync int rc;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint64_t msTsStartWait;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint32_t iWaitLoop;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync#endif
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Validate and adjust the input.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (!pSession->fGipReferenced)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VERR_WRONG_ORDER;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync pDevExt = pSession->pDevExt;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertReturn(SUP_IS_DEVEXT_VALID(pDevExt), VERR_INVALID_PARAMETER);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGip = pDevExt->pGip;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertPtrReturn(pGip, VERR_INTERNAL_ERROR_2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertReturn(iCpuSet < RTCPUSET_MAX_CPUS, VERR_INVALID_CPU_INDEX);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertReturn(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx), VERR_INVALID_CPU_INDEX);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet];
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertReturn(iGipCpu < pGip->cCpus, VERR_INVALID_CPU_INDEX);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (fFlags & ~SUP_TSCDELTA_MEASURE_F_VALID_MASK)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VERR_INVALID_FLAGS;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /*
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync * The request is a noop if the TSC delta isn't being used.
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync */
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync return VINF_SUCCESS;
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (cTries == 0)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cTries = 12;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync else if (cTries > 256)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cTries = 256;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if (cMsWaitRetry == 0)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync cMsWaitRetry = 2;
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync else if (cMsWaitRetry > 1000)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cMsWaitRetry = 1000;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync#ifdef SUPDRV_USE_TSC_DELTA_THREAD
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Has the TSC already been measured and we're not forced to redo it?
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if ( pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync && !(fFlags & SUP_TSCDELTA_MEASURE_F_FORCE))
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VINF_SUCCESS;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Asynchronous request? Forward it to the thread, no waiting.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (fFlags & SUP_TSCDELTA_MEASURE_F_ASYNC)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /** @todo Async. doesn't implement options like retries, waiting. We'll need
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * to pass those options to the thread somehow and implement it in the
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * thread. Check if anyone uses/needs fAsync before implementing this. */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync rc = VINF_SUCCESS;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync }
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync else if (pDevExt->enmTscDeltaThreadState != kTscDeltaThreadState_WaitAndMeasure)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync rc = VERR_THREAD_IS_DEAD;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTThreadUserSignal(pDevExt->hTscDeltaThread);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VINF_SUCCESS;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * If a TSC-delta measurement request is already being serviced by the thread,
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * wait 'cTries' times if a retry-timeout is provided, otherwise bail as busy.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync msTsStartWait = RTTimeSystemMilliTS();
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync for (iWaitLoop = 0;; iWaitLoop++)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint64_t cMsElapsed;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync SUPDRVTSCDELTATHREADSTATE enmState;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync enmState = pDevExt->enmTscDeltaThreadState;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (enmState == kTscDeltaThreadState_Measuring)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync { /* Must wait, the thread is busy. */ }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync else if (enmState == kTscDeltaThreadState_WaitAndMeasure)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync { /* Must wait, this state only says what will happen next. */ }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync else if (enmState == kTscDeltaThreadState_Terminating)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync { /* Must wait, this state only says what should happen next. */ }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync else
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync break; /* All other states, the thread is either idly listening or dead. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /* Wait or fail. */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (cMsWaitThread == 0)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cMsElapsed = RTTimeSystemMilliTS() - msTsStartWait;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (cMsElapsed >= cMsWaitThread)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
87c5113417e917cdf64545d4f8e0a27047cea783vboxsync rc = RTThreadSleep(RT_MIN((RTMSINTERVAL)(cMsWaitThread - cMsElapsed), RT_MIN(iWaitLoop + 1, 10)));
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (rc == VERR_INTERRUPTED)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return rc;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync#endif /* SUPDRV_USE_TSC_DELTA_THREAD */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Try measure the TSC delta the given number of times.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync for (;;)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /* Unless we're forced to measure the delta, check whether it's done already. */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if ( !(fFlags & SUP_TSCDELTA_MEASURE_F_FORCE)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync && pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync rc = VINF_SUCCESS;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync break;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /* Measure it. */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (rc != VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync {
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /* Retry? */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (cTries <= 1)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync break;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cTries--;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync /* Always delay between retries (be nice to the rest of the system
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync and avoid the BSOD hounds). */
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync rc = RTThreadSleep(cMsWaitRetry);
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync if (rc == VERR_INTERRUPTED)
6f34d825e07e8dcd535b37d7685ab62220a23addvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync/**
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Service a TSC-delta measurement request.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync *
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @returns VBox status code.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param pDevExt Pointer to the device instance data.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param pSession The support driver session.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * @param pReq Pointer to the TSC-delta measurement request.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsyncint VBOXCALL supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync{
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint32_t cTries;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint32_t iCpuSet;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync uint32_t fFlags;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync RTMSINTERVAL cMsWaitRetry;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync /*
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync * Validate and adjust/resolve the input so they can be passed onto SUPR0TscDeltaMeasureBySetIndex.
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync AssertPtr(pDevExt); AssertPtr(pSession); AssertPtr(pReq); /* paranoia^2 */
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (pReq->u.In.idCpu == NIL_RTCPUID)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VERR_INVALID_CPU_ID;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync iCpuSet = RTMpCpuIdToSetIndex(pReq->u.In.idCpu);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (iCpuSet >= RTCPUSET_MAX_CPUS)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return VERR_INVALID_CPU_ID;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cTries = pReq->u.In.cRetries == 0 ? 0 : (uint32_t)pReq->u.In.cRetries + 1;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cMsWaitRetry = RT_MAX(pReq->u.In.cMsWaitRetry, 5);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync fFlags = 0;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (pReq->u.In.fAsync)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync fFlags |= SUP_TSCDELTA_MEASURE_F_ASYNC;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync if (pReq->u.In.fForce)
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync fFlags |= SUP_TSCDELTA_MEASURE_F_FORCE;
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync return SUPR0TscDeltaMeasureBySetIndex(pSession, iCpuSet, fFlags, cMsWaitRetry,
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync cTries == 0 ? 5 * RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/,
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync cTries);
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync}
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9a59b271202449cf51ec3ac13b8ef1b4b9810850vboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync/**
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Reads TSC with delta applied.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Will try to resolve delta value INT64_MAX before applying it. This is the
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * main purpose of this function, to handle the case where the delta needs to be
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * determined.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync *
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @returns VBox status code.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pDevExt Pointer to the device instance data.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pSession The support driver session.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * @param pReq Pointer to the TSC-read request.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsyncint VBOXCALL supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCREAD pReq)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync{
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync PSUPGLOBALINFOPAGE pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Validate. We require the client to have mapped GIP (no asserting on
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * ring-3 preconditions).
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertPtr(pDevExt); AssertPtr(pReq); AssertPtr(pSession); /* paranoia^2 */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return VERR_WRONG_ORDER;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pGip = pDevExt->pGip;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertReturn(pGip, VERR_INTERNAL_ERROR_2);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * We're usually here because we need to apply delta, but we shouldn't be
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * upset if the GIP is some different mode.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync uint32_t cTries = 0;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync for (;;)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * Start by gathering the data, using CLI for disabling preemption
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * while we do that.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags = ASMIntDisableFlags();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId());
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int iGipCpu;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_LIKELY( (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && (iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]) < pGip->cCpus ))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int64_t i64Delta = pGip->aCPUs[iGipCpu].i64TSCDelta;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.idApic = pGip->aCPUs[iGipCpu].idApic;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.u64AdjustedTsc = ASMReadTSC();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * If we're lucky we've got a delta, but no predicitions here
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * as this I/O control is normally only used when the TSC delta
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * is set to INT64_MAX.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (i64Delta != INT64_MAX)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.u64AdjustedTsc -= i64Delta;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /* Give up after a few times. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (cTries >= 4)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VWRN_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /* Need to measure the delta an try again. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc));
476493afbafe452ee52b3b3b2bb77e07e5e56285vboxsync /** @todo should probably delay on failure... dpc watchdogs */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /* This really shouldn't happen. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync AssertMsgFailed(("idCpu=%#x iCpuSet=%#x (%d)\n", RTMpCpuId(), iCpuSet, iCpuSet));
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.idApic = ASMGetApicId();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.u64AdjustedTsc = ASMReadTSC();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VERR_INTERNAL_ERROR_5; /** @todo change to warning. */
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync break;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync {
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync /*
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync * No delta to apply. Easy. Deal with preemption the lazy way.
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync */
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync RTCCUINTREG fEFlags = ASMIntDisableFlags();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId());
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync int iGipCpu;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync if (RT_LIKELY( (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync && (iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]) < pGip->cCpus ))
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.idApic = pGip->aCPUs[iGipCpu].idApic;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync else
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.idApic = ASMGetApicId();
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync pReq->u.Out.u64AdjustedTsc = ASMReadTSC();
22362edec993ca6ca17ae026d28a8495fad880e0vboxsync ASMSetFlags(fEFlags);
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync rc = VINF_SUCCESS;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync }
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync return rc;
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync}
9888fffcfbe2d41dce14a1249b12cb88cc9b149fvboxsync