1eadb83f9SZhao Liu // Copyright (C) 2024 Intel Corporation. 2*86c54a3aSZhao Liu // Author(s): Zhao Liu <zhao1.liu@intel.com> 3eadb83f9SZhao Liu // SPDX-License-Identifier: GPL-2.0-or-later 4eadb83f9SZhao Liu 5a32b2396SPaolo Bonzini use std::{ 6e4fb0be1SPaolo Bonzini ffi::{c_int, c_void}, 7a32b2396SPaolo Bonzini pin::Pin, 8a32b2396SPaolo Bonzini }; 9eadb83f9SZhao Liu 10eadb83f9SZhao Liu use crate::{ 11eadb83f9SZhao Liu bindings::{self, qemu_clock_get_ns, timer_del, timer_init_full, timer_mod, QEMUClockType}, 12eadb83f9SZhao Liu callbacks::FnCall, 13a32b2396SPaolo Bonzini cell::Opaque, 14eadb83f9SZhao Liu }; 15eadb83f9SZhao Liu 16a32b2396SPaolo Bonzini /// A safe wrapper around [`bindings::QEMUTimer`]. 17a32b2396SPaolo Bonzini #[repr(transparent)] 18a32b2396SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)] 19a32b2396SPaolo Bonzini pub struct Timer(Opaque<bindings::QEMUTimer>); 20a32b2396SPaolo Bonzini 21a32b2396SPaolo Bonzini unsafe impl Send for Timer {} 22a32b2396SPaolo Bonzini unsafe impl Sync for Timer {} 23a32b2396SPaolo Bonzini 24a32b2396SPaolo Bonzini #[repr(transparent)] 25a32b2396SPaolo Bonzini #[derive(qemu_api_macros::Wrapper)] 26a32b2396SPaolo Bonzini pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>); 27a32b2396SPaolo Bonzini 28a32b2396SPaolo Bonzini unsafe impl Send for TimerListGroup {} 29a32b2396SPaolo Bonzini unsafe impl Sync for TimerListGroup {} 30eadb83f9SZhao Liu 31eadb83f9SZhao Liu impl Timer { 32eadb83f9SZhao Liu pub const MS: u32 = bindings::SCALE_MS; 33eadb83f9SZhao Liu pub const US: u32 = bindings::SCALE_US; 34eadb83f9SZhao Liu pub const NS: u32 = bindings::SCALE_NS; 35eadb83f9SZhao Liu 36a32b2396SPaolo Bonzini /// Create a `Timer` struct without initializing it. 37a32b2396SPaolo Bonzini /// 38a32b2396SPaolo Bonzini /// # Safety 39a32b2396SPaolo Bonzini /// 40a32b2396SPaolo Bonzini /// The timer must be initialized before it is armed with 41a32b2396SPaolo Bonzini /// [`modify`](Self::modify). new() -> Self42a32b2396SPaolo Bonzini pub unsafe fn new() -> Self { 43a32b2396SPaolo Bonzini // SAFETY: requirements relayed to callers of Timer::new 44a32b2396SPaolo Bonzini Self(unsafe { Opaque::zeroed() }) 45eadb83f9SZhao Liu } 46eadb83f9SZhao Liu 47a32b2396SPaolo Bonzini /// Create a new timer with the given attributes. init_full<'timer, 'opaque: 'timer, T, F>( self: Pin<&'timer mut Self>, timer_list_group: Option<&TimerListGroup>, clk_type: ClockType, scale: u32, attributes: u32, _cb: F, opaque: &'opaque T, ) where F: for<'a> FnCall<(&'a T,)>,48eadb83f9SZhao Liu pub fn init_full<'timer, 'opaque: 'timer, T, F>( 49a32b2396SPaolo Bonzini self: Pin<&'timer mut Self>, 50eadb83f9SZhao Liu timer_list_group: Option<&TimerListGroup>, 51eadb83f9SZhao Liu clk_type: ClockType, 52eadb83f9SZhao Liu scale: u32, 53eadb83f9SZhao Liu attributes: u32, 54eadb83f9SZhao Liu _cb: F, 55eadb83f9SZhao Liu opaque: &'opaque T, 56eadb83f9SZhao Liu ) where 57eadb83f9SZhao Liu F: for<'a> FnCall<(&'a T,)>, 58eadb83f9SZhao Liu { 59eadb83f9SZhao Liu let _: () = F::ASSERT_IS_SOME; 60eadb83f9SZhao Liu 61eadb83f9SZhao Liu /// timer expiration callback 62eadb83f9SZhao Liu unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>( 63eadb83f9SZhao Liu opaque: *mut c_void, 64eadb83f9SZhao Liu ) { 65eadb83f9SZhao Liu // SAFETY: the opaque was passed as a reference to `T`. 66eadb83f9SZhao Liu F::call((unsafe { &*(opaque.cast::<T>()) },)) 67eadb83f9SZhao Liu } 68eadb83f9SZhao Liu 69eadb83f9SZhao Liu let timer_cb: unsafe extern "C" fn(*mut c_void) = rust_timer_handler::<T, F>; 70eadb83f9SZhao Liu 71eadb83f9SZhao Liu // SAFETY: the opaque outlives the timer 72eadb83f9SZhao Liu unsafe { 73eadb83f9SZhao Liu timer_init_full( 74a32b2396SPaolo Bonzini self.as_mut_ptr(), 75eadb83f9SZhao Liu if let Some(g) = timer_list_group { 76eadb83f9SZhao Liu g as *const TimerListGroup as *mut _ 77eadb83f9SZhao Liu } else { 78eadb83f9SZhao Liu ::core::ptr::null_mut() 79eadb83f9SZhao Liu }, 80eadb83f9SZhao Liu clk_type.id, 81eadb83f9SZhao Liu scale as c_int, 82eadb83f9SZhao Liu attributes as c_int, 83eadb83f9SZhao Liu Some(timer_cb), 845df3fe06SPaolo Bonzini (opaque as *const T).cast::<c_void>().cast_mut(), 85eadb83f9SZhao Liu ) 86eadb83f9SZhao Liu } 87eadb83f9SZhao Liu } 88eadb83f9SZhao Liu modify(&self, expire_time: u64)89eadb83f9SZhao Liu pub fn modify(&self, expire_time: u64) { 90a32b2396SPaolo Bonzini // SAFETY: the only way to obtain a Timer safely is via methods that 91a32b2396SPaolo Bonzini // take a Pin<&mut Self>, therefore the timer is pinned 92eadb83f9SZhao Liu unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) } 93eadb83f9SZhao Liu } 94eadb83f9SZhao Liu delete(&self)95eadb83f9SZhao Liu pub fn delete(&self) { 96a32b2396SPaolo Bonzini // SAFETY: the only way to obtain a Timer safely is via methods that 97a32b2396SPaolo Bonzini // take a Pin<&mut Self>, therefore the timer is pinned 98eadb83f9SZhao Liu unsafe { timer_del(self.as_mut_ptr()) } 99eadb83f9SZhao Liu } 100eadb83f9SZhao Liu } 101eadb83f9SZhao Liu 102a32b2396SPaolo Bonzini // FIXME: use something like PinnedDrop from the pinned_init crate 103eadb83f9SZhao Liu impl Drop for Timer { drop(&mut self)104eadb83f9SZhao Liu fn drop(&mut self) { 105eadb83f9SZhao Liu self.delete() 106eadb83f9SZhao Liu } 107eadb83f9SZhao Liu } 108eadb83f9SZhao Liu 109eadb83f9SZhao Liu pub struct ClockType { 110eadb83f9SZhao Liu id: QEMUClockType, 111eadb83f9SZhao Liu } 112eadb83f9SZhao Liu 113eadb83f9SZhao Liu impl ClockType { get_ns(&self) -> u64114eadb83f9SZhao Liu pub fn get_ns(&self) -> u64 { 115eadb83f9SZhao Liu // SAFETY: cannot be created outside this module, therefore id 116eadb83f9SZhao Liu // is valid 117eadb83f9SZhao Liu (unsafe { qemu_clock_get_ns(self.id) }) as u64 118eadb83f9SZhao Liu } 119eadb83f9SZhao Liu } 120eadb83f9SZhao Liu 121eadb83f9SZhao Liu pub const CLOCK_VIRTUAL: ClockType = ClockType { 122eadb83f9SZhao Liu id: QEMUClockType::QEMU_CLOCK_VIRTUAL, 123eadb83f9SZhao Liu }; 1248d9502b4SZhao Liu 1258d9502b4SZhao Liu pub const NANOSECONDS_PER_SECOND: u64 = 1000000000; 126