xref: /openbmc/qemu/rust/util/src/timer.rs (revision ccafa85a97e38698b798115bba6c18c849846e25)
159869b4dSMarc-André Lureau // Copyright (C) 2024 Intel Corporation.
259869b4dSMarc-André Lureau // Author(s): Zhao Liu <zhao1.liu@intel.com>
359869b4dSMarc-André Lureau // SPDX-License-Identifier: GPL-2.0-or-later
459869b4dSMarc-André Lureau 
559869b4dSMarc-André Lureau use std::{
659869b4dSMarc-André Lureau     ffi::{c_int, c_void},
759869b4dSMarc-André Lureau     pin::Pin,
859869b4dSMarc-André Lureau };
959869b4dSMarc-André Lureau 
1059869b4dSMarc-André Lureau use common::{callbacks::FnCall, Opaque};
1159869b4dSMarc-André Lureau 
1259869b4dSMarc-André Lureau use crate::bindings::{
1359869b4dSMarc-André Lureau     self, qemu_clock_get_ns, timer_del, timer_init_full, timer_mod, QEMUClockType,
1459869b4dSMarc-André Lureau };
1559869b4dSMarc-André Lureau 
1659869b4dSMarc-André Lureau /// A safe wrapper around [`bindings::QEMUTimer`].
1759869b4dSMarc-André Lureau #[repr(transparent)]
18*e4444d71SMarc-André Lureau #[derive(Debug, common::Wrapper)]
1959869b4dSMarc-André Lureau pub struct Timer(Opaque<bindings::QEMUTimer>);
2059869b4dSMarc-André Lureau 
2159869b4dSMarc-André Lureau unsafe impl Send for Timer {}
2259869b4dSMarc-André Lureau unsafe impl Sync for Timer {}
2359869b4dSMarc-André Lureau 
2459869b4dSMarc-André Lureau #[repr(transparent)]
25*e4444d71SMarc-André Lureau #[derive(common::Wrapper)]
2659869b4dSMarc-André Lureau pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>);
2759869b4dSMarc-André Lureau 
2859869b4dSMarc-André Lureau unsafe impl Send for TimerListGroup {}
2959869b4dSMarc-André Lureau unsafe impl Sync for TimerListGroup {}
3059869b4dSMarc-André Lureau 
3159869b4dSMarc-André Lureau impl Timer {
3259869b4dSMarc-André Lureau     pub const MS: u32 = bindings::SCALE_MS;
3359869b4dSMarc-André Lureau     pub const US: u32 = bindings::SCALE_US;
3459869b4dSMarc-André Lureau     pub const NS: u32 = bindings::SCALE_NS;
3559869b4dSMarc-André Lureau 
3659869b4dSMarc-André Lureau     /// Create a `Timer` struct without initializing it.
3759869b4dSMarc-André Lureau     ///
3859869b4dSMarc-André Lureau     /// # Safety
3959869b4dSMarc-André Lureau     ///
4059869b4dSMarc-André Lureau     /// The timer must be initialized before it is armed with
4159869b4dSMarc-André Lureau     /// [`modify`](Self::modify).
4259869b4dSMarc-André Lureau     pub const unsafe fn new() -> Self {
4359869b4dSMarc-André Lureau         // SAFETY: requirements relayed to callers of Timer::new
4459869b4dSMarc-André Lureau         Self(unsafe { Opaque::zeroed() })
4559869b4dSMarc-André Lureau     }
4659869b4dSMarc-André Lureau 
4759869b4dSMarc-André Lureau     /// Create a new timer with the given attributes.
4859869b4dSMarc-André Lureau     pub fn init_full<'timer, 'opaque: 'timer, T, F>(
4959869b4dSMarc-André Lureau         self: Pin<&'timer mut Self>,
5059869b4dSMarc-André Lureau         timer_list_group: Option<&TimerListGroup>,
5159869b4dSMarc-André Lureau         clk_type: ClockType,
5259869b4dSMarc-André Lureau         scale: u32,
5359869b4dSMarc-André Lureau         attributes: u32,
5459869b4dSMarc-André Lureau         _cb: F,
5559869b4dSMarc-André Lureau         opaque: &'opaque T,
5659869b4dSMarc-André Lureau     ) where
5759869b4dSMarc-André Lureau         F: for<'a> FnCall<(&'a T,)>,
5859869b4dSMarc-André Lureau     {
5959869b4dSMarc-André Lureau         const { assert!(F::IS_SOME) };
6059869b4dSMarc-André Lureau 
6159869b4dSMarc-André Lureau         /// timer expiration callback
6259869b4dSMarc-André Lureau         unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>(
6359869b4dSMarc-André Lureau             opaque: *mut c_void,
6459869b4dSMarc-André Lureau         ) {
6559869b4dSMarc-André Lureau             // SAFETY: the opaque was passed as a reference to `T`.
6659869b4dSMarc-André Lureau             F::call((unsafe { &*(opaque.cast::<T>()) },))
6759869b4dSMarc-André Lureau         }
6859869b4dSMarc-André Lureau 
6959869b4dSMarc-André Lureau         let timer_cb: unsafe extern "C" fn(*mut c_void) = rust_timer_handler::<T, F>;
7059869b4dSMarc-André Lureau 
7159869b4dSMarc-André Lureau         // SAFETY: the opaque outlives the timer
7259869b4dSMarc-André Lureau         unsafe {
7359869b4dSMarc-André Lureau             timer_init_full(
7459869b4dSMarc-André Lureau                 self.as_mut_ptr(),
7559869b4dSMarc-André Lureau                 if let Some(g) = timer_list_group {
7659869b4dSMarc-André Lureau                     g as *const TimerListGroup as *mut _
7759869b4dSMarc-André Lureau                 } else {
7859869b4dSMarc-André Lureau                     ::core::ptr::null_mut()
7959869b4dSMarc-André Lureau                 },
8059869b4dSMarc-André Lureau                 clk_type.id,
8159869b4dSMarc-André Lureau                 scale as c_int,
8259869b4dSMarc-André Lureau                 attributes as c_int,
8359869b4dSMarc-André Lureau                 Some(timer_cb),
8459869b4dSMarc-André Lureau                 (opaque as *const T).cast::<c_void>().cast_mut(),
8559869b4dSMarc-André Lureau             )
8659869b4dSMarc-André Lureau         }
8759869b4dSMarc-André Lureau     }
8859869b4dSMarc-André Lureau 
8959869b4dSMarc-André Lureau     pub fn modify(&self, expire_time: u64) {
9059869b4dSMarc-André Lureau         // SAFETY: the only way to obtain a Timer safely is via methods that
9159869b4dSMarc-André Lureau         // take a Pin<&mut Self>, therefore the timer is pinned
9259869b4dSMarc-André Lureau         unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) }
9359869b4dSMarc-André Lureau     }
9459869b4dSMarc-André Lureau 
9559869b4dSMarc-André Lureau     pub fn delete(&self) {
9659869b4dSMarc-André Lureau         // SAFETY: the only way to obtain a Timer safely is via methods that
9759869b4dSMarc-André Lureau         // take a Pin<&mut Self>, therefore the timer is pinned
9859869b4dSMarc-André Lureau         unsafe { timer_del(self.as_mut_ptr()) }
9959869b4dSMarc-André Lureau     }
10059869b4dSMarc-André Lureau }
10159869b4dSMarc-André Lureau 
10259869b4dSMarc-André Lureau // FIXME: use something like PinnedDrop from the pinned_init crate
10359869b4dSMarc-André Lureau impl Drop for Timer {
10459869b4dSMarc-André Lureau     fn drop(&mut self) {
10559869b4dSMarc-André Lureau         self.delete()
10659869b4dSMarc-André Lureau     }
10759869b4dSMarc-André Lureau }
10859869b4dSMarc-André Lureau 
10959869b4dSMarc-André Lureau pub struct ClockType {
11059869b4dSMarc-André Lureau     id: QEMUClockType,
11159869b4dSMarc-André Lureau }
11259869b4dSMarc-André Lureau 
11359869b4dSMarc-André Lureau impl ClockType {
11459869b4dSMarc-André Lureau     pub fn get_ns(&self) -> u64 {
11559869b4dSMarc-André Lureau         // SAFETY: cannot be created outside this module, therefore id
11659869b4dSMarc-André Lureau         // is valid
11759869b4dSMarc-André Lureau         (unsafe { qemu_clock_get_ns(self.id) }) as u64
11859869b4dSMarc-André Lureau     }
11959869b4dSMarc-André Lureau }
12059869b4dSMarc-André Lureau 
12159869b4dSMarc-André Lureau pub const CLOCK_VIRTUAL: ClockType = ClockType {
12259869b4dSMarc-André Lureau     id: QEMUClockType::QEMU_CLOCK_VIRTUAL,
12359869b4dSMarc-André Lureau };
12459869b4dSMarc-André Lureau 
12559869b4dSMarc-André Lureau pub const NANOSECONDS_PER_SECOND: u64 = 1000000000;
126