xref: /qemu/rust/qemu-api/src/timer.rs (revision 3228d311ab1882f75b04d080d33a71fc7a0bcac5)
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