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