162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2020 Intel Corporation 462306a36Sopenharmony_ci * Author: Johannes Berg <johannes@sipsolutions.net> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <stdbool.h> 762306a36Sopenharmony_ci#include <os.h> 862306a36Sopenharmony_ci#include <errno.h> 962306a36Sopenharmony_ci#include <sched.h> 1062306a36Sopenharmony_ci#include <unistd.h> 1162306a36Sopenharmony_ci#include <kern_util.h> 1262306a36Sopenharmony_ci#include <sys/select.h> 1362306a36Sopenharmony_ci#include <stdio.h> 1462306a36Sopenharmony_ci#include <sys/timerfd.h> 1562306a36Sopenharmony_ci#include "rtc.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic int uml_rtc_irq_fds[2]; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_civoid uml_rtc_send_timetravel_alarm(void) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci unsigned long long c = 1; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci CATCH_EINTR(write(uml_rtc_irq_fds[1], &c, sizeof(c))); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ciint uml_rtc_start(bool timetravel) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci int err; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (timetravel) { 3162306a36Sopenharmony_ci int err = os_pipe(uml_rtc_irq_fds, 1, 1); 3262306a36Sopenharmony_ci if (err) 3362306a36Sopenharmony_ci goto fail; 3462306a36Sopenharmony_ci } else { 3562306a36Sopenharmony_ci uml_rtc_irq_fds[0] = timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC); 3662306a36Sopenharmony_ci if (uml_rtc_irq_fds[0] < 0) { 3762306a36Sopenharmony_ci err = -errno; 3862306a36Sopenharmony_ci goto fail; 3962306a36Sopenharmony_ci } 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* apparently timerfd won't send SIGIO, use workaround */ 4262306a36Sopenharmony_ci sigio_broken(uml_rtc_irq_fds[0]); 4362306a36Sopenharmony_ci err = add_sigio_fd(uml_rtc_irq_fds[0]); 4462306a36Sopenharmony_ci if (err < 0) { 4562306a36Sopenharmony_ci close(uml_rtc_irq_fds[0]); 4662306a36Sopenharmony_ci goto fail; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci return uml_rtc_irq_fds[0]; 5162306a36Sopenharmony_cifail: 5262306a36Sopenharmony_ci uml_rtc_stop(timetravel); 5362306a36Sopenharmony_ci return err; 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ciint uml_rtc_enable_alarm(unsigned long long delta_seconds) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct itimerspec it = { 5962306a36Sopenharmony_ci .it_value = { 6062306a36Sopenharmony_ci .tv_sec = delta_seconds, 6162306a36Sopenharmony_ci }, 6262306a36Sopenharmony_ci }; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (timerfd_settime(uml_rtc_irq_fds[0], 0, &it, NULL)) 6562306a36Sopenharmony_ci return -errno; 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid uml_rtc_disable_alarm(void) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci uml_rtc_enable_alarm(0); 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_civoid uml_rtc_stop(bool timetravel) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci if (timetravel) 7762306a36Sopenharmony_ci os_close_file(uml_rtc_irq_fds[1]); 7862306a36Sopenharmony_ci else 7962306a36Sopenharmony_ci ignore_sigio_fd(uml_rtc_irq_fds[0]); 8062306a36Sopenharmony_ci os_close_file(uml_rtc_irq_fds[0]); 8162306a36Sopenharmony_ci} 82