aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/kernel/time.c')
-rw-r--r--arch/um/kernel/time.c131
1 files changed, 124 insertions, 7 deletions
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 0c572a48158e..6a051b078359 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -19,11 +19,29 @@
19#include <kern_util.h> 19#include <kern_util.h>
20#include <os.h> 20#include <os.h>
21#include <timer-internal.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
22 37
23void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs) 38void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
24{ 39{
25 unsigned long flags; 40 unsigned long flags;
26 41
42 if (time_travel_mode != TT_MODE_OFF)
43 time_travel_set_time(time_travel_timer_expiry);
44
27 local_irq_save(flags); 45 local_irq_save(flags);
28 do_IRQ(TIMER_IRQ, regs); 46 do_IRQ(TIMER_IRQ, regs);
29 local_irq_restore(flags); 47 local_irq_restore(flags);
@@ -31,26 +49,47 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
31 49
32static int itimer_shutdown(struct clock_event_device *evt) 50static int itimer_shutdown(struct clock_event_device *evt)
33{ 51{
34 os_timer_disable(); 52 if (time_travel_mode != TT_MODE_OFF)
53 time_travel_set_timer(TT_TMR_DISABLED, 0);
54
55 if (time_travel_mode != TT_MODE_INFCPU)
56 os_timer_disable();
57
35 return 0; 58 return 0;
36} 59}
37 60
38static int itimer_set_periodic(struct clock_event_device *evt) 61static int itimer_set_periodic(struct clock_event_device *evt)
39{ 62{
40 os_timer_set_interval(NULL, NULL); 63 unsigned long long interval = NSEC_PER_SEC / HZ;
64
65 if (time_travel_mode != TT_MODE_OFF)
66 time_travel_set_timer(TT_TMR_PERIODIC,
67 time_travel_time + interval);
68
69 if (time_travel_mode != TT_MODE_INFCPU)
70 os_timer_set_interval(interval);
71
41 return 0; 72 return 0;
42} 73}
43 74
44static int itimer_next_event(unsigned long delta, 75static int itimer_next_event(unsigned long delta,
45 struct clock_event_device *evt) 76 struct clock_event_device *evt)
46{ 77{
47 return os_timer_one_shot(delta); 78 delta += 1;
79
80 if (time_travel_mode != TT_MODE_OFF)
81 time_travel_set_timer(TT_TMR_ONESHOT,
82 time_travel_time + delta);
83
84 if (time_travel_mode != TT_MODE_INFCPU)
85 return os_timer_one_shot(delta);
86
87 return 0;
48} 88}
49 89
50static int itimer_one_shot(struct clock_event_device *evt) 90static int itimer_one_shot(struct clock_event_device *evt)
51{ 91{
52 os_timer_one_shot(1); 92 return itimer_next_event(0, evt);
53 return 0;
54} 93}
55 94
56static struct clock_event_device timer_clockevent = { 95static struct clock_event_device timer_clockevent = {
@@ -87,6 +126,17 @@ static irqreturn_t um_timer(int irq, void *dev)
87 126
88static u64 timer_read(struct clocksource *cs) 127static u64 timer_read(struct clocksource *cs)
89{ 128{
129 if (time_travel_mode != TT_MODE_OFF) {
130 /*
131 * We make reading the timer cost a bit so that we don't get
132 * stuck in loops that expect time to move more than the
133 * exact requested sleep amount, e.g. python's socket server,
134 * see https://bugs.python.org/issue37026.
135 */
136 time_travel_set_time(time_travel_time + TIMER_MULTIPLIER);
137 return time_travel_time / TIMER_MULTIPLIER;
138 }
139
90 return os_nsecs() / TIMER_MULTIPLIER; 140 return os_nsecs() / TIMER_MULTIPLIER;
91} 141}
92 142
@@ -107,7 +157,7 @@ static void __init um_timer_setup(void)
107 printk(KERN_ERR "register_timer : request_irq failed - " 157 printk(KERN_ERR "register_timer : request_irq failed - "
108 "errno = %d\n", -err); 158 "errno = %d\n", -err);
109 159
110 err = os_timer_create(NULL); 160 err = os_timer_create();
111 if (err != 0) { 161 if (err != 0) {
112 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err); 162 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
113 return; 163 return;
@@ -123,7 +173,12 @@ static void __init um_timer_setup(void)
123 173
124void read_persistent_clock64(struct timespec64 *ts) 174void read_persistent_clock64(struct timespec64 *ts)
125{ 175{
126 long long nsecs = os_persistent_clock_emulation(); 176 long long nsecs;
177
178 if (time_travel_start_set)
179 nsecs = time_travel_start + time_travel_time;
180 else
181 nsecs = os_persistent_clock_emulation();
127 182
128 set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC, 183 set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
129 nsecs % NSEC_PER_SEC); 184 nsecs % NSEC_PER_SEC);
@@ -134,3 +189,65 @@ void __init time_init(void)
134 timer_set_signal_handler(); 189 timer_set_signal_handler();
135 late_time_init = um_timer_setup; 190 late_time_init = um_timer_setup;
136} 191}
192
193#ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
194unsigned long calibrate_delay_is_known(void)
195{
196 if (time_travel_mode == TT_MODE_INFCPU)
197 return 1;
198 return 0;
199}
200
201int setup_time_travel(char *str)
202{
203 if (strcmp(str, "=inf-cpu") == 0) {
204 time_travel_mode = TT_MODE_INFCPU;
205 timer_clockevent.name = "time-travel-timer-infcpu";
206 timer_clocksource.name = "time-travel-clock";
207 return 1;
208 }
209
210 if (!*str) {
211 time_travel_mode = TT_MODE_BASIC;
212 timer_clockevent.name = "time-travel-timer";
213 timer_clocksource.name = "time-travel-clock";
214 return 1;
215 }
216
217 return -EINVAL;
218}
219
220__setup("time-travel", setup_time_travel);
221__uml_help(setup_time_travel,
222"time-travel\n"
223"This option just enables basic time travel mode, in which the clock/timers\n"
224"inside the UML instance skip forward when there's nothing to do, rather than\n"
225"waiting for real time to elapse. However, instance CPU speed is limited by\n"
226"the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
227"clock (but quicker when there's nothing to do).\n"
228"\n"
229"time-travel=inf-cpu\n"
230"This enables time travel mode with infinite processing power, in which there\n"
231"are no wall clock timers, and any CPU processing happens - as seen from the\n"
232"guest - instantly. This can be useful for accurate simulation regardless of\n"
233"debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
234"easily lead to getting stuck (e.g. if anything in the system busy loops).\n");
235
236int setup_time_travel_start(char *str)
237{
238 int err;
239
240 err = kstrtoull(str, 0, &time_travel_start);
241 if (err)
242 return err;
243
244 time_travel_start_set = 1;
245 return 1;
246}
247
248__setup("time-travel-start", setup_time_travel_start);
249__uml_help(setup_time_travel_start,
250"time-travel-start=<seconds>\n"
251"Configure the UML instance's wall clock to start at this value rather than\n"
252"the host's wall clock at the time of UML boot.\n");
253#endif