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