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