2006-01-18 17:42:42 -08:00
/*
2015-11-02 16:16:37 +00:00
* Copyright ( C ) 2015 Anton Ivanov ( aivanov @ { brocade . com , kot - begemot . co . uk } )
* Copyright ( C ) 2015 Thomas Meyer ( thomas @ m3y3r . de )
* Copyright ( C ) 2012 - 2014 Cisco Systems
2007-10-16 01:27:00 -07:00
* Copyright ( C ) 2000 - 2007 Jeff Dike ( jdike @ { addtoit , linux . intel } . com )
2005-04-16 15:20:36 -07:00
* Licensed under the GPL
*/
2008-02-04 22:31:14 -08:00
# include <linux/clockchips.h>
2008-04-29 00:59:18 -07:00
# include <linux/init.h>
2008-02-04 22:31:14 -08:00
# include <linux/interrupt.h>
# include <linux/jiffies.h>
2015-11-02 16:16:37 +00:00
# include <linux/mm.h>
# include <linux/sched.h>
# include <linux/spinlock.h>
2008-02-04 22:31:14 -08:00
# include <linux/threads.h>
# include <asm/irq.h>
# include <asm/param.h>
2012-10-08 03:27:32 +01:00
# include <kern_util.h>
# include <os.h>
2015-11-02 16:16:37 +00:00
# include <timer-internal.h>
2019-05-27 10:34:27 +02:00
# include <shared/init.h>
# ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
enum time_travel_mode time_travel_mode ;
unsigned long long time_travel_time ;
enum time_travel_timer_mode time_travel_timer_mode ;
unsigned long long time_travel_timer_expiry ;
unsigned long long time_travel_timer_interval ;
static bool time_travel_start_set ;
static unsigned long long time_travel_start ;
# else
# define time_travel_start_set 0
# define time_travel_start 0
# endif
2005-04-16 15:20:36 -07:00
2012-08-02 00:49:17 +02:00
void timer_handler ( int sig , struct siginfo * unused_si , struct uml_pt_regs * regs )
2005-04-16 15:20:36 -07:00
{
2007-10-16 01:27:24 -07:00
unsigned long flags ;
2019-05-27 10:34:27 +02:00
if ( time_travel_mode ! = TT_MODE_OFF )
time_travel_set_time ( time_travel_timer_expiry ) ;
2007-10-16 01:27:24 -07:00
local_irq_save ( flags ) ;
2007-10-16 01:27:25 -07:00
do_IRQ ( TIMER_IRQ , regs ) ;
2007-10-16 01:27:24 -07:00
local_irq_restore ( flags ) ;
2005-04-16 15:20:36 -07:00
}
2015-07-16 16:56:31 +05:30
static int itimer_shutdown ( struct clock_event_device * evt )
2006-01-18 17:42:42 -08:00
{
2019-05-27 10:34:27 +02:00
if ( time_travel_mode ! = TT_MODE_OFF )
time_travel_set_timer ( TT_TMR_DISABLED , 0 ) ;
if ( time_travel_mode ! = TT_MODE_INFCPU )
os_timer_disable ( ) ;
2015-07-16 16:56:31 +05:30
return 0 ;
}
2007-10-16 01:27:24 -07:00
2015-07-16 16:56:31 +05:30
static int itimer_set_periodic ( struct clock_event_device * evt )
{
2019-05-27 10:34:27 +02:00
unsigned long long interval = NSEC_PER_SEC / HZ ;
if ( time_travel_mode ! = TT_MODE_OFF )
time_travel_set_timer ( TT_TMR_PERIODIC ,
time_travel_time + interval ) ;
if ( time_travel_mode ! = TT_MODE_INFCPU )
os_timer_set_interval ( interval ) ;
2015-07-16 16:56:31 +05:30
return 0 ;
2006-01-18 17:42:42 -08:00
}
2007-10-16 01:27:25 -07:00
static int itimer_next_event ( unsigned long delta ,
struct clock_event_device * evt )
{
2019-05-27 10:34:27 +02:00
delta + = 1 ;
if ( time_travel_mode ! = TT_MODE_OFF )
time_travel_set_timer ( TT_TMR_ONESHOT ,
time_travel_time + delta ) ;
if ( time_travel_mode ! = TT_MODE_INFCPU )
return os_timer_one_shot ( delta ) ;
return 0 ;
2007-10-16 01:27:25 -07:00
}
2015-11-02 16:16:37 +00:00
static int itimer_one_shot ( struct clock_event_device * evt )
{
2019-05-27 10:34:27 +02:00
return itimer_next_event ( 0 , evt ) ;
2015-11-02 16:16:37 +00:00
}
static struct clock_event_device timer_clockevent = {
. name = " posix-timer " ,
2015-07-16 16:56:31 +05:30
. rating = 250 ,
2019-04-10 11:11:23 -07:00
. cpumask = cpu_possible_mask ,
2015-07-16 16:56:31 +05:30
. features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT ,
. set_state_shutdown = itimer_shutdown ,
. set_state_periodic = itimer_set_periodic ,
2015-11-02 16:16:37 +00:00
. set_state_oneshot = itimer_one_shot ,
2015-07-16 16:56:31 +05:30
. set_next_event = itimer_next_event ,
2015-11-02 16:16:37 +00:00
. shift = 0 ,
. max_delta_ns = 0xffffffff ,
2017-03-30 21:59:42 +02:00
. max_delta_ticks = 0xffffffff ,
. min_delta_ns = TIMER_MIN_DELTA ,
. min_delta_ticks = TIMER_MIN_DELTA , // microsecond resolution should be enough for anyone, same as 640K RAM
2015-07-16 16:56:31 +05:30
. irq = 0 ,
2015-11-02 16:16:37 +00:00
. mult = 1 ,
2007-10-16 01:27:24 -07:00
} ;
static irqreturn_t um_timer ( int irq , void * dev )
2005-04-16 15:20:36 -07:00
{
2015-11-02 16:16:37 +00:00
if ( get_current ( ) - > mm ! = NULL )
{
/* userspace - relay signal, results in correct userspace timers */
os_alarm_process ( get_current ( ) - > mm - > context . id . u . pid ) ;
}
( * timer_clockevent . event_handler ) ( & timer_clockevent ) ;
2006-01-18 17:42:42 -08:00
2006-06-30 01:55:56 -07:00
return IRQ_HANDLED ;
2005-04-16 15:20:36 -07:00
}
2016-12-21 20:32:01 +01:00
static u64 timer_read ( struct clocksource * cs )
2007-10-16 01:27:25 -07:00
{
2019-05-27 10:34:27 +02:00
if ( time_travel_mode ! = TT_MODE_OFF ) {
/*
* We make reading the timer cost a bit so that we don ' t get
* stuck in loops that expect time to move more than the
* exact requested sleep amount , e . g . python ' s socket server ,
* see https : //bugs.python.org/issue37026.
*/
time_travel_set_time ( time_travel_time + TIMER_MULTIPLIER ) ;
return time_travel_time / TIMER_MULTIPLIER ;
}
2015-11-02 16:16:37 +00:00
return os_nsecs ( ) / TIMER_MULTIPLIER ;
2007-10-16 01:27:25 -07:00
}
2015-11-02 16:16:37 +00:00
static struct clocksource timer_clocksource = {
. name = " timer " ,
2007-10-16 01:27:25 -07:00
. rating = 300 ,
2015-11-02 16:16:37 +00:00
. read = timer_read ,
2007-10-16 01:27:25 -07:00
. mask = CLOCKSOURCE_MASK ( 64 ) ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2017-09-29 10:07:44 +02:00
static void __init um_timer_setup ( void )
2006-07-10 04:45:05 -07:00
{
int err ;
2015-11-02 16:16:37 +00:00
err = request_irq ( TIMER_IRQ , um_timer , IRQF_TIMER , " hr timer " , NULL ) ;
2007-10-16 01:27:00 -07:00
if ( err ! = 0 )
2006-09-25 23:33:05 -07:00
printk ( KERN_ERR " register_timer : request_irq failed - "
2006-07-10 04:45:05 -07:00
" errno = %d \n " , - err ) ;
2019-05-06 14:39:38 +02:00
err = os_timer_create ( ) ;
2015-11-02 16:16:37 +00:00
if ( err ! = 0 ) {
printk ( KERN_ERR " creation of timer failed - errno = %d \n " , - err ) ;
return ;
}
err = clocksource_register_hz ( & timer_clocksource , NSEC_PER_SEC / TIMER_MULTIPLIER ) ;
2007-10-16 01:27:25 -07:00
if ( err ) {
2010-04-26 20:25:16 -07:00
printk ( KERN_ERR " clocksource_register_hz returned %d \n " , err ) ;
2007-10-16 01:27:25 -07:00
return ;
}
2015-11-02 16:16:37 +00:00
clockevents_register_device ( & timer_clockevent ) ;
2006-07-10 04:45:05 -07:00
}
2017-11-02 13:07:02 +01:00
void read_persistent_clock64 ( struct timespec64 * ts )
2010-07-13 17:56:24 -07:00
{
2019-05-27 10:34:27 +02:00
long long nsecs ;
if ( time_travel_start_set )
nsecs = time_travel_start + time_travel_time ;
else
nsecs = os_persistent_clock_emulation ( ) ;
2010-08-03 20:34:48 +02:00
2017-11-02 13:07:02 +01:00
set_normalized_timespec64 ( ts , nsecs / NSEC_PER_SEC ,
nsecs % NSEC_PER_SEC ) ;
2010-07-13 17:56:24 -07:00
}
2007-10-16 01:27:24 -07:00
void __init time_init ( void )
2006-07-10 04:45:05 -07:00
{
2015-11-02 16:16:37 +00:00
timer_set_signal_handler ( ) ;
2017-09-29 10:07:44 +02:00
late_time_init = um_timer_setup ;
2005-04-16 15:20:36 -07:00
}
2019-05-27 10:34:27 +02:00
# ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
unsigned long calibrate_delay_is_known ( void )
{
if ( time_travel_mode = = TT_MODE_INFCPU )
return 1 ;
return 0 ;
}
int setup_time_travel ( char * str )
{
if ( strcmp ( str , " =inf-cpu " ) = = 0 ) {
time_travel_mode = TT_MODE_INFCPU ;
timer_clockevent . name = " time-travel-timer-infcpu " ;
timer_clocksource . name = " time-travel-clock " ;
return 1 ;
}
if ( ! * str ) {
time_travel_mode = TT_MODE_BASIC ;
timer_clockevent . name = " time-travel-timer " ;
timer_clocksource . name = " time-travel-clock " ;
return 1 ;
}
return - EINVAL ;
}
__setup ( " time-travel " , setup_time_travel ) ;
__uml_help ( setup_time_travel ,
" time-travel \n "
" This option just enables basic time travel mode, in which the clock/timers \n "
" inside the UML instance skip forward when there's nothing to do, rather than \n "
" waiting for real time to elapse. However, instance CPU speed is limited by \n "
" the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall \n "
" clock (but quicker when there's nothing to do). \n "
" \n "
" time-travel=inf-cpu \n "
" This enables time travel mode with infinite processing power, in which there \n "
" are no wall clock timers, and any CPU processing happens - as seen from the \n "
" guest - instantly. This can be useful for accurate simulation regardless of \n "
" debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can \n "
" easily lead to getting stuck (e.g. if anything in the system busy loops). \n " ) ;
int setup_time_travel_start ( char * str )
{
int err ;
err = kstrtoull ( str , 0 , & time_travel_start ) ;
if ( err )
return err ;
time_travel_start_set = 1 ;
return 1 ;
}
__setup ( " time-travel-start " , setup_time_travel_start ) ;
__uml_help ( setup_time_travel_start ,
" time-travel-start=<seconds> \n "
" Configure the UML instance's wall clock to start at this value rather than \n "
" the host's wall clock at the time of UML boot. \n " ) ;
# endif