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