linux/arch/um/kernel/time.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
   3 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
   4 * Copyright (C) 2012-2014 Cisco Systems
   5 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   6 * Licensed under the GPL
   7 */
   8
   9#include <linux/clockchips.h>
  10#include <linux/init.h>
  11#include <linux/interrupt.h>
  12#include <linux/jiffies.h>
  13#include <linux/mm.h>
  14#include <linux/sched.h>
  15#include <linux/spinlock.h>
  16#include <linux/threads.h>
  17#include <asm/irq.h>
  18#include <asm/param.h>
  19#include <kern_util.h>
  20#include <os.h>
  21#include <timer-internal.h>
  22#include <shared/init.h>
  23
  24#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
  25enum time_travel_mode time_travel_mode;
  26unsigned long long time_travel_time;
  27enum time_travel_timer_mode time_travel_timer_mode;
  28unsigned long long time_travel_timer_expiry;
  29unsigned long long time_travel_timer_interval;
  30
  31static bool time_travel_start_set;
  32static unsigned long long time_travel_start;
  33#else
  34#define time_travel_start_set 0
  35#define time_travel_start 0
  36#endif
  37
  38void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
  39{
  40        unsigned long flags;
  41
  42        if (time_travel_mode != TT_MODE_OFF)
  43                time_travel_set_time(time_travel_timer_expiry);
  44
  45        local_irq_save(flags);
  46        do_IRQ(TIMER_IRQ, regs);
  47        local_irq_restore(flags);
  48}
  49
  50static int itimer_shutdown(struct clock_event_device *evt)
  51{
  52        if (time_travel_mode != TT_MODE_OFF)
  53                time_travel_set_timer_mode(TT_TMR_DISABLED);
  54
  55        if (time_travel_mode != TT_MODE_INFCPU)
  56                os_timer_disable();
  57
  58        return 0;
  59}
  60
  61static int itimer_set_periodic(struct clock_event_device *evt)
  62{
  63        unsigned long long interval = NSEC_PER_SEC / HZ;
  64
  65        if (time_travel_mode != TT_MODE_OFF) {
  66                time_travel_set_timer_mode(TT_TMR_PERIODIC);
  67                time_travel_set_timer_expiry(time_travel_time + interval);
  68        }
  69
  70        if (time_travel_mode != TT_MODE_INFCPU)
  71                os_timer_set_interval(interval);
  72
  73        return 0;
  74}
  75
  76static int itimer_next_event(unsigned long delta,
  77                             struct clock_event_device *evt)
  78{
  79        delta += 1;
  80
  81        if (time_travel_mode != TT_MODE_OFF) {
  82                time_travel_set_timer_mode(TT_TMR_ONESHOT);
  83                time_travel_set_timer_expiry(time_travel_time + delta);
  84        }
  85
  86        if (time_travel_mode != TT_MODE_INFCPU)
  87                return os_timer_one_shot(delta);
  88
  89        return 0;
  90}
  91
  92static int itimer_one_shot(struct clock_event_device *evt)
  93{
  94        return itimer_next_event(0, evt);
  95}
  96
  97static struct clock_event_device timer_clockevent = {
  98        .name                   = "posix-timer",
  99        .rating                 = 250,
 100        .cpumask                = cpu_possible_mask,
 101        .features               = CLOCK_EVT_FEAT_PERIODIC |
 102                                  CLOCK_EVT_FEAT_ONESHOT,
 103        .set_state_shutdown     = itimer_shutdown,
 104        .set_state_periodic     = itimer_set_periodic,
 105        .set_state_oneshot      = itimer_one_shot,
 106        .set_next_event         = itimer_next_event,
 107        .shift                  = 0,
 108        .max_delta_ns           = 0xffffffff,
 109        .max_delta_ticks        = 0xffffffff,
 110        .min_delta_ns           = TIMER_MIN_DELTA,
 111        .min_delta_ticks        = TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM
 112        .irq                    = 0,
 113        .mult                   = 1,
 114};
 115
 116static irqreturn_t um_timer(int irq, void *dev)
 117{
 118        if (get_current()->mm != NULL)
 119        {
 120        /* userspace - relay signal, results in correct userspace timers */
 121                os_alarm_process(get_current()->mm->context.id.u.pid);
 122        }
 123
 124        (*timer_clockevent.event_handler)(&timer_clockevent);
 125
 126        return IRQ_HANDLED;
 127}
 128
 129static u64 timer_read(struct clocksource *cs)
 130{
 131        if (time_travel_mode != TT_MODE_OFF) {
 132                /*
 133                 * We make reading the timer cost a bit so that we don't get
 134                 * stuck in loops that expect time to move more than the
 135                 * exact requested sleep amount, e.g. python's socket server,
 136                 * see https://bugs.python.org/issue37026.
 137                 */
 138                time_travel_set_time(time_travel_time + TIMER_MULTIPLIER);
 139                return time_travel_time / TIMER_MULTIPLIER;
 140        }
 141
 142        return os_nsecs() / TIMER_MULTIPLIER;
 143}
 144
 145static struct clocksource timer_clocksource = {
 146        .name           = "timer",
 147        .rating         = 300,
 148        .read           = timer_read,
 149        .mask           = CLOCKSOURCE_MASK(64),
 150        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 151};
 152
 153static void __init um_timer_setup(void)
 154{
 155        int err;
 156
 157        err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
 158        if (err != 0)
 159                printk(KERN_ERR "register_timer : request_irq failed - "
 160                       "errno = %d\n", -err);
 161
 162        err = os_timer_create();
 163        if (err != 0) {
 164                printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
 165                return;
 166        }
 167
 168        err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
 169        if (err) {
 170                printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
 171                return;
 172        }
 173        clockevents_register_device(&timer_clockevent);
 174}
 175
 176void read_persistent_clock64(struct timespec64 *ts)
 177{
 178        long long nsecs;
 179
 180        if (time_travel_start_set)
 181                nsecs = time_travel_start + time_travel_time;
 182        else
 183                nsecs = os_persistent_clock_emulation();
 184
 185        set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
 186                                  nsecs % NSEC_PER_SEC);
 187}
 188
 189void __init time_init(void)
 190{
 191        timer_set_signal_handler();
 192        late_time_init = um_timer_setup;
 193}
 194
 195#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
 196unsigned long calibrate_delay_is_known(void)
 197{
 198        if (time_travel_mode == TT_MODE_INFCPU)
 199                return 1;
 200        return 0;
 201}
 202
 203int setup_time_travel(char *str)
 204{
 205        if (strcmp(str, "=inf-cpu") == 0) {
 206                time_travel_mode = TT_MODE_INFCPU;
 207                timer_clockevent.name = "time-travel-timer-infcpu";
 208                timer_clocksource.name = "time-travel-clock";
 209                return 1;
 210        }
 211
 212        if (!*str) {
 213                time_travel_mode = TT_MODE_BASIC;
 214                timer_clockevent.name = "time-travel-timer";
 215                timer_clocksource.name = "time-travel-clock";
 216                return 1;
 217        }
 218
 219        return -EINVAL;
 220}
 221
 222__setup("time-travel", setup_time_travel);
 223__uml_help(setup_time_travel,
 224"time-travel\n"
 225"This option just enables basic time travel mode, in which the clock/timers\n"
 226"inside the UML instance skip forward when there's nothing to do, rather than\n"
 227"waiting for real time to elapse. However, instance CPU speed is limited by\n"
 228"the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
 229"clock (but quicker when there's nothing to do).\n"
 230"\n"
 231"time-travel=inf-cpu\n"
 232"This enables time travel mode with infinite processing power, in which there\n"
 233"are no wall clock timers, and any CPU processing happens - as seen from the\n"
 234"guest - instantly. This can be useful for accurate simulation regardless of\n"
 235"debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
 236"easily lead to getting stuck (e.g. if anything in the system busy loops).\n");
 237
 238int setup_time_travel_start(char *str)
 239{
 240        int err;
 241
 242        err = kstrtoull(str, 0, &time_travel_start);
 243        if (err)
 244                return err;
 245
 246        time_travel_start_set = 1;
 247        return 1;
 248}
 249
 250__setup("time-travel-start", setup_time_travel_start);
 251__uml_help(setup_time_travel_start,
 252"time-travel-start=<seconds>\n"
 253"Configure the UML instance's wall clock to start at this value rather than\n"
 254"the host's wall clock at the time of UML boot.\n");
 255#endif
 256