1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Copyright (C) 2020 Intel Corporation |
4 | * Author: Johannes Berg <johannes@sipsolutions.net> |
5 | */ |
6 | #include <stdbool.h> |
7 | #include <os.h> |
8 | #include <errno.h> |
9 | #include <sched.h> |
10 | #include <unistd.h> |
11 | #include <kern_util.h> |
12 | #include <sys/select.h> |
13 | #include <stdio.h> |
14 | #include <sys/timerfd.h> |
15 | #include "rtc.h" |
16 | |
17 | static int uml_rtc_irq_fds[2]; |
18 | |
19 | void uml_rtc_send_timetravel_alarm(void) |
20 | { |
21 | unsigned long long c = 1; |
22 | |
23 | CATCH_EINTR(write(uml_rtc_irq_fds[1], &c, sizeof(c))); |
24 | } |
25 | |
26 | int uml_rtc_start(bool timetravel) |
27 | { |
28 | int err; |
29 | |
30 | if (timetravel) { |
31 | int err = os_pipe(uml_rtc_irq_fds, 1, 1); |
32 | if (err) |
33 | goto fail; |
34 | } else { |
35 | uml_rtc_irq_fds[0] = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC); |
36 | if (uml_rtc_irq_fds[0] < 0) { |
37 | err = -errno; |
38 | goto fail; |
39 | } |
40 | |
41 | /* apparently timerfd won't send SIGIO, use workaround */ |
42 | sigio_broken(uml_rtc_irq_fds[0]); |
43 | err = add_sigio_fd(uml_rtc_irq_fds[0]); |
44 | if (err < 0) { |
45 | close(uml_rtc_irq_fds[0]); |
46 | goto fail; |
47 | } |
48 | } |
49 | |
50 | return uml_rtc_irq_fds[0]; |
51 | fail: |
52 | uml_rtc_stop(timetravel); |
53 | return err; |
54 | } |
55 | |
56 | int uml_rtc_enable_alarm(unsigned long long delta_seconds) |
57 | { |
58 | struct itimerspec it = { |
59 | .it_value = { |
60 | .tv_sec = delta_seconds, |
61 | }, |
62 | }; |
63 | |
64 | if (timerfd_settime(uml_rtc_irq_fds[0], 0, &it, NULL)) |
65 | return -errno; |
66 | return 0; |
67 | } |
68 | |
69 | void uml_rtc_disable_alarm(void) |
70 | { |
71 | uml_rtc_enable_alarm(delta_seconds: 0); |
72 | } |
73 | |
74 | void uml_rtc_stop(bool timetravel) |
75 | { |
76 | if (timetravel) |
77 | os_close_file(uml_rtc_irq_fds[1]); |
78 | else |
79 | ignore_sigio_fd(uml_rtc_irq_fds[0]); |
80 | os_close_file(uml_rtc_irq_fds[0]); |
81 | } |
82 | |