1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
4 * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
5 * Copyright (C) 2012-2014 Cisco Systems
6 * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
7 * Copyright (C) 2019 Intel Corporation
8 */
9
10 #include <linux/clockchips.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/jiffies.h>
14 #include <linux/mm.h>
15 #include <linux/sched.h>
16 #include <linux/spinlock.h>
17 #include <linux/threads.h>
18 #include <asm/irq.h>
19 #include <asm/param.h>
20 #include <kern_util.h>
21 #include <os.h>
22 #include <linux/time-internal.h>
23 #include <linux/um_timetravel.h>
24 #include <shared/init.h>
25
26 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
27 enum time_travel_mode time_travel_mode;
28 EXPORT_SYMBOL_GPL(time_travel_mode);
29
30 static bool time_travel_start_set;
31 static unsigned long long time_travel_start;
32 static unsigned long long time_travel_time;
33 static LIST_HEAD(time_travel_events);
34 static unsigned long long time_travel_timer_interval;
35 static unsigned long long time_travel_next_event;
36 static struct time_travel_event time_travel_timer_event;
37 static int time_travel_ext_fd = -1;
38 static unsigned int time_travel_ext_waiting;
39 static bool time_travel_ext_prev_request_valid;
40 static unsigned long long time_travel_ext_prev_request;
41 static bool time_travel_ext_free_until_valid;
42 static unsigned long long time_travel_ext_free_until;
43
time_travel_set_time(unsigned long long ns)44 static void time_travel_set_time(unsigned long long ns)
45 {
46 if (unlikely(ns < time_travel_time))
47 panic("time-travel: time goes backwards %lld -> %lld\n",
48 time_travel_time, ns);
49 time_travel_time = ns;
50 }
51
52 enum time_travel_message_handling {
53 TTMH_IDLE,
54 TTMH_POLL,
55 TTMH_READ,
56 };
57
time_travel_handle_message(struct um_timetravel_msg * msg,enum time_travel_message_handling mode)58 static void time_travel_handle_message(struct um_timetravel_msg *msg,
59 enum time_travel_message_handling mode)
60 {
61 struct um_timetravel_msg resp = {
62 .op = UM_TIMETRAVEL_ACK,
63 };
64 int ret;
65
66 /*
67 * Poll outside the locked section (if we're not called to only read
68 * the response) so we can get interrupts for e.g. virtio while we're
69 * here, but then we need to lock to not get interrupted between the
70 * read of the message and write of the ACK.
71 */
72 if (mode != TTMH_READ) {
73 bool disabled = irqs_disabled();
74
75 BUG_ON(mode == TTMH_IDLE && !disabled);
76
77 if (disabled)
78 local_irq_enable();
79 while (os_poll(1, &time_travel_ext_fd) != 0) {
80 /* nothing */
81 }
82 if (disabled)
83 local_irq_disable();
84 }
85
86 ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg));
87
88 if (ret == 0)
89 panic("time-travel external link is broken\n");
90 if (ret != sizeof(*msg))
91 panic("invalid time-travel message - %d bytes\n", ret);
92
93 switch (msg->op) {
94 default:
95 WARN_ONCE(1, "time-travel: unexpected message %lld\n",
96 (unsigned long long)msg->op);
97 break;
98 case UM_TIMETRAVEL_ACK:
99 return;
100 case UM_TIMETRAVEL_RUN:
101 time_travel_set_time(msg->time);
102 break;
103 case UM_TIMETRAVEL_FREE_UNTIL:
104 time_travel_ext_free_until_valid = true;
105 time_travel_ext_free_until = msg->time;
106 break;
107 }
108
109 resp.seq = msg->seq;
110 os_write_file(time_travel_ext_fd, &resp, sizeof(resp));
111 }
112
time_travel_ext_req(u32 op,u64 time)113 static u64 time_travel_ext_req(u32 op, u64 time)
114 {
115 static int seq;
116 int mseq = ++seq;
117 struct um_timetravel_msg msg = {
118 .op = op,
119 .time = time,
120 .seq = mseq,
121 };
122 unsigned long flags;
123
124 /*
125 * We need to save interrupts here and only restore when we
126 * got the ACK - otherwise we can get interrupted and send
127 * another request while we're still waiting for an ACK, but
128 * the peer doesn't know we got interrupted and will send
129 * the ACKs in the same order as the message, but we'd need
130 * to see them in the opposite order ...
131 *
132 * This wouldn't matter *too* much, but some ACKs carry the
133 * current time (for UM_TIMETRAVEL_GET) and getting another
134 * ACK without a time would confuse us a lot!
135 *
136 * The sequence number assignment that happens here lets us
137 * debug such message handling issues more easily.
138 */
139 local_irq_save(flags);
140 os_write_file(time_travel_ext_fd, &msg, sizeof(msg));
141
142 while (msg.op != UM_TIMETRAVEL_ACK)
143 time_travel_handle_message(&msg, TTMH_READ);
144
145 if (msg.seq != mseq)
146 panic("time-travel: ACK message has different seqno! op=%d, seq=%d != %d time=%lld\n",
147 msg.op, msg.seq, mseq, msg.time);
148
149 if (op == UM_TIMETRAVEL_GET)
150 time_travel_set_time(msg.time);
151 local_irq_restore(flags);
152
153 return msg.time;
154 }
155
__time_travel_wait_readable(int fd)156 void __time_travel_wait_readable(int fd)
157 {
158 int fds[2] = { fd, time_travel_ext_fd };
159 int ret;
160
161 if (time_travel_mode != TT_MODE_EXTERNAL)
162 return;
163
164 while ((ret = os_poll(2, fds))) {
165 struct um_timetravel_msg msg;
166
167 if (ret == 1)
168 time_travel_handle_message(&msg, TTMH_READ);
169 }
170 }
171 EXPORT_SYMBOL_GPL(__time_travel_wait_readable);
172
time_travel_ext_update_request(unsigned long long time)173 static void time_travel_ext_update_request(unsigned long long time)
174 {
175 if (time_travel_mode != TT_MODE_EXTERNAL)
176 return;
177
178 /* asked for exactly this time previously */
179 if (time_travel_ext_prev_request_valid &&
180 time == time_travel_ext_prev_request)
181 return;
182
183 time_travel_ext_prev_request = time;
184 time_travel_ext_prev_request_valid = true;
185 time_travel_ext_req(UM_TIMETRAVEL_REQUEST, time);
186 }
187
__time_travel_propagate_time(void)188 void __time_travel_propagate_time(void)
189 {
190 time_travel_ext_req(UM_TIMETRAVEL_UPDATE, time_travel_time);
191 }
192 EXPORT_SYMBOL_GPL(__time_travel_propagate_time);
193
194 /* returns true if we must do a wait to the simtime device */
time_travel_ext_request(unsigned long long time)195 static bool time_travel_ext_request(unsigned long long time)
196 {
197 /*
198 * If we received an external sync point ("free until") then we
199 * don't have to request/wait for anything until then, unless
200 * we're already waiting.
201 */
202 if (!time_travel_ext_waiting && time_travel_ext_free_until_valid &&
203 time < time_travel_ext_free_until)
204 return false;
205
206 time_travel_ext_update_request(time);
207 return true;
208 }
209
time_travel_ext_wait(bool idle)210 static void time_travel_ext_wait(bool idle)
211 {
212 struct um_timetravel_msg msg = {
213 .op = UM_TIMETRAVEL_ACK,
214 };
215
216 time_travel_ext_prev_request_valid = false;
217 time_travel_ext_waiting++;
218
219 time_travel_ext_req(UM_TIMETRAVEL_WAIT, -1);
220
221 /*
222 * Here we are deep in the idle loop, so we have to break out of the
223 * kernel abstraction in a sense and implement this in terms of the
224 * UML system waiting on the VQ interrupt while sleeping, when we get
225 * the signal it'll call time_travel_ext_vq_notify_done() completing the
226 * call.
227 */
228 while (msg.op != UM_TIMETRAVEL_RUN)
229 time_travel_handle_message(&msg, idle ? TTMH_IDLE : TTMH_POLL);
230
231 time_travel_ext_waiting--;
232
233 /* we might request more stuff while polling - reset when we run */
234 time_travel_ext_prev_request_valid = false;
235 }
236
time_travel_ext_get_time(void)237 static void time_travel_ext_get_time(void)
238 {
239 time_travel_ext_req(UM_TIMETRAVEL_GET, -1);
240 }
241
__time_travel_update_time(unsigned long long ns,bool idle)242 static void __time_travel_update_time(unsigned long long ns, bool idle)
243 {
244 if (time_travel_mode == TT_MODE_EXTERNAL && time_travel_ext_request(ns))
245 time_travel_ext_wait(idle);
246 else
247 time_travel_set_time(ns);
248 }
249
time_travel_first_event(void)250 static struct time_travel_event *time_travel_first_event(void)
251 {
252 return list_first_entry_or_null(&time_travel_events,
253 struct time_travel_event,
254 list);
255 }
256
__time_travel_add_event(struct time_travel_event * e,unsigned long long time)257 static void __time_travel_add_event(struct time_travel_event *e,
258 unsigned long long time)
259 {
260 struct time_travel_event *tmp;
261 bool inserted = false;
262
263 if (WARN(time_travel_mode == TT_MODE_BASIC &&
264 e != &time_travel_timer_event,
265 "only timer events can be handled in basic mode"))
266 return;
267
268 if (e->pending)
269 return;
270
271 e->pending = true;
272 e->time = time;
273
274 list_for_each_entry(tmp, &time_travel_events, list) {
275 /*
276 * Add the new entry before one with higher time,
277 * or if they're equal and both on stack, because
278 * in that case we need to unwind the stack in the
279 * right order, and the later event (timer sleep
280 * or such) must be dequeued first.
281 */
282 if ((tmp->time > e->time) ||
283 (tmp->time == e->time && tmp->onstack && e->onstack)) {
284 list_add_tail(&e->list, &tmp->list);
285 inserted = true;
286 break;
287 }
288 }
289
290 if (!inserted)
291 list_add_tail(&e->list, &time_travel_events);
292
293 tmp = time_travel_first_event();
294 time_travel_ext_update_request(tmp->time);
295 time_travel_next_event = tmp->time;
296 }
297
time_travel_add_event(struct time_travel_event * e,unsigned long long time)298 static void time_travel_add_event(struct time_travel_event *e,
299 unsigned long long time)
300 {
301 if (WARN_ON(!e->fn))
302 return;
303
304 __time_travel_add_event(e, time);
305 }
306
time_travel_periodic_timer(struct time_travel_event * e)307 void time_travel_periodic_timer(struct time_travel_event *e)
308 {
309 time_travel_add_event(&time_travel_timer_event,
310 time_travel_time + time_travel_timer_interval);
311 deliver_alarm();
312 }
313
time_travel_deliver_event(struct time_travel_event * e)314 static void time_travel_deliver_event(struct time_travel_event *e)
315 {
316 if (e == &time_travel_timer_event) {
317 /*
318 * deliver_alarm() does the irq_enter/irq_exit
319 * by itself, so must handle it specially here
320 */
321 e->fn(e);
322 } else {
323 unsigned long flags;
324
325 local_irq_save(flags);
326 irq_enter();
327 e->fn(e);
328 irq_exit();
329 local_irq_restore(flags);
330 }
331 }
332
time_travel_del_event(struct time_travel_event * e)333 static bool time_travel_del_event(struct time_travel_event *e)
334 {
335 if (!e->pending)
336 return false;
337 list_del(&e->list);
338 e->pending = false;
339 return true;
340 }
341
time_travel_update_time(unsigned long long next,bool idle)342 static void time_travel_update_time(unsigned long long next, bool idle)
343 {
344 struct time_travel_event ne = {
345 .onstack = true,
346 };
347 struct time_travel_event *e;
348 bool finished = idle;
349
350 /* add it without a handler - we deal with that specifically below */
351 __time_travel_add_event(&ne, next);
352
353 do {
354 e = time_travel_first_event();
355
356 BUG_ON(!e);
357 __time_travel_update_time(e->time, idle);
358
359 /* new events may have been inserted while we were waiting */
360 if (e == time_travel_first_event()) {
361 BUG_ON(!time_travel_del_event(e));
362 BUG_ON(time_travel_time != e->time);
363
364 if (e == &ne) {
365 finished = true;
366 } else {
367 if (e->onstack)
368 panic("On-stack event dequeued outside of the stack! time=%lld, event time=%lld, event=%pS\n",
369 time_travel_time, e->time, e);
370 time_travel_deliver_event(e);
371 }
372 }
373
374 e = time_travel_first_event();
375 if (e)
376 time_travel_ext_update_request(e->time);
377 } while (ne.pending && !finished);
378
379 time_travel_del_event(&ne);
380 }
381
time_travel_ndelay(unsigned long nsec)382 void time_travel_ndelay(unsigned long nsec)
383 {
384 time_travel_update_time(time_travel_time + nsec, false);
385 }
386 EXPORT_SYMBOL(time_travel_ndelay);
387
time_travel_add_irq_event(struct time_travel_event * e)388 void time_travel_add_irq_event(struct time_travel_event *e)
389 {
390 BUG_ON(time_travel_mode != TT_MODE_EXTERNAL);
391
392 time_travel_ext_get_time();
393 /*
394 * We could model interrupt latency here, for now just
395 * don't have any latency at all and request the exact
396 * same time (again) to run the interrupt...
397 */
398 time_travel_add_event(e, time_travel_time);
399 }
400 EXPORT_SYMBOL_GPL(time_travel_add_irq_event);
401
time_travel_oneshot_timer(struct time_travel_event * e)402 static void time_travel_oneshot_timer(struct time_travel_event *e)
403 {
404 deliver_alarm();
405 }
406
time_travel_sleep(unsigned long long duration)407 void time_travel_sleep(unsigned long long duration)
408 {
409 unsigned long long next = time_travel_time + duration;
410
411 if (time_travel_mode == TT_MODE_BASIC)
412 os_timer_disable();
413
414 time_travel_update_time(next, true);
415
416 if (time_travel_mode == TT_MODE_BASIC &&
417 time_travel_timer_event.pending) {
418 if (time_travel_timer_event.fn == time_travel_periodic_timer) {
419 /*
420 * This is somewhat wrong - we should get the first
421 * one sooner like the os_timer_one_shot() below...
422 */
423 os_timer_set_interval(time_travel_timer_interval);
424 } else {
425 os_timer_one_shot(time_travel_timer_event.time - next);
426 }
427 }
428 }
429
time_travel_handle_real_alarm(void)430 static void time_travel_handle_real_alarm(void)
431 {
432 time_travel_set_time(time_travel_next_event);
433
434 time_travel_del_event(&time_travel_timer_event);
435
436 if (time_travel_timer_event.fn == time_travel_periodic_timer)
437 time_travel_add_event(&time_travel_timer_event,
438 time_travel_time +
439 time_travel_timer_interval);
440 }
441
time_travel_set_interval(unsigned long long interval)442 static void time_travel_set_interval(unsigned long long interval)
443 {
444 time_travel_timer_interval = interval;
445 }
446
time_travel_connect_external(const char * socket)447 static int time_travel_connect_external(const char *socket)
448 {
449 const char *sep;
450 unsigned long long id = (unsigned long long)-1;
451 int rc;
452
453 if ((sep = strchr(socket, ':'))) {
454 char buf[25] = {};
455 if (sep - socket > sizeof(buf) - 1)
456 goto invalid_number;
457
458 memcpy(buf, socket, sep - socket);
459 if (kstrtoull(buf, 0, &id)) {
460 invalid_number:
461 panic("time-travel: invalid external ID in string '%s'\n",
462 socket);
463 return -EINVAL;
464 }
465
466 socket = sep + 1;
467 }
468
469 rc = os_connect_socket(socket);
470 if (rc < 0) {
471 panic("time-travel: failed to connect to external socket %s\n",
472 socket);
473 return rc;
474 }
475
476 time_travel_ext_fd = rc;
477
478 time_travel_ext_req(UM_TIMETRAVEL_START, id);
479
480 return 1;
481 }
482 #else /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
483 #define time_travel_start_set 0
484 #define time_travel_start 0
485 #define time_travel_time 0
486
time_travel_update_time(unsigned long long ns,bool retearly)487 static inline void time_travel_update_time(unsigned long long ns, bool retearly)
488 {
489 }
490
time_travel_handle_real_alarm(void)491 static inline void time_travel_handle_real_alarm(void)
492 {
493 }
494
time_travel_set_interval(unsigned long long interval)495 static void time_travel_set_interval(unsigned long long interval)
496 {
497 }
498
499 /* fail link if this actually gets used */
500 extern u64 time_travel_ext_req(u32 op, u64 time);
501
502 /* these are empty macros so the struct/fn need not exist */
503 #define time_travel_add_event(e, time) do { } while (0)
504 #define time_travel_del_event(e) do { } while (0)
505 #endif
506
timer_handler(int sig,struct siginfo * unused_si,struct uml_pt_regs * regs)507 void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
508 {
509 unsigned long flags;
510
511 /*
512 * In basic time-travel mode we still get real interrupts
513 * (signals) but since we don't read time from the OS, we
514 * must update the simulated time here to the expiry when
515 * we get a signal.
516 * This is not the case in inf-cpu mode, since there we
517 * never get any real signals from the OS.
518 */
519 if (time_travel_mode == TT_MODE_BASIC)
520 time_travel_handle_real_alarm();
521
522 local_irq_save(flags);
523 do_IRQ(TIMER_IRQ, regs);
524 local_irq_restore(flags);
525 }
526
itimer_shutdown(struct clock_event_device * evt)527 static int itimer_shutdown(struct clock_event_device *evt)
528 {
529 if (time_travel_mode != TT_MODE_OFF)
530 time_travel_del_event(&time_travel_timer_event);
531
532 if (time_travel_mode != TT_MODE_INFCPU &&
533 time_travel_mode != TT_MODE_EXTERNAL)
534 os_timer_disable();
535
536 return 0;
537 }
538
itimer_set_periodic(struct clock_event_device * evt)539 static int itimer_set_periodic(struct clock_event_device *evt)
540 {
541 unsigned long long interval = NSEC_PER_SEC / HZ;
542
543 if (time_travel_mode != TT_MODE_OFF) {
544 time_travel_del_event(&time_travel_timer_event);
545 time_travel_set_event_fn(&time_travel_timer_event,
546 time_travel_periodic_timer);
547 time_travel_set_interval(interval);
548 time_travel_add_event(&time_travel_timer_event,
549 time_travel_time + interval);
550 }
551
552 if (time_travel_mode != TT_MODE_INFCPU &&
553 time_travel_mode != TT_MODE_EXTERNAL)
554 os_timer_set_interval(interval);
555
556 return 0;
557 }
558
itimer_next_event(unsigned long delta,struct clock_event_device * evt)559 static int itimer_next_event(unsigned long delta,
560 struct clock_event_device *evt)
561 {
562 delta += 1;
563
564 if (time_travel_mode != TT_MODE_OFF) {
565 time_travel_del_event(&time_travel_timer_event);
566 time_travel_set_event_fn(&time_travel_timer_event,
567 time_travel_oneshot_timer);
568 time_travel_add_event(&time_travel_timer_event,
569 time_travel_time + delta);
570 }
571
572 if (time_travel_mode != TT_MODE_INFCPU &&
573 time_travel_mode != TT_MODE_EXTERNAL)
574 return os_timer_one_shot(delta);
575
576 return 0;
577 }
578
itimer_one_shot(struct clock_event_device * evt)579 static int itimer_one_shot(struct clock_event_device *evt)
580 {
581 return itimer_next_event(0, evt);
582 }
583
584 static struct clock_event_device timer_clockevent = {
585 .name = "posix-timer",
586 .rating = 250,
587 .cpumask = cpu_possible_mask,
588 .features = CLOCK_EVT_FEAT_PERIODIC |
589 CLOCK_EVT_FEAT_ONESHOT,
590 .set_state_shutdown = itimer_shutdown,
591 .set_state_periodic = itimer_set_periodic,
592 .set_state_oneshot = itimer_one_shot,
593 .set_next_event = itimer_next_event,
594 .shift = 0,
595 .max_delta_ns = 0xffffffff,
596 .max_delta_ticks = 0xffffffff,
597 .min_delta_ns = TIMER_MIN_DELTA,
598 .min_delta_ticks = TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM
599 .irq = 0,
600 .mult = 1,
601 };
602
um_timer(int irq,void * dev)603 static irqreturn_t um_timer(int irq, void *dev)
604 {
605 if (get_current()->mm != NULL)
606 {
607 /* userspace - relay signal, results in correct userspace timers */
608 os_alarm_process(get_current()->mm->context.id.u.pid);
609 }
610
611 (*timer_clockevent.event_handler)(&timer_clockevent);
612
613 return IRQ_HANDLED;
614 }
615
timer_read(struct clocksource * cs)616 static u64 timer_read(struct clocksource *cs)
617 {
618 if (time_travel_mode != TT_MODE_OFF) {
619 /*
620 * We make reading the timer cost a bit so that we don't get
621 * stuck in loops that expect time to move more than the
622 * exact requested sleep amount, e.g. python's socket server,
623 * see https://bugs.python.org/issue37026.
624 *
625 * However, don't do that when we're in interrupt or such as
626 * then we might recurse into our own processing, and get to
627 * even more waiting, and that's not good - it messes up the
628 * "what do I do next" and onstack event we use to know when
629 * to return from time_travel_update_time().
630 */
631 if (!irqs_disabled() && !in_interrupt() && !in_softirq())
632 time_travel_update_time(time_travel_time +
633 TIMER_MULTIPLIER,
634 false);
635 return time_travel_time / TIMER_MULTIPLIER;
636 }
637
638 return os_nsecs() / TIMER_MULTIPLIER;
639 }
640
641 static struct clocksource timer_clocksource = {
642 .name = "timer",
643 .rating = 300,
644 .read = timer_read,
645 .mask = CLOCKSOURCE_MASK(64),
646 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
647 };
648
um_timer_setup(void)649 static void __init um_timer_setup(void)
650 {
651 int err;
652
653 err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
654 if (err != 0)
655 printk(KERN_ERR "register_timer : request_irq failed - "
656 "errno = %d\n", -err);
657
658 err = os_timer_create();
659 if (err != 0) {
660 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
661 return;
662 }
663
664 err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
665 if (err) {
666 printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
667 return;
668 }
669 clockevents_register_device(&timer_clockevent);
670 }
671
read_persistent_clock64(struct timespec64 * ts)672 void read_persistent_clock64(struct timespec64 *ts)
673 {
674 long long nsecs;
675
676 if (time_travel_start_set)
677 nsecs = time_travel_start + time_travel_time;
678 else if (time_travel_mode == TT_MODE_EXTERNAL)
679 nsecs = time_travel_ext_req(UM_TIMETRAVEL_GET_TOD, -1);
680 else
681 nsecs = os_persistent_clock_emulation();
682
683 set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
684 nsecs % NSEC_PER_SEC);
685 }
686
time_init(void)687 void __init time_init(void)
688 {
689 timer_set_signal_handler();
690 late_time_init = um_timer_setup;
691 }
692
693 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
calibrate_delay_is_known(void)694 unsigned long calibrate_delay_is_known(void)
695 {
696 if (time_travel_mode == TT_MODE_INFCPU ||
697 time_travel_mode == TT_MODE_EXTERNAL)
698 return 1;
699 return 0;
700 }
701
setup_time_travel(char * str)702 int setup_time_travel(char *str)
703 {
704 if (strcmp(str, "=inf-cpu") == 0) {
705 time_travel_mode = TT_MODE_INFCPU;
706 timer_clockevent.name = "time-travel-timer-infcpu";
707 timer_clocksource.name = "time-travel-clock";
708 return 1;
709 }
710
711 if (strncmp(str, "=ext:", 5) == 0) {
712 time_travel_mode = TT_MODE_EXTERNAL;
713 timer_clockevent.name = "time-travel-timer-external";
714 timer_clocksource.name = "time-travel-clock-external";
715 return time_travel_connect_external(str + 5);
716 }
717
718 if (!*str) {
719 time_travel_mode = TT_MODE_BASIC;
720 timer_clockevent.name = "time-travel-timer";
721 timer_clocksource.name = "time-travel-clock";
722 return 1;
723 }
724
725 return -EINVAL;
726 }
727
728 __setup("time-travel", setup_time_travel);
729 __uml_help(setup_time_travel,
730 "time-travel\n"
731 "This option just enables basic time travel mode, in which the clock/timers\n"
732 "inside the UML instance skip forward when there's nothing to do, rather than\n"
733 "waiting for real time to elapse. However, instance CPU speed is limited by\n"
734 "the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
735 "clock (but quicker when there's nothing to do).\n"
736 "\n"
737 "time-travel=inf-cpu\n"
738 "This enables time travel mode with infinite processing power, in which there\n"
739 "are no wall clock timers, and any CPU processing happens - as seen from the\n"
740 "guest - instantly. This can be useful for accurate simulation regardless of\n"
741 "debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
742 "easily lead to getting stuck (e.g. if anything in the system busy loops).\n"
743 "\n"
744 "time-travel=ext:[ID:]/path/to/socket\n"
745 "This enables time travel mode similar to =inf-cpu, except the system will\n"
746 "use the given socket to coordinate with a central scheduler, in order to\n"
747 "have more than one system simultaneously be on simulated time. The virtio\n"
748 "driver code in UML knows about this so you can also simulate networks and\n"
749 "devices using it, assuming the device has the right capabilities.\n"
750 "The optional ID is a 64-bit integer that's sent to the central scheduler.\n");
751
setup_time_travel_start(char * str)752 int setup_time_travel_start(char *str)
753 {
754 int err;
755
756 err = kstrtoull(str, 0, &time_travel_start);
757 if (err)
758 return err;
759
760 time_travel_start_set = 1;
761 return 1;
762 }
763
764 __setup("time-travel-start", setup_time_travel_start);
765 __uml_help(setup_time_travel_start,
766 "time-travel-start=<seconds>\n"
767 "Configure the UML instance's wall clock to start at this value rather than\n"
768 "the host's wall clock at the time of UML boot.\n");
769 #endif
770