~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/um/kernel/time.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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/delay.h>
 23 #include <linux/time-internal.h>
 24 #include <linux/um_timetravel.h>
 25 #include <shared/init.h>
 26 
 27 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
 28 enum time_travel_mode time_travel_mode;
 29 EXPORT_SYMBOL_GPL(time_travel_mode);
 30 
 31 static bool time_travel_start_set;
 32 static unsigned long long time_travel_start;
 33 static unsigned long long time_travel_time;
 34 static unsigned long long time_travel_shm_offset;
 35 static LIST_HEAD(time_travel_events);
 36 static LIST_HEAD(time_travel_irqs);
 37 static unsigned long long time_travel_timer_interval;
 38 static unsigned long long time_travel_next_event;
 39 static struct time_travel_event time_travel_timer_event;
 40 static int time_travel_ext_fd = -1;
 41 static unsigned int time_travel_ext_waiting;
 42 static bool time_travel_ext_prev_request_valid;
 43 static unsigned long long time_travel_ext_prev_request;
 44 static unsigned long long *time_travel_ext_free_until;
 45 static unsigned long long _time_travel_ext_free_until;
 46 static u16 time_travel_shm_id;
 47 static struct um_timetravel_schedshm *time_travel_shm;
 48 static union um_timetravel_schedshm_client *time_travel_shm_client;
 49 
 50 static void time_travel_set_time(unsigned long long ns)
 51 {
 52         if (unlikely(ns < time_travel_time))
 53                 panic("time-travel: time goes backwards %lld -> %lld\n",
 54                       time_travel_time, ns);
 55         else if (unlikely(ns >= S64_MAX))
 56                 panic("The system was going to sleep forever, aborting");
 57 
 58         time_travel_time = ns;
 59 }
 60 
 61 enum time_travel_message_handling {
 62         TTMH_IDLE,
 63         TTMH_POLL,
 64         TTMH_READ,
 65         TTMH_READ_START_ACK,
 66 };
 67 
 68 static u64 bc_message;
 69 int time_travel_should_print_bc_msg;
 70 
 71 void _time_travel_print_bc_msg(void)
 72 {
 73         time_travel_should_print_bc_msg = 0;
 74         printk(KERN_INFO "time-travel: received broadcast 0x%llx\n", bc_message);
 75 }
 76 
 77 static void time_travel_setup_shm(int fd, u16 id)
 78 {
 79         u32 len;
 80 
 81         time_travel_shm = os_mmap_rw_shared(fd, sizeof(*time_travel_shm));
 82 
 83         if (!time_travel_shm)
 84                 goto out;
 85 
 86         len = time_travel_shm->len;
 87 
 88         if (time_travel_shm->version != UM_TIMETRAVEL_SCHEDSHM_VERSION ||
 89             len < struct_size(time_travel_shm, clients, id + 1)) {
 90                 os_unmap_memory(time_travel_shm, sizeof(*time_travel_shm));
 91                 time_travel_shm = NULL;
 92                 goto out;
 93         }
 94 
 95         time_travel_shm = os_mremap_rw_shared(time_travel_shm,
 96                                               sizeof(*time_travel_shm),
 97                                               len);
 98         if (!time_travel_shm)
 99                 goto out;
100 
101         time_travel_shm_offset = time_travel_shm->current_time;
102         time_travel_shm_client = &time_travel_shm->clients[id];
103         time_travel_shm_client->capa |= UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE;
104         time_travel_shm_id = id;
105         /* always look at that free_until from now on */
106         time_travel_ext_free_until = &time_travel_shm->free_until;
107 out:
108         os_close_file(fd);
109 }
110 
111 static void time_travel_handle_message(struct um_timetravel_msg *msg,
112                                        enum time_travel_message_handling mode)
113 {
114         struct um_timetravel_msg resp = {
115                 .op = UM_TIMETRAVEL_ACK,
116         };
117         int ret;
118 
119         /*
120          * We can't unlock here, but interrupt signals with a timetravel_handler
121          * (see um_request_irq_tt) get to the timetravel_handler anyway.
122          */
123         if (mode != TTMH_READ) {
124                 BUG_ON(mode == TTMH_IDLE && !irqs_disabled());
125 
126                 while (os_poll(1, &time_travel_ext_fd) != 0) {
127                         /* nothing */
128                 }
129         }
130 
131         if (unlikely(mode == TTMH_READ_START_ACK)) {
132                 int fd[UM_TIMETRAVEL_SHARED_MAX_FDS];
133 
134                 ret = os_rcv_fd_msg(time_travel_ext_fd, fd,
135                                     ARRAY_SIZE(fd), msg, sizeof(*msg));
136                 if (ret == sizeof(*msg)) {
137                         time_travel_setup_shm(fd[UM_TIMETRAVEL_SHARED_MEMFD],
138                                               msg->time & UM_TIMETRAVEL_START_ACK_ID);
139                         /* we don't use the logging for now */
140                         os_close_file(fd[UM_TIMETRAVEL_SHARED_LOGFD]);
141                 }
142         } else {
143                 ret = os_read_file(time_travel_ext_fd, msg, sizeof(*msg));
144         }
145 
146         if (ret == 0)
147                 panic("time-travel external link is broken\n");
148         if (ret != sizeof(*msg))
149                 panic("invalid time-travel message - %d bytes\n", ret);
150 
151         switch (msg->op) {
152         default:
153                 WARN_ONCE(1, "time-travel: unexpected message %lld\n",
154                           (unsigned long long)msg->op);
155                 break;
156         case UM_TIMETRAVEL_ACK:
157                 return;
158         case UM_TIMETRAVEL_RUN:
159                 time_travel_set_time(msg->time);
160                 if (time_travel_shm) {
161                         /* no request right now since we're running */
162                         time_travel_shm_client->flags &=
163                                 ~UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN;
164                         /* no ack for shared memory RUN */
165                         return;
166                 }
167                 break;
168         case UM_TIMETRAVEL_FREE_UNTIL:
169                 /* not supposed to get this with shm, but ignore it */
170                 if (time_travel_shm)
171                         break;
172                 time_travel_ext_free_until = &_time_travel_ext_free_until;
173                 _time_travel_ext_free_until = msg->time;
174                 break;
175         case UM_TIMETRAVEL_BROADCAST:
176                 bc_message = msg->time;
177                 time_travel_should_print_bc_msg = 1;
178                 break;
179         }
180 
181         resp.seq = msg->seq;
182         os_write_file(time_travel_ext_fd, &resp, sizeof(resp));
183 }
184 
185 static u64 time_travel_ext_req(u32 op, u64 time)
186 {
187         static int seq;
188         int mseq = ++seq;
189         struct um_timetravel_msg msg = {
190                 .op = op,
191                 .time = time,
192                 .seq = mseq,
193         };
194 
195         /*
196          * We need to block even the timetravel handlers of SIGIO here and
197          * only restore their use when we got the ACK - otherwise we may
198          * (will) get interrupted by that, try to queue the IRQ for future
199          * processing and thus send another request while we're still waiting
200          * for an ACK, but the peer doesn't know we got interrupted and will
201          * send the ACKs in the same order as the message, but we'd need to
202          * see them in the opposite order ...
203          *
204          * This wouldn't matter *too* much, but some ACKs carry the
205          * current time (for UM_TIMETRAVEL_GET) and getting another
206          * ACK without a time would confuse us a lot!
207          *
208          * The sequence number assignment that happens here lets us
209          * debug such message handling issues more easily.
210          */
211         block_signals_hard();
212         os_write_file(time_travel_ext_fd, &msg, sizeof(msg));
213 
214         /* no ACK expected for WAIT in shared memory mode */
215         if (msg.op == UM_TIMETRAVEL_WAIT && time_travel_shm)
216                 goto done;
217 
218         while (msg.op != UM_TIMETRAVEL_ACK)
219                 time_travel_handle_message(&msg,
220                                            op == UM_TIMETRAVEL_START ?
221                                                 TTMH_READ_START_ACK :
222                                                 TTMH_READ);
223 
224         if (msg.seq != mseq)
225                 panic("time-travel: ACK message has different seqno! op=%d, seq=%d != %d time=%lld\n",
226                       msg.op, msg.seq, mseq, msg.time);
227 
228         if (op == UM_TIMETRAVEL_GET)
229                 time_travel_set_time(msg.time);
230 done:
231         unblock_signals_hard();
232 
233         return msg.time;
234 }
235 
236 void __time_travel_wait_readable(int fd)
237 {
238         int fds[2] = { fd, time_travel_ext_fd };
239         int ret;
240 
241         if (time_travel_mode != TT_MODE_EXTERNAL)
242                 return;
243 
244         while ((ret = os_poll(2, fds))) {
245                 struct um_timetravel_msg msg;
246 
247                 if (ret == 1)
248                         time_travel_handle_message(&msg, TTMH_READ);
249         }
250 }
251 EXPORT_SYMBOL_GPL(__time_travel_wait_readable);
252 
253 static void time_travel_ext_update_request(unsigned long long time)
254 {
255         if (time_travel_mode != TT_MODE_EXTERNAL)
256                 return;
257 
258         /* asked for exactly this time previously */
259         if (time_travel_ext_prev_request_valid &&
260             time == time_travel_ext_prev_request)
261                 return;
262 
263         /*
264          * if we're running and are allowed to run past the request
265          * then we don't need to update it either
266          *
267          * Note for shm we ignore FREE_UNTIL messages and leave the pointer
268          * to shared memory, and for non-shm the offset is 0.
269          */
270         if (!time_travel_ext_waiting && time_travel_ext_free_until &&
271             time < (*time_travel_ext_free_until - time_travel_shm_offset))
272                 return;
273 
274         time_travel_ext_prev_request = time;
275         time_travel_ext_prev_request_valid = true;
276 
277         if (time_travel_shm) {
278                 union um_timetravel_schedshm_client *running;
279 
280                 running = &time_travel_shm->clients[time_travel_shm->running_id];
281 
282                 if (running->capa & UM_TIMETRAVEL_SCHEDSHM_CAP_TIME_SHARE) {
283                         time_travel_shm_client->flags |=
284                                 UM_TIMETRAVEL_SCHEDSHM_FLAGS_REQ_RUN;
285                         time += time_travel_shm_offset;
286                         time_travel_shm_client->req_time = time;
287                         if (time < time_travel_shm->free_until)
288                                 time_travel_shm->free_until = time;
289                         return;
290                 }
291         }
292 
293         time_travel_ext_req(UM_TIMETRAVEL_REQUEST, time);
294 }
295 
296 void __time_travel_propagate_time(void)
297 {
298         static unsigned long long last_propagated;
299 
300         if (time_travel_shm) {
301                 if (time_travel_shm->running_id != time_travel_shm_id)
302                         panic("time-travel: setting time while not running\n");
303                 time_travel_shm->current_time = time_travel_time +
304                                                 time_travel_shm_offset;
305                 return;
306         }
307 
308         if (last_propagated == time_travel_time)
309                 return;
310 
311         time_travel_ext_req(UM_TIMETRAVEL_UPDATE, time_travel_time);
312         last_propagated = time_travel_time;
313 }
314 EXPORT_SYMBOL_GPL(__time_travel_propagate_time);
315 
316 /* returns true if we must do a wait to the simtime device */
317 static bool time_travel_ext_request(unsigned long long time)
318 {
319         /*
320          * If we received an external sync point ("free until") then we
321          * don't have to request/wait for anything until then, unless
322          * we're already waiting.
323          *
324          * Note for shm we ignore FREE_UNTIL messages and leave the pointer
325          * to shared memory, and for non-shm the offset is 0.
326          */
327         if (!time_travel_ext_waiting && time_travel_ext_free_until &&
328             time < (*time_travel_ext_free_until - time_travel_shm_offset))
329                 return false;
330 
331         time_travel_ext_update_request(time);
332         return true;
333 }
334 
335 static void time_travel_ext_wait(bool idle)
336 {
337         struct um_timetravel_msg msg = {
338                 .op = UM_TIMETRAVEL_ACK,
339         };
340 
341         time_travel_ext_prev_request_valid = false;
342         if (!time_travel_shm)
343                 time_travel_ext_free_until = NULL;
344         time_travel_ext_waiting++;
345 
346         time_travel_ext_req(UM_TIMETRAVEL_WAIT, -1);
347 
348         /*
349          * Here we are deep in the idle loop, so we have to break out of the
350          * kernel abstraction in a sense and implement this in terms of the
351          * UML system waiting on the VQ interrupt while sleeping, when we get
352          * the signal it'll call time_travel_ext_vq_notify_done() completing the
353          * call.
354          */
355         while (msg.op != UM_TIMETRAVEL_RUN)
356                 time_travel_handle_message(&msg, idle ? TTMH_IDLE : TTMH_POLL);
357 
358         time_travel_ext_waiting--;
359 
360         /* we might request more stuff while polling - reset when we run */
361         time_travel_ext_prev_request_valid = false;
362 }
363 
364 static void time_travel_ext_get_time(void)
365 {
366         if (time_travel_shm)
367                 time_travel_set_time(time_travel_shm->current_time -
368                                      time_travel_shm_offset);
369         else
370                 time_travel_ext_req(UM_TIMETRAVEL_GET, -1);
371 }
372 
373 static void __time_travel_update_time(unsigned long long ns, bool idle)
374 {
375         if (time_travel_mode == TT_MODE_EXTERNAL && time_travel_ext_request(ns))
376                 time_travel_ext_wait(idle);
377         else
378                 time_travel_set_time(ns);
379 }
380 
381 static struct time_travel_event *time_travel_first_event(void)
382 {
383         return list_first_entry_or_null(&time_travel_events,
384                                         struct time_travel_event,
385                                         list);
386 }
387 
388 static void __time_travel_add_event(struct time_travel_event *e,
389                                     unsigned long long time)
390 {
391         struct time_travel_event *tmp;
392         bool inserted = false;
393         unsigned long flags;
394 
395         if (e->pending)
396                 return;
397 
398         e->pending = true;
399         e->time = time;
400 
401         local_irq_save(flags);
402         list_for_each_entry(tmp, &time_travel_events, list) {
403                 /*
404                  * Add the new entry before one with higher time,
405                  * or if they're equal and both on stack, because
406                  * in that case we need to unwind the stack in the
407                  * right order, and the later event (timer sleep
408                  * or such) must be dequeued first.
409                  */
410                 if ((tmp->time > e->time) ||
411                     (tmp->time == e->time && tmp->onstack && e->onstack)) {
412                         list_add_tail(&e->list, &tmp->list);
413                         inserted = true;
414                         break;
415                 }
416         }
417 
418         if (!inserted)
419                 list_add_tail(&e->list, &time_travel_events);
420 
421         tmp = time_travel_first_event();
422         time_travel_ext_update_request(tmp->time);
423         time_travel_next_event = tmp->time;
424         local_irq_restore(flags);
425 }
426 
427 static void time_travel_add_event(struct time_travel_event *e,
428                                   unsigned long long time)
429 {
430         if (WARN_ON(!e->fn))
431                 return;
432 
433         __time_travel_add_event(e, time);
434 }
435 
436 void time_travel_add_event_rel(struct time_travel_event *e,
437                                unsigned long long delay_ns)
438 {
439         time_travel_add_event(e, time_travel_time + delay_ns);
440 }
441 
442 static void time_travel_periodic_timer(struct time_travel_event *e)
443 {
444         time_travel_add_event(&time_travel_timer_event,
445                               time_travel_time + time_travel_timer_interval);
446         deliver_alarm();
447 }
448 
449 void deliver_time_travel_irqs(void)
450 {
451         struct time_travel_event *e;
452         unsigned long flags;
453 
454         /*
455          * Don't do anything for most cases. Note that because here we have
456          * to disable IRQs (and re-enable later) we'll actually recurse at
457          * the end of the function, so this is strictly necessary.
458          */
459         if (likely(list_empty(&time_travel_irqs)))
460                 return;
461 
462         local_irq_save(flags);
463         irq_enter();
464         while ((e = list_first_entry_or_null(&time_travel_irqs,
465                                              struct time_travel_event,
466                                              list))) {
467                 list_del(&e->list);
468                 e->pending = false;
469                 e->fn(e);
470         }
471         irq_exit();
472         local_irq_restore(flags);
473 }
474 
475 static void time_travel_deliver_event(struct time_travel_event *e)
476 {
477         if (e == &time_travel_timer_event) {
478                 /*
479                  * deliver_alarm() does the irq_enter/irq_exit
480                  * by itself, so must handle it specially here
481                  */
482                 e->fn(e);
483         } else if (irqs_disabled()) {
484                 list_add_tail(&e->list, &time_travel_irqs);
485                 /*
486                  * set pending again, it was set to false when the
487                  * event was deleted from the original list, but
488                  * now it's still pending until we deliver the IRQ.
489                  */
490                 e->pending = true;
491         } else {
492                 unsigned long flags;
493 
494                 local_irq_save(flags);
495                 irq_enter();
496                 e->fn(e);
497                 irq_exit();
498                 local_irq_restore(flags);
499         }
500 }
501 
502 bool time_travel_del_event(struct time_travel_event *e)
503 {
504         unsigned long flags;
505 
506         if (!e->pending)
507                 return false;
508         local_irq_save(flags);
509         list_del(&e->list);
510         e->pending = false;
511         local_irq_restore(flags);
512         return true;
513 }
514 
515 static void time_travel_update_time(unsigned long long next, bool idle)
516 {
517         struct time_travel_event ne = {
518                 .onstack = true,
519         };
520         struct time_travel_event *e;
521         bool finished = idle;
522 
523         /* add it without a handler - we deal with that specifically below */
524         __time_travel_add_event(&ne, next);
525 
526         do {
527                 e = time_travel_first_event();
528 
529                 BUG_ON(!e);
530                 __time_travel_update_time(e->time, idle);
531 
532                 /* new events may have been inserted while we were waiting */
533                 if (e == time_travel_first_event()) {
534                         BUG_ON(!time_travel_del_event(e));
535                         BUG_ON(time_travel_time != e->time);
536 
537                         if (e == &ne) {
538                                 finished = true;
539                         } else {
540                                 if (e->onstack)
541                                         panic("On-stack event dequeued outside of the stack! time=%lld, event time=%lld, event=%pS\n",
542                                               time_travel_time, e->time, e);
543                                 time_travel_deliver_event(e);
544                         }
545                 }
546 
547                 e = time_travel_first_event();
548                 if (e)
549                         time_travel_ext_update_request(e->time);
550         } while (ne.pending && !finished);
551 
552         time_travel_del_event(&ne);
553 }
554 
555 static void time_travel_update_time_rel(unsigned long long offs)
556 {
557         unsigned long flags;
558 
559         /*
560          * Disable interrupts before calculating the new time so
561          * that a real timer interrupt (signal) can't happen at
562          * a bad time e.g. after we read time_travel_time but
563          * before we've completed updating the time.
564          */
565         local_irq_save(flags);
566         time_travel_update_time(time_travel_time + offs, false);
567         local_irq_restore(flags);
568 }
569 
570 void time_travel_ndelay(unsigned long nsec)
571 {
572         /*
573          * Not strictly needed to use _rel() version since this is
574          * only used in INFCPU/EXT modes, but it doesn't hurt and
575          * is more readable too.
576          */
577         time_travel_update_time_rel(nsec);
578 }
579 EXPORT_SYMBOL(time_travel_ndelay);
580 
581 void time_travel_add_irq_event(struct time_travel_event *e)
582 {
583         BUG_ON(time_travel_mode != TT_MODE_EXTERNAL);
584 
585         time_travel_ext_get_time();
586         /*
587          * We could model interrupt latency here, for now just
588          * don't have any latency at all and request the exact
589          * same time (again) to run the interrupt...
590          */
591         time_travel_add_event(e, time_travel_time);
592 }
593 EXPORT_SYMBOL_GPL(time_travel_add_irq_event);
594 
595 static void time_travel_oneshot_timer(struct time_travel_event *e)
596 {
597         deliver_alarm();
598 }
599 
600 void time_travel_sleep(void)
601 {
602         /*
603          * Wait "forever" (using S64_MAX because there are some potential
604          * wrapping issues, especially with the current TT_MODE_EXTERNAL
605          * controller application.
606          */
607         unsigned long long next = S64_MAX;
608 
609         if (time_travel_mode == TT_MODE_BASIC)
610                 os_timer_disable();
611 
612         time_travel_update_time(next, true);
613 
614         if (time_travel_mode == TT_MODE_BASIC &&
615             time_travel_timer_event.pending) {
616                 if (time_travel_timer_event.fn == time_travel_periodic_timer) {
617                         /*
618                          * This is somewhat wrong - we should get the first
619                          * one sooner like the os_timer_one_shot() below...
620                          */
621                         os_timer_set_interval(time_travel_timer_interval);
622                 } else {
623                         os_timer_one_shot(time_travel_timer_event.time - next);
624                 }
625         }
626 }
627 
628 static void time_travel_handle_real_alarm(void)
629 {
630         time_travel_set_time(time_travel_next_event);
631 
632         time_travel_del_event(&time_travel_timer_event);
633 
634         if (time_travel_timer_event.fn == time_travel_periodic_timer)
635                 time_travel_add_event(&time_travel_timer_event,
636                                       time_travel_time +
637                                       time_travel_timer_interval);
638 }
639 
640 static void time_travel_set_interval(unsigned long long interval)
641 {
642         time_travel_timer_interval = interval;
643 }
644 
645 static int time_travel_connect_external(const char *socket)
646 {
647         const char *sep;
648         unsigned long long id = (unsigned long long)-1;
649         int rc;
650 
651         if ((sep = strchr(socket, ':'))) {
652                 char buf[25] = {};
653                 if (sep - socket > sizeof(buf) - 1)
654                         goto invalid_number;
655 
656                 memcpy(buf, socket, sep - socket);
657                 if (kstrtoull(buf, 0, &id)) {
658 invalid_number:
659                         panic("time-travel: invalid external ID in string '%s'\n",
660                               socket);
661                         return -EINVAL;
662                 }
663 
664                 socket = sep + 1;
665         }
666 
667         rc = os_connect_socket(socket);
668         if (rc < 0) {
669                 panic("time-travel: failed to connect to external socket %s\n",
670                       socket);
671                 return rc;
672         }
673 
674         time_travel_ext_fd = rc;
675 
676         time_travel_ext_req(UM_TIMETRAVEL_START, id);
677 
678         return 1;
679 }
680 
681 static void time_travel_set_start(void)
682 {
683         if (time_travel_start_set)
684                 return;
685 
686         switch (time_travel_mode) {
687         case TT_MODE_EXTERNAL:
688                 time_travel_start = time_travel_ext_req(UM_TIMETRAVEL_GET_TOD, -1);
689                 /* controller gave us the *current* time, so adjust by that */
690                 time_travel_ext_get_time();
691                 time_travel_start -= time_travel_time;
692                 break;
693         case TT_MODE_INFCPU:
694         case TT_MODE_BASIC:
695                 if (!time_travel_start_set)
696                         time_travel_start = os_persistent_clock_emulation();
697                 break;
698         case TT_MODE_OFF:
699                 /* we just read the host clock with os_persistent_clock_emulation() */
700                 break;
701         }
702 
703         time_travel_start_set = true;
704 }
705 #else /* CONFIG_UML_TIME_TRAVEL_SUPPORT */
706 #define time_travel_start_set 0
707 #define time_travel_start 0
708 #define time_travel_time 0
709 #define time_travel_ext_waiting 0
710 
711 static inline void time_travel_update_time(unsigned long long ns, bool idle)
712 {
713 }
714 
715 static inline void time_travel_update_time_rel(unsigned long long offs)
716 {
717 }
718 
719 static inline void time_travel_handle_real_alarm(void)
720 {
721 }
722 
723 static void time_travel_set_interval(unsigned long long interval)
724 {
725 }
726 
727 static inline void time_travel_set_start(void)
728 {
729 }
730 
731 /* fail link if this actually gets used */
732 extern u64 time_travel_ext_req(u32 op, u64 time);
733 
734 /* these are empty macros so the struct/fn need not exist */
735 #define time_travel_add_event(e, time) do { } while (0)
736 /* externally not usable - redefine here so we can */
737 #undef time_travel_del_event
738 #define time_travel_del_event(e) do { } while (0)
739 #endif
740 
741 void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
742 {
743         unsigned long flags;
744 
745         /*
746          * In basic time-travel mode we still get real interrupts
747          * (signals) but since we don't read time from the OS, we
748          * must update the simulated time here to the expiry when
749          * we get a signal.
750          * This is not the case in inf-cpu mode, since there we
751          * never get any real signals from the OS.
752          */
753         if (time_travel_mode == TT_MODE_BASIC)
754                 time_travel_handle_real_alarm();
755 
756         local_irq_save(flags);
757         do_IRQ(TIMER_IRQ, regs);
758         local_irq_restore(flags);
759 }
760 
761 static int itimer_shutdown(struct clock_event_device *evt)
762 {
763         if (time_travel_mode != TT_MODE_OFF)
764                 time_travel_del_event(&time_travel_timer_event);
765 
766         if (time_travel_mode != TT_MODE_INFCPU &&
767             time_travel_mode != TT_MODE_EXTERNAL)
768                 os_timer_disable();
769 
770         return 0;
771 }
772 
773 static int itimer_set_periodic(struct clock_event_device *evt)
774 {
775         unsigned long long interval = NSEC_PER_SEC / HZ;
776 
777         if (time_travel_mode != TT_MODE_OFF) {
778                 time_travel_del_event(&time_travel_timer_event);
779                 time_travel_set_event_fn(&time_travel_timer_event,
780                                          time_travel_periodic_timer);
781                 time_travel_set_interval(interval);
782                 time_travel_add_event(&time_travel_timer_event,
783                                       time_travel_time + interval);
784         }
785 
786         if (time_travel_mode != TT_MODE_INFCPU &&
787             time_travel_mode != TT_MODE_EXTERNAL)
788                 os_timer_set_interval(interval);
789 
790         return 0;
791 }
792 
793 static int itimer_next_event(unsigned long delta,
794                              struct clock_event_device *evt)
795 {
796         delta += 1;
797 
798         if (time_travel_mode != TT_MODE_OFF) {
799                 time_travel_del_event(&time_travel_timer_event);
800                 time_travel_set_event_fn(&time_travel_timer_event,
801                                          time_travel_oneshot_timer);
802                 time_travel_add_event(&time_travel_timer_event,
803                                       time_travel_time + delta);
804         }
805 
806         if (time_travel_mode != TT_MODE_INFCPU &&
807             time_travel_mode != TT_MODE_EXTERNAL)
808                 return os_timer_one_shot(delta);
809 
810         return 0;
811 }
812 
813 static int itimer_one_shot(struct clock_event_device *evt)
814 {
815         return itimer_next_event(0, evt);
816 }
817 
818 static struct clock_event_device timer_clockevent = {
819         .name                   = "posix-timer",
820         .rating                 = 250,
821         .cpumask                = cpu_possible_mask,
822         .features               = CLOCK_EVT_FEAT_PERIODIC |
823                                   CLOCK_EVT_FEAT_ONESHOT,
824         .set_state_shutdown     = itimer_shutdown,
825         .set_state_periodic     = itimer_set_periodic,
826         .set_state_oneshot      = itimer_one_shot,
827         .set_next_event         = itimer_next_event,
828         .shift                  = 0,
829         .max_delta_ns           = 0xffffffff,
830         .max_delta_ticks        = 0xffffffff,
831         .min_delta_ns           = TIMER_MIN_DELTA,
832         .min_delta_ticks        = TIMER_MIN_DELTA, // microsecond resolution should be enough for anyone, same as 640K RAM
833         .irq                    = 0,
834         .mult                   = 1,
835 };
836 
837 static irqreturn_t um_timer(int irq, void *dev)
838 {
839         if (get_current()->mm != NULL)
840         {
841         /* userspace - relay signal, results in correct userspace timers */
842                 os_alarm_process(get_current()->mm->context.id.u.pid);
843         }
844 
845         (*timer_clockevent.event_handler)(&timer_clockevent);
846 
847         return IRQ_HANDLED;
848 }
849 
850 static u64 timer_read(struct clocksource *cs)
851 {
852         if (time_travel_mode != TT_MODE_OFF) {
853                 /*
854                  * We make reading the timer cost a bit so that we don't get
855                  * stuck in loops that expect time to move more than the
856                  * exact requested sleep amount, e.g. python's socket server,
857                  * see https://bugs.python.org/issue37026.
858                  *
859                  * However, don't do that when we're in interrupt or such as
860                  * then we might recurse into our own processing, and get to
861                  * even more waiting, and that's not good - it messes up the
862                  * "what do I do next" and onstack event we use to know when
863                  * to return from time_travel_update_time().
864                  */
865                 if (!irqs_disabled() && !in_interrupt() && !in_softirq() &&
866                     !time_travel_ext_waiting)
867                         time_travel_update_time_rel(TIMER_MULTIPLIER);
868                 return time_travel_time / TIMER_MULTIPLIER;
869         }
870 
871         return os_nsecs() / TIMER_MULTIPLIER;
872 }
873 
874 static struct clocksource timer_clocksource = {
875         .name           = "timer",
876         .rating         = 300,
877         .read           = timer_read,
878         .mask           = CLOCKSOURCE_MASK(64),
879         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
880 };
881 
882 static void __init um_timer_setup(void)
883 {
884         int err;
885 
886         err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
887         if (err != 0)
888                 printk(KERN_ERR "register_timer : request_irq failed - "
889                        "errno = %d\n", -err);
890 
891         err = os_timer_create();
892         if (err != 0) {
893                 printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
894                 return;
895         }
896 
897         err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
898         if (err) {
899                 printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
900                 return;
901         }
902         clockevents_register_device(&timer_clockevent);
903 }
904 
905 void read_persistent_clock64(struct timespec64 *ts)
906 {
907         long long nsecs;
908 
909         time_travel_set_start();
910 
911         if (time_travel_mode != TT_MODE_OFF)
912                 nsecs = time_travel_start + time_travel_time;
913         else
914                 nsecs = os_persistent_clock_emulation();
915 
916         set_normalized_timespec64(ts, nsecs / NSEC_PER_SEC,
917                                   nsecs % NSEC_PER_SEC);
918 }
919 
920 void __init time_init(void)
921 {
922         timer_set_signal_handler();
923         late_time_init = um_timer_setup;
924 }
925 
926 #ifdef CONFIG_UML_TIME_TRAVEL_SUPPORT
927 unsigned long calibrate_delay_is_known(void)
928 {
929         if (time_travel_mode == TT_MODE_INFCPU ||
930             time_travel_mode == TT_MODE_EXTERNAL)
931                 return 1;
932         return 0;
933 }
934 
935 static int setup_time_travel(char *str)
936 {
937         if (strcmp(str, "=inf-cpu") == 0) {
938                 time_travel_mode = TT_MODE_INFCPU;
939                 timer_clockevent.name = "time-travel-timer-infcpu";
940                 timer_clocksource.name = "time-travel-clock";
941                 return 1;
942         }
943 
944         if (strncmp(str, "=ext:", 5) == 0) {
945                 time_travel_mode = TT_MODE_EXTERNAL;
946                 timer_clockevent.name = "time-travel-timer-external";
947                 timer_clocksource.name = "time-travel-clock-external";
948                 return time_travel_connect_external(str + 5);
949         }
950 
951         if (!*str) {
952                 time_travel_mode = TT_MODE_BASIC;
953                 timer_clockevent.name = "time-travel-timer";
954                 timer_clocksource.name = "time-travel-clock";
955                 return 1;
956         }
957 
958         return -EINVAL;
959 }
960 
961 __setup("time-travel", setup_time_travel);
962 __uml_help(setup_time_travel,
963 "time-travel\n"
964 "This option just enables basic time travel mode, in which the clock/timers\n"
965 "inside the UML instance skip forward when there's nothing to do, rather than\n"
966 "waiting for real time to elapse. However, instance CPU speed is limited by\n"
967 "the real CPU speed, so e.g. a 10ms timer will always fire after ~10ms wall\n"
968 "clock (but quicker when there's nothing to do).\n"
969 "\n"
970 "time-travel=inf-cpu\n"
971 "This enables time travel mode with infinite processing power, in which there\n"
972 "are no wall clock timers, and any CPU processing happens - as seen from the\n"
973 "guest - instantly. This can be useful for accurate simulation regardless of\n"
974 "debug overhead, physical CPU speed, etc. but is somewhat dangerous as it can\n"
975 "easily lead to getting stuck (e.g. if anything in the system busy loops).\n"
976 "\n"
977 "time-travel=ext:[ID:]/path/to/socket\n"
978 "This enables time travel mode similar to =inf-cpu, except the system will\n"
979 "use the given socket to coordinate with a central scheduler, in order to\n"
980 "have more than one system simultaneously be on simulated time. The virtio\n"
981 "driver code in UML knows about this so you can also simulate networks and\n"
982 "devices using it, assuming the device has the right capabilities.\n"
983 "The optional ID is a 64-bit integer that's sent to the central scheduler.\n");
984 
985 static int setup_time_travel_start(char *str)
986 {
987         int err;
988 
989         err = kstrtoull(str, 0, &time_travel_start);
990         if (err)
991                 return err;
992 
993         time_travel_start_set = 1;
994         return 1;
995 }
996 
997 __setup("time-travel-start=", setup_time_travel_start);
998 __uml_help(setup_time_travel_start,
999 "time-travel-start=<nanoseconds>\n"
1000 "Configure the UML instance's wall clock to start at this value rather than\n"
1001 "the host's wall clock at the time of UML boot.\n");
1002 static struct kobject *bc_time_kobject;
1003 
1004 static ssize_t bc_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
1005 {
1006         return sprintf(buf, "0x%llx", bc_message);
1007 }
1008 
1009 static ssize_t bc_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
1010 {
1011         int ret;
1012         u64 user_bc_message;
1013 
1014         ret = kstrtou64(buf, 0, &user_bc_message);
1015         if (ret)
1016                 return ret;
1017 
1018         bc_message = user_bc_message;
1019 
1020         time_travel_ext_req(UM_TIMETRAVEL_BROADCAST, bc_message);
1021         pr_info("um: time: sent broadcast message: 0x%llx\n", bc_message);
1022         return count;
1023 }
1024 
1025 static struct kobj_attribute bc_attribute = __ATTR(bc-message, 0660, bc_show, bc_store);
1026 
1027 static int __init um_bc_start(void)
1028 {
1029         if (time_travel_mode != TT_MODE_EXTERNAL)
1030                 return 0;
1031 
1032         bc_time_kobject = kobject_create_and_add("um-ext-time", kernel_kobj);
1033         if (!bc_time_kobject)
1034                 return 0;
1035 
1036         if (sysfs_create_file(bc_time_kobject, &bc_attribute.attr))
1037                 pr_debug("failed to create the bc file in /sys/kernel/um_time");
1038 
1039         return 0;
1040 }
1041 late_initcall(um_bc_start);
1042 #endif
1043 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php