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(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