1 // Copyright (C) 2024 Intel Corporation. 2 // Author(s): Zhao Liu <zhai1.liu@intel.com> 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 use std::os::raw::{c_int, c_void}; 6 7 use crate::{ 8 bindings::{self, qemu_clock_get_ns, timer_del, timer_init_full, timer_mod, QEMUClockType}, 9 callbacks::FnCall, 10 }; 11 12 pub type Timer = bindings::QEMUTimer; 13 pub type TimerListGroup = bindings::QEMUTimerListGroup; 14 15 impl Timer { 16 pub const MS: u32 = bindings::SCALE_MS; 17 pub const US: u32 = bindings::SCALE_US; 18 pub const NS: u32 = bindings::SCALE_NS; 19 20 pub fn new() -> Self { 21 Default::default() 22 } 23 24 const fn as_mut_ptr(&self) -> *mut Self { 25 self as *const Timer as *mut _ 26 } 27 28 pub fn init_full<'timer, 'opaque: 'timer, T, F>( 29 &'timer mut self, 30 timer_list_group: Option<&TimerListGroup>, 31 clk_type: ClockType, 32 scale: u32, 33 attributes: u32, 34 _cb: F, 35 opaque: &'opaque T, 36 ) where 37 F: for<'a> FnCall<(&'a T,)>, 38 { 39 let _: () = F::ASSERT_IS_SOME; 40 41 /// timer expiration callback 42 unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>( 43 opaque: *mut c_void, 44 ) { 45 // SAFETY: the opaque was passed as a reference to `T`. 46 F::call((unsafe { &*(opaque.cast::<T>()) },)) 47 } 48 49 let timer_cb: unsafe extern "C" fn(*mut c_void) = rust_timer_handler::<T, F>; 50 51 // SAFETY: the opaque outlives the timer 52 unsafe { 53 timer_init_full( 54 self, 55 if let Some(g) = timer_list_group { 56 g as *const TimerListGroup as *mut _ 57 } else { 58 ::core::ptr::null_mut() 59 }, 60 clk_type.id, 61 scale as c_int, 62 attributes as c_int, 63 Some(timer_cb), 64 (opaque as *const T).cast::<c_void>() as *mut c_void, 65 ) 66 } 67 } 68 69 pub fn modify(&self, expire_time: u64) { 70 unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) } 71 } 72 73 pub fn delete(&self) { 74 unsafe { timer_del(self.as_mut_ptr()) } 75 } 76 } 77 78 impl Drop for Timer { 79 fn drop(&mut self) { 80 self.delete() 81 } 82 } 83 84 pub struct ClockType { 85 id: QEMUClockType, 86 } 87 88 impl ClockType { 89 pub fn get_ns(&self) -> u64 { 90 // SAFETY: cannot be created outside this module, therefore id 91 // is valid 92 (unsafe { qemu_clock_get_ns(self.id) }) as u64 93 } 94 } 95 96 pub const CLOCK_VIRTUAL: ClockType = ClockType { 97 id: QEMUClockType::QEMU_CLOCK_VIRTUAL, 98 }; 99