1052 lines · 26.6 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* *  Copyright (C) 1991, 1992  Linus Torvalds * *  This file contains the interface functions for the various time related *  system calls: time, stime, gettimeofday, settimeofday, adjtime * * Modification history: * * 1993-09-02    Philip Gladstone *      Created file with time related functions from sched/core.c and adjtimex() * 1993-10-08    Torsten Duwe *      adjtime interface update and CMOS clock write code * 1995-08-13    Torsten Duwe *      kernel PLL updated to 1994-12-13 specs (rfc-1589) * 1999-01-16    Ulrich Windl *	Introduced error checking for many cases in adjtimex(). *	Updated NTP code according to technical memorandum Jan '96 *	"A Kernel Model for Precision Timekeeping" by Dave Mills *	Allow time_constant larger than MAXTC(6) for NTP v4 (MAXTC == 10) *	(Even though the technical memorandum forbids it) * 2004-07-14	 Christoph Lameter *	Added getnstimeofday to allow the posix timer functions to return *	with nanosecond accuracy */ #include <linux/export.h>#include <linux/kernel.h>#include <linux/timex.h>#include <linux/capability.h>#include <linux/timekeeper_internal.h>#include <linux/errno.h>#include <linux/syscalls.h>#include <linux/security.h>#include <linux/fs.h>#include <linux/math64.h>#include <linux/ptrace.h> #include <linux/uaccess.h>#include <linux/compat.h>#include <asm/unistd.h> #include <generated/timeconst.h>#include "timekeeping.h" /* * The timezone where the local system is located.  Used as a default by some * programs who obtain this value by using gettimeofday. */struct timezone sys_tz; EXPORT_SYMBOL(sys_tz); #ifdef __ARCH_WANT_SYS_TIME /* * sys_time() can be implemented in user-level using * sys_gettimeofday().  Is this for backwards compatibility?  If so, * why not move it into the appropriate arch directory (for those * architectures that need it). */SYSCALL_DEFINE1(time, __kernel_old_time_t __user *, tloc){	__kernel_old_time_t i = (__kernel_old_time_t)ktime_get_real_seconds(); 	if (tloc) {		if (put_user(i,tloc))			return -EFAULT;	}	force_successful_syscall_return();	return i;} /* * sys_stime() can be implemented in user-level using * sys_settimeofday().  Is this for backwards compatibility?  If so, * why not move it into the appropriate arch directory (for those * architectures that need it). */ SYSCALL_DEFINE1(stime, __kernel_old_time_t __user *, tptr){	struct timespec64 tv;	int err; 	if (get_user(tv.tv_sec, tptr))		return -EFAULT; 	tv.tv_nsec = 0; 	err = security_settime64(&tv, NULL);	if (err)		return err; 	do_settimeofday64(&tv);	return 0;} #endif /* __ARCH_WANT_SYS_TIME */ #ifdef CONFIG_COMPAT_32BIT_TIME#ifdef __ARCH_WANT_SYS_TIME32 /* old_time32_t is a 32 bit "long" and needs to get converted. */SYSCALL_DEFINE1(time32, old_time32_t __user *, tloc){	old_time32_t i; 	i = (old_time32_t)ktime_get_real_seconds(); 	if (tloc) {		if (put_user(i,tloc))			return -EFAULT;	}	force_successful_syscall_return();	return i;} SYSCALL_DEFINE1(stime32, old_time32_t __user *, tptr){	struct timespec64 tv;	int err; 	if (get_user(tv.tv_sec, tptr))		return -EFAULT; 	tv.tv_nsec = 0; 	err = security_settime64(&tv, NULL);	if (err)		return err; 	do_settimeofday64(&tv);	return 0;} #endif /* __ARCH_WANT_SYS_TIME32 */#endif SYSCALL_DEFINE2(gettimeofday, struct __kernel_old_timeval __user *, tv,		struct timezone __user *, tz){	if (likely(tv != NULL)) {		struct timespec64 ts; 		ktime_get_real_ts64(&ts);		if (put_user(ts.tv_sec, &tv->tv_sec) ||		    put_user(ts.tv_nsec / 1000, &tv->tv_usec))			return -EFAULT;	}	if (unlikely(tz != NULL)) {		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))			return -EFAULT;	}	return 0;} /* * In case for some reason the CMOS clock has not already been running * in UTC, but in some local time: The first time we set the timezone, * we will warp the clock so that it is ticking UTC time instead of * local time. Presumably, if someone is setting the timezone then we * are running in an environment where the programs understand about * timezones. This should be done at boot time in the /etc/rc script, * as soon as possible, so that the clock can be set right. Otherwise, * various programs will get confused when the clock gets warped. */ int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz){	static int firsttime = 1;	int error = 0; 	if (tv && !timespec64_valid_settod(tv))		return -EINVAL; 	error = security_settime64(tv, tz);	if (error)		return error; 	if (tz) {		/* Verify we're within the +-15 hrs range */		if (tz->tz_minuteswest > 15*60 || tz->tz_minuteswest < -15*60)			return -EINVAL; 		sys_tz = *tz;		update_vsyscall_tz();		if (firsttime) {			firsttime = 0;			if (!tv)				timekeeping_warp_clock();		}	}	if (tv)		return do_settimeofday64(tv);	return 0;} SYSCALL_DEFINE2(settimeofday, struct __kernel_old_timeval __user *, tv,		struct timezone __user *, tz){	struct timespec64 new_ts;	struct timezone new_tz; 	if (tv) {		if (get_user(new_ts.tv_sec, &tv->tv_sec) ||		    get_user(new_ts.tv_nsec, &tv->tv_usec))			return -EFAULT; 		if (new_ts.tv_nsec >= USEC_PER_SEC || new_ts.tv_nsec < 0)			return -EINVAL; 		new_ts.tv_nsec *= NSEC_PER_USEC;	}	if (tz) {		if (copy_from_user(&new_tz, tz, sizeof(*tz)))			return -EFAULT;	} 	return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);} #ifdef CONFIG_COMPATCOMPAT_SYSCALL_DEFINE2(gettimeofday, struct old_timeval32 __user *, tv,		       struct timezone __user *, tz){	if (tv) {		struct timespec64 ts; 		ktime_get_real_ts64(&ts);		if (put_user(ts.tv_sec, &tv->tv_sec) ||		    put_user(ts.tv_nsec / 1000, &tv->tv_usec))			return -EFAULT;	}	if (tz) {		if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))			return -EFAULT;	} 	return 0;} COMPAT_SYSCALL_DEFINE2(settimeofday, struct old_timeval32 __user *, tv,		       struct timezone __user *, tz){	struct timespec64 new_ts;	struct timezone new_tz; 	if (tv) {		if (get_user(new_ts.tv_sec, &tv->tv_sec) ||		    get_user(new_ts.tv_nsec, &tv->tv_usec))			return -EFAULT; 		if (new_ts.tv_nsec > USEC_PER_SEC || new_ts.tv_nsec < 0)			return -EINVAL; 		new_ts.tv_nsec *= NSEC_PER_USEC;	}	if (tz) {		if (copy_from_user(&new_tz, tz, sizeof(*tz)))			return -EFAULT;	} 	return do_sys_settimeofday64(tv ? &new_ts : NULL, tz ? &new_tz : NULL);}#endif #ifdef CONFIG_64BITSYSCALL_DEFINE1(adjtimex, struct __kernel_timex __user *, txc_p){	struct __kernel_timex txc;		/* Local copy of parameter */	int ret; 	/* Copy the user data space into the kernel copy	 * structure. But bear in mind that the structures	 * may change	 */	if (copy_from_user(&txc, txc_p, sizeof(struct __kernel_timex)))		return -EFAULT;	ret = do_adjtimex(&txc);	return copy_to_user(txc_p, &txc, sizeof(struct __kernel_timex)) ? -EFAULT : ret;}#endif #ifdef CONFIG_COMPAT_32BIT_TIMEint get_old_timex32(struct __kernel_timex *txc, const struct old_timex32 __user *utp){	struct old_timex32 tx32; 	memset(txc, 0, sizeof(struct __kernel_timex));	if (copy_from_user(&tx32, utp, sizeof(struct old_timex32)))		return -EFAULT; 	txc->modes = tx32.modes;	txc->offset = tx32.offset;	txc->freq = tx32.freq;	txc->maxerror = tx32.maxerror;	txc->esterror = tx32.esterror;	txc->status = tx32.status;	txc->constant = tx32.constant;	txc->precision = tx32.precision;	txc->tolerance = tx32.tolerance;	txc->time.tv_sec = tx32.time.tv_sec;	txc->time.tv_usec = tx32.time.tv_usec;	txc->tick = tx32.tick;	txc->ppsfreq = tx32.ppsfreq;	txc->jitter = tx32.jitter;	txc->shift = tx32.shift;	txc->stabil = tx32.stabil;	txc->jitcnt = tx32.jitcnt;	txc->calcnt = tx32.calcnt;	txc->errcnt = tx32.errcnt;	txc->stbcnt = tx32.stbcnt; 	return 0;} int put_old_timex32(struct old_timex32 __user *utp, const struct __kernel_timex *txc){	struct old_timex32 tx32; 	memset(&tx32, 0, sizeof(struct old_timex32));	tx32.modes = txc->modes;	tx32.offset = txc->offset;	tx32.freq = txc->freq;	tx32.maxerror = txc->maxerror;	tx32.esterror = txc->esterror;	tx32.status = txc->status;	tx32.constant = txc->constant;	tx32.precision = txc->precision;	tx32.tolerance = txc->tolerance;	tx32.time.tv_sec = txc->time.tv_sec;	tx32.time.tv_usec = txc->time.tv_usec;	tx32.tick = txc->tick;	tx32.ppsfreq = txc->ppsfreq;	tx32.jitter = txc->jitter;	tx32.shift = txc->shift;	tx32.stabil = txc->stabil;	tx32.jitcnt = txc->jitcnt;	tx32.calcnt = txc->calcnt;	tx32.errcnt = txc->errcnt;	tx32.stbcnt = txc->stbcnt;	tx32.tai = txc->tai;	if (copy_to_user(utp, &tx32, sizeof(struct old_timex32)))		return -EFAULT;	return 0;} SYSCALL_DEFINE1(adjtimex_time32, struct old_timex32 __user *, utp){	struct __kernel_timex txc;	int err, ret; 	err = get_old_timex32(&txc, utp);	if (err)		return err; 	ret = do_adjtimex(&txc); 	err = put_old_timex32(utp, &txc);	if (err)		return err; 	return ret;}#endif #if HZ > MSEC_PER_SEC || (MSEC_PER_SEC % HZ)/** * jiffies_to_msecs - Convert jiffies to milliseconds * @j: jiffies value * * Return: milliseconds value */unsigned int jiffies_to_msecs(const unsigned long j){#if HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)	return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);#else# if BITS_PER_LONG == 32	return (HZ_TO_MSEC_MUL32 * j + (1ULL << HZ_TO_MSEC_SHR32) - 1) >>	       HZ_TO_MSEC_SHR32;# else	return DIV_ROUND_UP(j * HZ_TO_MSEC_NUM, HZ_TO_MSEC_DEN);# endif#endif}EXPORT_SYMBOL(jiffies_to_msecs);#endif #if (USEC_PER_SEC % HZ)/** * jiffies_to_usecs - Convert jiffies to microseconds * @j: jiffies value * * Return: microseconds value */unsigned int jiffies_to_usecs(const unsigned long j){	/*	 * Hz usually doesn't go much further MSEC_PER_SEC.	 * jiffies_to_usecs() and usecs_to_jiffies() depend on that.	 */	BUILD_BUG_ON(HZ > USEC_PER_SEC); #if BITS_PER_LONG == 32	return (HZ_TO_USEC_MUL32 * j) >> HZ_TO_USEC_SHR32;#else	return (j * HZ_TO_USEC_NUM) / HZ_TO_USEC_DEN;#endif}EXPORT_SYMBOL(jiffies_to_usecs);#endif /** * mktime64 - Converts date to seconds. * @year0: year to convert * @mon0: month to convert * @day: day to convert * @hour: hour to convert * @min: minute to convert * @sec: second to convert * * Converts Gregorian date to seconds since 1970-01-01 00:00:00. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. * * [For the Julian calendar (which was used in Russia before 1917, * Britain & colonies before 1752, anywhere else before 1582, * and is still in use by some communities) leave out the * -year/100+year/400 terms, and add 10.] * * This algorithm was first published by Gauss (I think). * * A leap second can be indicated by calling this function with sec as * 60 (allowable under ISO 8601).  The leap second is treated the same * as the following second since they don't exist in UNIX time. * * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight * tomorrow - (allowable under ISO 8601) is supported. * * Return: seconds since the epoch time for the given input date */time64_t mktime64(const unsigned int year0, const unsigned int mon0,		const unsigned int day, const unsigned int hour,		const unsigned int min, const unsigned int sec){	unsigned int mon = mon0, year = year0; 	/* 1..12 -> 11,12,1..10 */	if (0 >= (int) (mon -= 2)) {		mon += 12;	/* Puts Feb last since it has leap day */		year -= 1;	} 	return ((((time64_t)		  (year/4 - year/100 + year/400 + 367*mon/12 + day) +		  year*365 - 719499	    )*24 + hour /* now have hours - midnight tomorrow handled here */	  )*60 + min /* now have minutes */	)*60 + sec; /* finally seconds */}EXPORT_SYMBOL(mktime64); struct __kernel_old_timeval ns_to_kernel_old_timeval(s64 nsec){	struct timespec64 ts = ns_to_timespec64(nsec);	struct __kernel_old_timeval tv; 	tv.tv_sec = ts.tv_sec;	tv.tv_usec = (suseconds_t)ts.tv_nsec / 1000; 	return tv;}EXPORT_SYMBOL(ns_to_kernel_old_timeval); /** * set_normalized_timespec64 - set timespec sec and nsec parts and normalize * * @ts:		pointer to timespec variable to be set * @sec:	seconds to set * @nsec:	nanoseconds to set * * Set seconds and nanoseconds field of a timespec variable and * normalize to the timespec storage format * * Note: The tv_nsec part is always in the range of 0 <= tv_nsec < NSEC_PER_SEC. * For negative values only the tv_sec field is negative ! */void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec){	while (nsec >= NSEC_PER_SEC) {		/*		 * The following asm() prevents the compiler from		 * optimising this loop into a modulo operation. See		 * also __iter_div_u64_rem() in include/linux/time.h		 */		asm("" : "+rm"(nsec));		nsec -= NSEC_PER_SEC;		++sec;

Lines 1–500 of 1052.