1843e1988Sjohnlev /* 2843e1988Sjohnlev * CDDL HEADER START 3843e1988Sjohnlev * 4843e1988Sjohnlev * The contents of this file are subject to the terms of the 5843e1988Sjohnlev * Common Development and Distribution License (the "License"). 6843e1988Sjohnlev * You may not use this file except in compliance with the License. 7843e1988Sjohnlev * 8843e1988Sjohnlev * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9843e1988Sjohnlev * or http://www.opensolaris.org/os/licensing. 10843e1988Sjohnlev * See the License for the specific language governing permissions 11843e1988Sjohnlev * and limitations under the License. 12843e1988Sjohnlev * 13843e1988Sjohnlev * When distributing Covered Code, include this CDDL HEADER in each 14843e1988Sjohnlev * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15843e1988Sjohnlev * If applicable, add the following below this CDDL HEADER, with the 16843e1988Sjohnlev * fields enclosed by brackets "[]" replaced with your own identifying 17843e1988Sjohnlev * information: Portions Copyright [yyyy] [name of copyright owner] 18843e1988Sjohnlev * 19843e1988Sjohnlev * CDDL HEADER END 20843e1988Sjohnlev */ 21843e1988Sjohnlev 22843e1988Sjohnlev /* 23349b53ddSStuart Maybee * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24843e1988Sjohnlev * Use is subject to license terms. 25*263f549eSPatrick Mooney * Copyright 2016 Joyent, Inc. 26843e1988Sjohnlev */ 27843e1988Sjohnlev 28843e1988Sjohnlev #include <sys/types.h> 29843e1988Sjohnlev #include <sys/clock.h> 30843e1988Sjohnlev #include <sys/panic.h> 31843e1988Sjohnlev #include <sys/atomic.h> 32843e1988Sjohnlev #include <sys/hypervisor.h> 33843e1988Sjohnlev 34843e1988Sjohnlev #include <sys/archsystm.h> 35843e1988Sjohnlev 36843e1988Sjohnlev /* 37843e1988Sjohnlev * On the hypervisor, we have a virtualized system time based upon the 38843e1988Sjohnlev * information provided for each VCPU, which is updated every time it is 39843e1988Sjohnlev * scheduled onto a real CPU. Thus, none of the traditional code in 40843e1988Sjohnlev * i86pc/os/timestamp.c applies, our gethrtime() implementation is run through 41843e1988Sjohnlev * the PSM, and there is no scaling step to apply. 42843e1988Sjohnlev * 43843e1988Sjohnlev * However, the platform does not guarantee monotonicity; thus we have to fake 44843e1988Sjohnlev * this up, which is a deeply unpleasant thing to have to do. 45843e1988Sjohnlev * 46843e1988Sjohnlev * Note that the virtualized interface still relies on the current TSC to 47843e1988Sjohnlev * calculate the time in nanoseconds since the VCPU was scheduled, and is thus 48843e1988Sjohnlev * subject to all the problems with that. For the most part, the hypervisor is 49843e1988Sjohnlev * supposed to deal with them. 50843e1988Sjohnlev * 51843e1988Sjohnlev * Another wrinkle involves suspend/resume/migration. If we come back and time 52843e1988Sjohnlev * is apparently less, we may have resumed on a different machine or on the 53843e1988Sjohnlev * same machine after a reboot. In this case we need to maintain an addend to 54843e1988Sjohnlev * ensure time continues reasonably. Otherwise we could end up taking a very 55843e1988Sjohnlev * long time to expire cyclics in the heap. Thus we have two functions: 56843e1988Sjohnlev * 57843e1988Sjohnlev * xpv_getsystime() 58843e1988Sjohnlev * 59843e1988Sjohnlev * The unadulterated system time from the hypervisor. This is only to be 60843e1988Sjohnlev * used when programming the hypervisor (setting a timer or calculating 61843e1988Sjohnlev * the TOD). 62843e1988Sjohnlev * 63843e1988Sjohnlev * xpv_gethrtime() 64843e1988Sjohnlev * 65843e1988Sjohnlev * This is the monotonic hrtime counter to be used by everything else such 66843e1988Sjohnlev * as the cyclic subsystem. We should never pass an hrtime directly into 67843e1988Sjohnlev * a hypervisor interface, as hrtime_addend may well be non-zero. 68843e1988Sjohnlev */ 69843e1988Sjohnlev 70349b53ddSStuart Maybee int hrtime_fake_mt = 1; 71843e1988Sjohnlev static volatile hrtime_t hrtime_last; 72843e1988Sjohnlev static hrtime_t hrtime_suspend_time; 73843e1988Sjohnlev static hrtime_t hrtime_addend; 74843e1988Sjohnlev 75*263f549eSPatrick Mooney volatile uint32_t hres_lock; 76*263f549eSPatrick Mooney hrtime_t hres_last_tick; 77*263f549eSPatrick Mooney int64_t hrestime_adj; 78*263f549eSPatrick Mooney volatile timestruc_t hrestime; 79*263f549eSPatrick Mooney 80843e1988Sjohnlev /* 81843e1988Sjohnlev * These functions are used in DTrace probe context, and must be removed from 82843e1988Sjohnlev * fbt consideration. Currently fbt ignores all weak symbols, so this will 83843e1988Sjohnlev * achieve that. 84843e1988Sjohnlev */ 85843e1988Sjohnlev #pragma weak xpv_gethrtime = dtrace_xpv_gethrtime 86843e1988Sjohnlev #pragma weak xpv_getsystime = dtrace_xpv_getsystime 87843e1988Sjohnlev #pragma weak dtrace_gethrtime = dtrace_xpv_gethrtime 88843e1988Sjohnlev #pragma weak tsc_read = dtrace_xpv_gethrtime 89843e1988Sjohnlev 90843e1988Sjohnlev hrtime_t 91843e1988Sjohnlev dtrace_xpv_getsystime(void) 92843e1988Sjohnlev { 93843e1988Sjohnlev vcpu_time_info_t *src; 94843e1988Sjohnlev vcpu_time_info_t __vti, *dst = &__vti; 95843e1988Sjohnlev uint64_t tsc_delta; 96843e1988Sjohnlev uint64_t tsc; 97843e1988Sjohnlev hrtime_t result; 983006ae82SFrank Van Der Linden uint32_t stamp; 99843e1988Sjohnlev 100843e1988Sjohnlev src = &CPU->cpu_m.mcpu_vcpu_info->time; 101843e1988Sjohnlev 102843e1988Sjohnlev /* 103843e1988Sjohnlev * Loop until version has not been changed during our update, and a Xen 104843e1988Sjohnlev * update is not under way (lowest bit is set). 105843e1988Sjohnlev */ 106843e1988Sjohnlev do { 107843e1988Sjohnlev dst->version = src->version; 1083006ae82SFrank Van Der Linden stamp = CPU->cpu_m.mcpu_istamp; 109843e1988Sjohnlev 110843e1988Sjohnlev membar_consumer(); 111843e1988Sjohnlev 112843e1988Sjohnlev dst->tsc_timestamp = src->tsc_timestamp; 113843e1988Sjohnlev dst->system_time = src->system_time; 114843e1988Sjohnlev dst->tsc_to_system_mul = src->tsc_to_system_mul; 115843e1988Sjohnlev dst->tsc_shift = src->tsc_shift; 116843e1988Sjohnlev 117843e1988Sjohnlev /* 118843e1988Sjohnlev * Note that this use of the -actual- TSC register 119843e1988Sjohnlev * should probably be the SOLE one in the system on this 120843e1988Sjohnlev * paravirtualized platform. 121843e1988Sjohnlev */ 122843e1988Sjohnlev tsc = __rdtsc_insn(); 123843e1988Sjohnlev tsc_delta = tsc - dst->tsc_timestamp; 124843e1988Sjohnlev 125843e1988Sjohnlev membar_consumer(); 126843e1988Sjohnlev 1273006ae82SFrank Van Der Linden } while (((src->version & 1) | (dst->version ^ src->version)) || 1283006ae82SFrank Van Der Linden CPU->cpu_m.mcpu_istamp != stamp); 129843e1988Sjohnlev 130843e1988Sjohnlev if (dst->tsc_shift >= 0) 131843e1988Sjohnlev tsc_delta <<= dst->tsc_shift; 132843e1988Sjohnlev else if (dst->tsc_shift < 0) 133843e1988Sjohnlev tsc_delta >>= -dst->tsc_shift; 134843e1988Sjohnlev 135843e1988Sjohnlev result = dst->system_time + 136843e1988Sjohnlev ((uint64_t)(tsc_delta * (uint64_t)dst->tsc_to_system_mul) >> 32); 137843e1988Sjohnlev 138843e1988Sjohnlev return (result); 139843e1988Sjohnlev } 140843e1988Sjohnlev 141843e1988Sjohnlev hrtime_t 142843e1988Sjohnlev dtrace_xpv_gethrtime(void) 143843e1988Sjohnlev { 144843e1988Sjohnlev hrtime_t result = xpv_getsystime() + hrtime_addend; 145843e1988Sjohnlev 146843e1988Sjohnlev if (hrtime_fake_mt) { 147843e1988Sjohnlev hrtime_t last; 148843e1988Sjohnlev do { 149843e1988Sjohnlev last = hrtime_last; 150843e1988Sjohnlev if (result < last) 151843e1988Sjohnlev result = last + 1; 152843e1988Sjohnlev } while (atomic_cas_64((volatile uint64_t *)&hrtime_last, 153843e1988Sjohnlev last, result) != last); 154843e1988Sjohnlev } 155843e1988Sjohnlev 156843e1988Sjohnlev return (result); 157843e1988Sjohnlev } 158843e1988Sjohnlev 159843e1988Sjohnlev void 160843e1988Sjohnlev xpv_time_suspend(void) 161843e1988Sjohnlev { 162843e1988Sjohnlev hrtime_suspend_time = xpv_getsystime(); 163843e1988Sjohnlev } 164843e1988Sjohnlev 165843e1988Sjohnlev void 166843e1988Sjohnlev xpv_time_resume(void) 167843e1988Sjohnlev { 168843e1988Sjohnlev hrtime_t delta = xpv_getsystime() - hrtime_suspend_time; 169843e1988Sjohnlev 170843e1988Sjohnlev if (delta < 0) 171843e1988Sjohnlev hrtime_addend += -delta; 172843e1988Sjohnlev } 173