int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); /* * Parse args */ static const RTGETOPTDEF g_aOptions[] = { { "--iterations", 'i', RTGETOPT_REQ_INT32 }, { "--hex", 'h', RTGETOPT_REQ_NOTHING }, { "--decimal", 'd', RTGETOPT_REQ_NOTHING }, { "--spin", 's', RTGETOPT_REQ_NOTHING }, { "--reference", 'r', RTGETOPT_REQ_UINT64 }, /* reference value of CpuHz, display the * CpuHz deviation in a separate column. */ }; uint32_t cIterations = 40; bool fHex = true; bool fSpin = false; int ch; uint64_t uCpuHzRef = 0; uint64_t uCpuHzOverallDeviation = 0; int64_t iCpuHzMaxDeviation = 0; int32_t cCpuHzOverallDevCnt = 0; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_NO_STD_OPTS); while ((ch = RTGetOpt(&GetState, &ValueUnion))) { switch (ch) { case 'i': cIterations = ValueUnion.u32; break; case 'd': fHex = false; break; case 'h': fHex = true; break; case 's': fSpin = true; break; case 'r': uCpuHzRef = ValueUnion.u64; break; default: return RTGetOptPrintError(ch, &ValueUnion); } } /* * Init */ PSUPDRVSESSION pSession = NIL_RTR0PTR; int rc = SUPR3Init(&pSession); if (RT_SUCCESS(rc)) { if (g_pSUPGlobalInfoPage) { RTPrintf("tstGIP-2: cCpus=%d u32UpdateHz=%RU32 u32UpdateIntervalNS=%RU32 u64NanoTSLastUpdateHz=%RX64 u64CpuHz=%RU64 uCpuHzRef=%RU64 u32Mode=%d (%s) u32Version=%#x\n", g_pSUPGlobalInfoPage->cCpus, g_pSUPGlobalInfoPage->u32UpdateHz, g_pSUPGlobalInfoPage->u32UpdateIntervalNS, g_pSUPGlobalInfoPage->u64NanoTSLastUpdateHz, g_pSUPGlobalInfoPage->u64CpuHz, uCpuHzRef, g_pSUPGlobalInfoPage->u32Mode, SUPGetGIPModeName(g_pSUPGlobalInfoPage), g_pSUPGlobalInfoPage->u32Version); RTPrintf(fHex ? "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz %sTSC Interval History...\n" : "tstGIP-2: it: u64NanoTS delta u64TSC UpIntTSC H TransId CpuHz %sTSC Interval History...\n", uCpuHzRef ? " CpuHz deviation " : ""); static SUPGIPCPU s_aaCPUs[2][256]; for (uint32_t i = 0; i < cIterations; i++) { /* copy the data */ memcpy(&s_aaCPUs[i & 1][0], &g_pSUPGlobalInfoPage->aCPUs[0], g_pSUPGlobalInfoPage->cCpus * sizeof(g_pSUPGlobalInfoPage->aCPUs[0])); /* display it & find something to spin on. */ uint32_t u32TransactionId = 0; uint32_t volatile *pu32TransactionId = NULL; for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) if ( g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz > 0 && g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz != _4G + 1) { char szCpuHzDeviation[32]; PSUPGIPCPU pPrevCpu = &s_aaCPUs[!(i & 1)][iCpu]; PSUPGIPCPU pCpu = &s_aaCPUs[i & 1][iCpu]; if (uCpuHzRef) { int64_t iCpuHzDeviation = pCpu->u64CpuHz - uCpuHzRef; uint64_t uCpuHzDeviation = RT_ABS(iCpuHzDeviation); if (uCpuHzDeviation > 999999999) RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%17s ", "?"); else { /* Wait until the history validation code takes effect. */ if (pCpu->u32TransactionId > 23 + (8 * 2) + 1) { if (RT_ABS(iCpuHzDeviation) > RT_ABS(iCpuHzMaxDeviation)) iCpuHzMaxDeviation = iCpuHzDeviation; uCpuHzOverallDeviation += uCpuHzDeviation; cCpuHzOverallDevCnt++; } uint32_t uPct = (uint32_t)(uCpuHzDeviation * 100000 / uCpuHzRef + 5); RTStrPrintf(szCpuHzDeviation, sizeof(szCpuHzDeviation), "%10RI64%3d.%02d%% ", iCpuHzDeviation, uPct / 1000, (uPct % 1000) / 10); } } else szCpuHzDeviation[0] = '\0'; RTPrintf(fHex ? "tstGIP-2: %4d/%d: %016llx %09llx %016llx %08x %d %08x %15llu %s%08x %08x %08x %08x %08x %08x %08x %08x (%d)\n" : "tstGIP-2: %4d/%d: %016llu %09llu %016llu %010u %d %010u %15llu %s%08x %08x %08x %08x %08x %08x %08x %08x (%d)\n", i, iCpu, pCpu->u64NanoTS, i ? pCpu->u64NanoTS - pPrevCpu->u64NanoTS : 0, pCpu->u64TSC, pCpu->u32UpdateIntervalTSC, pCpu->iTSCHistoryHead, pCpu->u32TransactionId, pCpu->u64CpuHz, szCpuHzDeviation, pCpu->au32TSCHistory[0], pCpu->au32TSCHistory[1], pCpu->au32TSCHistory[2], pCpu->au32TSCHistory[3], pCpu->au32TSCHistory[4], pCpu->au32TSCHistory[5], pCpu->au32TSCHistory[6], pCpu->au32TSCHistory[7], pCpu->cErrors); if (!pu32TransactionId) { pu32TransactionId = &g_pSUPGlobalInfoPage->aCPUs[iCpu].u32TransactionId; u32TransactionId = pCpu->u32TransactionId; } } /* wait a bit / spin */ if (!fSpin) RTThreadSleep(9); else { if (pu32TransactionId) { uint32_t uTmp; while ( u32TransactionId == (uTmp = *pu32TransactionId) || (uTmp & 1)) ASMNopPause(); } else RTThreadSleep(1); } } /* * Display TSC deltas. * * First iterative over the APIC ID array to get mostly consistent CPUID to APIC ID mapping. * Then iterate over the offline CPUs. It is possible that there's a race between the online/offline * states between the two iterations, but that cannot be helped from ring-3 anyway and not a biggie. */ RTPrintf("tstGIP-2: TSC deltas:\n"); RTPrintf("tstGIP-2: idApic: i64TSCDelta\n"); for (unsigned i = 0; i < RT_ELEMENTS(g_pSUPGlobalInfoPage->aiCpuFromApicId); i++) { uint16_t iCpu = g_pSUPGlobalInfoPage->aiCpuFromApicId[i]; if (iCpu != UINT16_MAX) { RTPrintf("tstGIP-2: %7d: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic, g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta); } } for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) if (g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic == UINT16_MAX) RTPrintf("tstGIP-2: offline: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta); RTPrintf("tstGIP-2: enmUseTscDelta=%d fGetGipCpu=%#x\n", g_pSUPGlobalInfoPage->enmUseTscDelta, g_pSUPGlobalInfoPage->fGetGipCpu); if ( uCpuHzRef && cCpuHzOverallDevCnt) { uint32_t uPct = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5); RTPrintf("tstGIP-2: Average CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10); uint32_t uMaxPct = (uint32_t)(RT_ABS(iCpuHzMaxDeviation) * 100000 / uCpuHzRef + 5); RTPrintf("tstGIP-2: Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n", uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation); } } else { RTPrintf("tstGIP-2: g_pSUPGlobalInfoPage is NULL\n"); rc = -1; } SUPR3Term(false /*fForced*/); } else RTPrintf("tstGIP-2: SUPR3Init failed: %Rrc\n", rc); return !!rc; }
/** * Kernel entry points */ int _init(void) { #if 0 /* No IPRT logging before RTR0Init() is done! */ LogFlowFunc(("vboxdrv:_init\n")); #endif /* * Prevent module autounloading. */ modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage); if (pModCtl) pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD; else cmn_err(CE_NOTE, "vboxdrv: failed to disable autounloading!\n"); /* * Initialize IPRT R0 driver, which internally calls OS-specific r0 init. */ int rc = RTR0Init(0); if (RT_SUCCESS(rc)) { /* * Initialize the device extension */ rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION)); if (RT_SUCCESS(rc)) { cmn_err(CE_CONT, "!tsc::mode %s @ tentative %lu Hz\n", SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz); /* * Initialize the session hash table. */ memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDrvSol"); if (RT_SUCCESS(rc)) { rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8); if (!rc) { rc = mod_install(&g_VBoxDrvSolarisModLinkage); if (!rc) return rc; /* success */ ddi_soft_state_fini(&g_pVBoxDrvSolarisState); LogRel(("vboxdrv: mod_install failed! rc=%d\n", rc)); } else LogRel(("vboxdrv: failed to initialize soft state.\n")); RTSpinlockDestroy(g_Spinlock); g_Spinlock = NIL_RTSPINLOCK; } else { LogRel(("VBoxDrvSolarisAttach: RTSpinlockCreate failed\n")); rc = RTErrConvertToErrno(rc); } supdrvDeleteDevExt(&g_DevExt); } else { LogRel(("VBoxDrvSolarisAttach: supdrvInitDevExt failed\n")); rc = EINVAL; } RTR0TermForced(); } else { LogRel(("VBoxDrvSolarisAttach: failed to init R0Drv\n")); rc = RTErrConvertToErrno(rc); } memset(&g_DevExt, 0, sizeof(g_DevExt)); return rc; }
/** * Initialize module. * * @returns appropriate status code. */ static int __init VBoxDrvLinuxInit(void) { int rc; /* * Check for synchronous/asynchronous TSC mode. */ printk(KERN_DEBUG "vboxdrv: Found %u processor cores\n", (unsigned)RTMpGetOnlineCount()); #ifdef CONFIG_VBOXDRV_AS_MISC rc = misc_register(&gMiscDeviceSys); if (rc) { printk(KERN_ERR "vboxdrv: Can't register system misc device! rc=%d\n", rc); return rc; } rc = misc_register(&gMiscDeviceUsr); if (rc) { printk(KERN_ERR "vboxdrv: Can't register user misc device! rc=%d\n", rc); misc_deregister(&gMiscDeviceSys); return rc; } #else /* !CONFIG_VBOXDRV_AS_MISC */ /* * Register character devices and save the returned major numbers. */ /* /dev/vboxdrv */ g_iModuleMajorSys = DEVICE_MAJOR_SYS; rc = register_chrdev((dev_t)g_iModuleMajorSys, DEVICE_NAME_SYS, &gFileOpsVBoxDrvSys); if (rc < 0) { Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc)); return rc; } if (DEVICE_MAJOR_SYS != 0) g_iModuleMajorSys = DEVICE_MAJOR_SYS; else g_iModuleMajorSys = rc; /* /dev/vboxdrvu */ /** @todo Use a minor number of this bugger (not sure if this code is used * though, so not bothering right now.) */ g_iModuleMajorUsr = DEVICE_MAJOR_USR; rc = register_chrdev((dev_t)g_iModuleMajorUsr, DEVICE_NAME_USR, &gFileOpsVBoxDrvUsr); if (rc < 0) { Log(("register_chrdev() failed with rc=%#x for vboxdrv!\n", rc)); return rc; } if (DEVICE_MAJOR_USR != 0) g_iModuleMajorUsr = DEVICE_MAJOR_USR; else g_iModuleMajorUsr = rc; rc = 0; # ifdef CONFIG_DEVFS_FS /* * Register a device entry */ if ( devfs_mk_cdev(MKDEV(DEVICE_MAJOR_SYS, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_SYS) != 0 || devfs_mk_cdev(MKDEV(DEVICE_MAJOR_USR, 0), S_IFCHR | VBOX_DEV_FMASK, DEVICE_NAME_USR) != 0) { Log(("devfs_register failed!\n")); rc = -EINVAL; } # endif #endif /* !CONFIG_VBOXDRV_AS_MISC */ if (!rc) { /* * Initialize the runtime. * On AMD64 we'll have to donate the high rwx memory block to the exec allocator. */ rc = RTR0Init(0); if (RT_SUCCESS(rc)) { #if (defined(RT_ARCH_AMD64) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)) || defined(VBOX_WITH_TEXT_MODMEM_HACK) # ifdef VBOX_WITH_TEXT_MODMEM_HACK set_memory_x(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE); set_memory_rw(&g_abExecMemory[0], sizeof(g_abExecMemory) / PAGE_SIZE); # endif rc = RTR0MemExecDonate(&g_abExecMemory[0], sizeof(g_abExecMemory)); printk(KERN_DEBUG "VBoxDrv: dbg - g_abExecMemory=%p\n", (void *)&g_abExecMemory[0]); #endif Log(("VBoxDrv::ModuleInit\n")); /* * Initialize the device extension. */ if (RT_SUCCESS(rc)) rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION)); if (RT_SUCCESS(rc)) { #ifdef VBOX_WITH_SUSPEND_NOTIFICATION rc = platform_driver_register(&gPlatformDriver); if (rc == 0) { rc = platform_device_register(&gPlatformDevice); if (rc == 0) #endif { printk(KERN_INFO "vboxdrv: TSC mode is %s, tentative frequency %llu Hz\n", SUPGetGIPModeName(g_DevExt.pGip), g_DevExt.pGip->u64CpuHz); LogFlow(("VBoxDrv::ModuleInit returning %#x\n", rc)); printk(KERN_DEBUG "vboxdrv: Successfully loaded version " VBOX_VERSION_STRING " (interface " RT_XSTR(SUPDRV_IOC_VERSION) ")\n"); return rc; } #ifdef VBOX_WITH_SUSPEND_NOTIFICATION else platform_driver_unregister(&gPlatformDriver); } #endif } rc = -EINVAL; RTR0TermForced(); } else rc = -EINVAL; /* * Failed, cleanup and return the error code. */ #if defined(CONFIG_DEVFS_FS) && !defined(CONFIG_VBOXDRV_AS_MISC) devfs_remove(DEVICE_NAME_SYS); devfs_remove(DEVICE_NAME_USR); #endif } #ifdef CONFIG_VBOXDRV_AS_MISC misc_deregister(&gMiscDeviceSys); misc_deregister(&gMiscDeviceUsr); Log(("VBoxDrv::ModuleInit returning %#x (minor:%d & %d)\n", rc, gMiscDeviceSys.minor, gMiscDeviceUsr.minor)); #else unregister_chrdev(g_iModuleMajorUsr, DEVICE_NAME_USR); unregister_chrdev(g_iModuleMajorSys, DEVICE_NAME_SYS); Log(("VBoxDrv::ModuleInit returning %#x (major:%d & %d)\n", rc, g_iModuleMajorSys, g_iModuleMajorUsr)); #endif return rc; }