2007-07-21 17:10:01 +02:00
/*
* Copyright 2006 Andi Kleen , SUSE Labs .
* Subject to the GNU Public License , v .2
*
2011-05-23 09:31:30 -04:00
* Fast user context implementation of clock_gettime , gettimeofday , and time .
2007-07-21 17:10:01 +02:00
*
2014-03-17 23:22:09 +01:00
* 32 Bit compat layer by Stefani Seibold < stefani @ seibold . net >
* sponsored by Rohde & Schwarz GmbH & Co . KG Munich / Germany
*
2007-07-21 17:10:01 +02:00
* The code should have no internal unresolved relocations .
* Check with readelf after changing .
*/
2014-03-17 23:22:09 +01:00
# include <uapi/linux/time.h>
2007-07-21 17:10:01 +02:00
# include <asm/vgtod.h>
2014-03-17 23:22:10 +01:00
# include <asm/vvar.h>
2007-07-21 17:10:01 +02:00
# include <asm/unistd.h>
2014-03-17 23:22:10 +01:00
# include <asm/msr.h>
2015-12-10 19:20:22 -08:00
# include <asm/pvclock.h>
2014-03-17 23:22:10 +01:00
# include <linux/math64.h>
# include <linux/time.h>
2015-12-10 19:20:22 -08:00
# include <linux/kernel.h>
2007-07-21 17:10:01 +02:00
2011-05-23 09:31:24 -04:00
# define gtod (&VVAR(vsyscall_gtod_data))
2007-07-21 17:10:01 +02:00
2014-03-17 23:22:09 +01:00
extern int __vdso_clock_gettime ( clockid_t clock , struct timespec * ts ) ;
extern int __vdso_gettimeofday ( struct timeval * tv , struct timezone * tz ) ;
extern time_t __vdso_time ( time_t * t ) ;
2015-12-10 19:20:20 -08:00
# ifdef CONFIG_PARAVIRT_CLOCK
extern u8 pvclock_page
__attribute__ ( ( visibility ( " hidden " ) ) ) ;
# endif
2014-03-17 23:22:09 +01:00
# ifndef BUILD_VDSO32
2014-03-17 23:22:03 +01:00
notrace static long vdso_fallback_gettime ( long clock , struct timespec * ts )
{
long ret ;
asm ( " syscall " : " =a " ( ret ) :
" 0 " ( __NR_clock_gettime ) , " D " ( clock ) , " S " ( ts ) : " memory " ) ;
return ret ;
2011-07-14 06:47:22 -04:00
}
2014-03-17 23:22:03 +01:00
notrace static long vdso_fallback_gtod ( struct timeval * tv , struct timezone * tz )
2011-07-14 06:47:22 -04:00
{
2014-03-17 23:22:03 +01:00
long ret ;
asm ( " syscall " : " =a " ( ret ) :
" 0 " ( __NR_gettimeofday ) , " D " ( tv ) , " S " ( tz ) : " memory " ) ;
return ret ;
2011-07-14 06:47:22 -04:00
}
2012-11-27 23:28:57 -02:00
2015-12-10 19:20:22 -08:00
# else
notrace static long vdso_fallback_gettime ( long clock , struct timespec * ts )
{
long ret ;
asm (
" mov %%ebx, %%edx \n "
" mov %2, %%ebx \n "
" call __kernel_vsyscall \n "
" mov %%edx, %%ebx \n "
: " =a " ( ret )
: " 0 " ( __NR_clock_gettime ) , " g " ( clock ) , " c " ( ts )
: " memory " , " edx " ) ;
return ret ;
}
notrace static long vdso_fallback_gtod ( struct timeval * tv , struct timezone * tz )
{
long ret ;
asm (
" mov %%ebx, %%edx \n "
" mov %2, %%ebx \n "
" call __kernel_vsyscall \n "
" mov %%edx, %%ebx \n "
: " =a " ( ret )
: " 0 " ( __NR_gettimeofday ) , " g " ( tv ) , " c " ( tz )
: " memory " , " edx " ) ;
return ret ;
}
# endif
# ifdef CONFIG_PARAVIRT_CLOCK
2015-12-10 19:20:20 -08:00
static notrace const struct pvclock_vsyscall_time_info * get_pvti0 ( void )
2012-11-27 23:28:57 -02:00
{
2015-12-10 19:20:20 -08:00
return ( const struct pvclock_vsyscall_time_info * ) & pvclock_page ;
2012-11-27 23:28:57 -02:00
}
static notrace cycle_t vread_pvclock ( int * mode )
{
2015-12-10 19:20:20 -08:00
const struct pvclock_vcpu_time_info * pvti = & get_pvti0 ( ) - > pvti ;
2012-11-27 23:28:57 -02:00
cycle_t ret ;
2015-12-10 19:20:19 -08:00
u64 tsc , pvti_tsc ;
u64 last , delta , pvti_system_time ;
u32 version , pvti_tsc_to_system_mul , pvti_tsc_shift ;
2012-11-27 23:28:57 -02:00
/*
2015-12-10 19:20:19 -08:00
* Note : The kernel and hypervisor must guarantee that cpu ID
* number maps 1 : 1 to per - CPU pvclock time info .
*
* Because the hypervisor is entirely unaware of guest userspace
* preemption , it cannot guarantee that per - CPU pvclock time
* info is updated if the underlying CPU changes or that that
* version is increased whenever underlying CPU changes .
*
* On KVM , we are guaranteed that pvti updates for any vCPU are
* atomic as seen by * all * vCPUs . This is an even stronger
* guarantee than we get with a normal seqlock .
2015-04-23 13:20:18 +02:00
*
2015-12-10 19:20:19 -08:00
* On Xen , we don ' t appear to have that guarantee , but Xen still
* supplies a valid seqlock using the version field .
2016-01-04 15:14:28 -08:00
*
2015-12-10 19:20:19 -08:00
* We only do pvclock vdso timing at all if
* PVCLOCK_TSC_STABLE_BIT is set , and we interpret that bit to
* mean that all vCPUs have matching pvti and that the TSC is
* synced , so we can just look at vCPU 0 ' s pvti .
2012-11-27 23:28:57 -02:00
*/
2015-12-10 19:20:19 -08:00
do {
version = pvti - > version ;
2015-12-10 19:20:22 -08:00
smp_rmb ( ) ;
2015-12-10 19:20:19 -08:00
2016-01-04 15:14:28 -08:00
if ( unlikely ( ! ( pvti - > flags & PVCLOCK_TSC_STABLE_BIT ) ) ) {
* mode = VCLOCK_NONE ;
return 0 ;
}
2015-12-10 19:20:22 -08:00
tsc = rdtsc_ordered ( ) ;
2015-12-10 19:20:19 -08:00
pvti_tsc_to_system_mul = pvti - > tsc_to_system_mul ;
pvti_tsc_shift = pvti - > tsc_shift ;
pvti_system_time = pvti - > system_time ;
pvti_tsc = pvti - > tsc_timestamp ;
/* Make sure that the version double-check is last. */
smp_rmb ( ) ;
} while ( unlikely ( ( version & 1 ) | | version ! = pvti - > version ) ) ;
delta = tsc - pvti_tsc ;
ret = pvti_system_time +
pvclock_scale_delta ( delta , pvti_tsc_to_system_mul ,
pvti_tsc_shift ) ;
2012-11-27 23:28:57 -02:00
2015-12-10 19:20:22 -08:00
/* refer to vread_tsc() comment for rationale */
2014-03-17 23:22:10 +01:00
last = gtod - > cycle_last ;
2012-11-27 23:28:57 -02:00
if ( likely ( ret > = last ) )
return ret ;
return last ;
}
# endif
2014-03-17 23:22:03 +01:00
notrace static cycle_t vread_tsc ( void )
2007-07-21 17:10:01 +02:00
{
2015-06-25 18:44:08 +02:00
cycle_t ret = ( cycle_t ) rdtsc_ordered ( ) ;
u64 last = gtod - > cycle_last ;
2012-03-01 22:11:09 -08:00
2014-03-17 23:22:03 +01:00
if ( likely ( ret > = last ) )
return ret ;
/*
* GCC likes to generate cmov here , but this branch is extremely
2016-02-23 15:34:30 -08:00
* predictable ( it ' s just a function of time and the likely is
2014-03-17 23:22:03 +01:00
* very likely ) and there ' s a data dependence , so force GCC
* to generate a branch instead . I don ' t barrier ( ) because
* we don ' t actually need a barrier , and if this function
* ever gets inlined it will generate worse code .
*/
asm volatile ( " " ) ;
return last ;
}
2012-03-01 22:11:09 -08:00
2012-11-27 23:28:57 -02:00
notrace static inline u64 vgetsns ( int * mode )
2007-07-21 17:10:01 +02:00
{
2014-03-17 23:22:09 +01:00
u64 v ;
2011-07-14 06:47:22 -04:00
cycles_t cycles ;
2014-03-17 23:22:10 +01:00
if ( gtod - > vclock_mode = = VCLOCK_TSC )
2011-07-14 06:47:22 -04:00
cycles = vread_tsc ( ) ;
2012-11-27 23:28:57 -02:00
# ifdef CONFIG_PARAVIRT_CLOCK
2014-03-17 23:22:10 +01:00
else if ( gtod - > vclock_mode = = VCLOCK_PVCLOCK )
2012-11-27 23:28:57 -02:00
cycles = vread_pvclock ( mode ) ;
# endif
2012-03-01 22:11:09 -08:00
else
return 0 ;
2014-03-17 23:22:10 +01:00
v = ( cycles - gtod - > cycle_last ) & gtod - > mask ;
return v * gtod - > mult ;
2007-07-21 17:10:01 +02:00
}
2012-03-22 21:15:52 -07:00
/* Code size doesn't matter (vdso is 4k anyway) and this is faster. */
notrace static int __always_inline do_realtime ( struct timespec * ts )
2007-07-21 17:10:01 +02:00
{
2012-09-04 16:14:46 -04:00
unsigned long seq ;
u64 ns ;
2012-03-01 22:11:09 -08:00
int mode ;
2007-07-21 17:10:01 +02:00
do {
2014-03-17 23:22:10 +01:00
seq = gtod_read_begin ( gtod ) ;
mode = gtod - > vclock_mode ;
2007-07-21 17:10:01 +02:00
ts - > tv_sec = gtod - > wall_time_sec ;
2012-09-04 16:14:46 -04:00
ns = gtod - > wall_time_snsec ;
2012-11-27 23:28:57 -02:00
ns + = vgetsns ( & mode ) ;
2014-03-17 23:22:10 +01:00
ns > > = gtod - > shift ;
} while ( unlikely ( gtod_read_retry ( gtod , seq ) ) ) ;
ts - > tv_sec + = __iter_div_u64_rem ( ns , NSEC_PER_SEC , & ns ) ;
ts - > tv_nsec = ns ;
2012-03-01 22:11:09 -08:00
return mode ;
2007-07-21 17:10:01 +02:00
}
2014-03-17 23:22:09 +01:00
notrace static int __always_inline do_monotonic ( struct timespec * ts )
2007-07-21 17:10:01 +02:00
{
2012-09-04 16:14:46 -04:00
unsigned long seq ;
u64 ns ;
2012-03-01 22:11:09 -08:00
int mode ;
2007-07-21 17:10:01 +02:00
do {
2014-03-17 23:22:10 +01:00
seq = gtod_read_begin ( gtod ) ;
mode = gtod - > vclock_mode ;
2012-03-22 21:15:51 -07:00
ts - > tv_sec = gtod - > monotonic_time_sec ;
2012-09-04 16:14:46 -04:00
ns = gtod - > monotonic_time_snsec ;
2012-11-27 23:28:57 -02:00
ns + = vgetsns ( & mode ) ;
2014-03-17 23:22:10 +01:00
ns > > = gtod - > shift ;
} while ( unlikely ( gtod_read_retry ( gtod , seq ) ) ) ;
ts - > tv_sec + = __iter_div_u64_rem ( ns , NSEC_PER_SEC , & ns ) ;
ts - > tv_nsec = ns ;
2011-05-23 09:31:27 -04:00
2012-03-01 22:11:09 -08:00
return mode ;
2007-07-21 17:10:01 +02:00
}
2014-03-17 23:22:04 +01:00
notrace static void do_realtime_coarse ( struct timespec * ts )
2009-08-19 19:13:34 -07:00
{
unsigned long seq ;
do {
2014-03-17 23:22:10 +01:00
seq = gtod_read_begin ( gtod ) ;
ts - > tv_sec = gtod - > wall_time_coarse_sec ;
ts - > tv_nsec = gtod - > wall_time_coarse_nsec ;
} while ( unlikely ( gtod_read_retry ( gtod , seq ) ) ) ;
2009-08-19 19:13:34 -07:00
}
2014-03-17 23:22:04 +01:00
notrace static void do_monotonic_coarse ( struct timespec * ts )
2009-08-19 19:13:34 -07:00
{
2012-03-22 21:15:51 -07:00
unsigned long seq ;
2009-08-19 19:13:34 -07:00
do {
2014-03-17 23:22:10 +01:00
seq = gtod_read_begin ( gtod ) ;
ts - > tv_sec = gtod - > monotonic_time_coarse_sec ;
ts - > tv_nsec = gtod - > monotonic_time_coarse_nsec ;
} while ( unlikely ( gtod_read_retry ( gtod , seq ) ) ) ;
2009-08-19 19:13:34 -07:00
}
2008-05-12 21:20:41 +02:00
notrace int __vdso_clock_gettime ( clockid_t clock , struct timespec * ts )
2007-07-21 17:10:01 +02:00
{
2011-06-05 13:50:20 -04:00
switch ( clock ) {
case CLOCK_REALTIME :
2014-03-17 23:22:04 +01:00
if ( do_realtime ( ts ) = = VCLOCK_NONE )
goto fallback ;
2011-06-05 13:50:20 -04:00
break ;
case CLOCK_MONOTONIC :
2014-03-17 23:22:04 +01:00
if ( do_monotonic ( ts ) = = VCLOCK_NONE )
goto fallback ;
2011-06-05 13:50:20 -04:00
break ;
case CLOCK_REALTIME_COARSE :
2014-03-17 23:22:04 +01:00
do_realtime_coarse ( ts ) ;
break ;
2011-06-05 13:50:20 -04:00
case CLOCK_MONOTONIC_COARSE :
2014-03-17 23:22:04 +01:00
do_monotonic_coarse ( ts ) ;
break ;
default :
goto fallback ;
2011-06-05 13:50:20 -04:00
}
2012-03-01 22:11:09 -08:00
return 0 ;
2014-03-17 23:22:04 +01:00
fallback :
return vdso_fallback_gettime ( clock , ts ) ;
2007-07-21 17:10:01 +02:00
}
int clock_gettime ( clockid_t , struct timespec * )
__attribute__ ( ( weak , alias ( " __vdso_clock_gettime " ) ) ) ;
2008-05-12 21:20:41 +02:00
notrace int __vdso_gettimeofday ( struct timeval * tv , struct timezone * tz )
2007-07-21 17:10:01 +02:00
{
2012-03-01 22:11:09 -08:00
if ( likely ( tv ! = NULL ) ) {
2014-03-17 23:22:06 +01:00
if ( unlikely ( do_realtime ( ( struct timespec * ) tv ) = = VCLOCK_NONE ) )
return vdso_fallback_gtod ( tv , tz ) ;
2012-03-01 22:11:09 -08:00
tv - > tv_usec / = 1000 ;
2007-07-21 17:10:01 +02:00
}
2012-03-01 22:11:09 -08:00
if ( unlikely ( tz ! = NULL ) ) {
2014-03-17 23:22:10 +01:00
tz - > tz_minuteswest = gtod - > tz_minuteswest ;
tz - > tz_dsttime = gtod - > tz_dsttime ;
2012-03-01 22:11:09 -08:00
}
return 0 ;
2007-07-21 17:10:01 +02:00
}
int gettimeofday ( struct timeval * , struct timezone * )
__attribute__ ( ( weak , alias ( " __vdso_gettimeofday " ) ) ) ;
2011-05-23 09:31:30 -04:00
2011-06-05 13:50:20 -04:00
/*
* This will break when the xtime seconds get inaccurate , but that is
* unlikely
*/
2011-05-23 09:31:30 -04:00
notrace time_t __vdso_time ( time_t * t )
{
2014-03-17 23:22:09 +01:00
/* This is atomic on x86 so we don't need any locks. */
2014-03-17 23:22:05 +01:00
time_t result = ACCESS_ONCE ( gtod - > wall_time_sec ) ;
2011-05-23 09:31:30 -04:00
if ( t )
* t = result ;
return result ;
}
int time ( time_t * t )
__attribute__ ( ( weak , alias ( " __vdso_time " ) ) ) ;