xref: /openbmc/qemu/rust/qemu-api/src/timer.rs (revision 1843a0c01d06049f517fea7e155e5236e7287276)
1eadb83f9SZhao Liu // Copyright (C) 2024 Intel Corporation.
2eadb83f9SZhao Liu // Author(s): Zhao Liu <zhai1.liu@intel.com>
3eadb83f9SZhao Liu // SPDX-License-Identifier: GPL-2.0-or-later
4eadb83f9SZhao Liu 
5*a32b2396SPaolo Bonzini use std::{
6*a32b2396SPaolo Bonzini     os::raw::{c_int, c_void},
7*a32b2396SPaolo Bonzini     pin::Pin,
8*a32b2396SPaolo 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,
13*a32b2396SPaolo Bonzini     cell::Opaque,
14eadb83f9SZhao Liu };
15eadb83f9SZhao Liu 
16*a32b2396SPaolo Bonzini /// A safe wrapper around [`bindings::QEMUTimer`].
17*a32b2396SPaolo Bonzini #[repr(transparent)]
18*a32b2396SPaolo Bonzini #[derive(Debug, qemu_api_macros::Wrapper)]
19*a32b2396SPaolo Bonzini pub struct Timer(Opaque<bindings::QEMUTimer>);
20*a32b2396SPaolo Bonzini 
21*a32b2396SPaolo Bonzini unsafe impl Send for Timer {}
22*a32b2396SPaolo Bonzini unsafe impl Sync for Timer {}
23*a32b2396SPaolo Bonzini 
24*a32b2396SPaolo Bonzini #[repr(transparent)]
25*a32b2396SPaolo Bonzini #[derive(qemu_api_macros::Wrapper)]
26*a32b2396SPaolo Bonzini pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>);
27*a32b2396SPaolo Bonzini 
28*a32b2396SPaolo Bonzini unsafe impl Send for TimerListGroup {}
29*a32b2396SPaolo 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 
36*a32b2396SPaolo Bonzini     /// Create a `Timer` struct without initializing it.
37*a32b2396SPaolo Bonzini     ///
38*a32b2396SPaolo Bonzini     /// # Safety
39*a32b2396SPaolo Bonzini     ///
40*a32b2396SPaolo Bonzini     /// The timer must be initialized before it is armed with
41*a32b2396SPaolo Bonzini     /// [`modify`](Self::modify).
new() -> Self42*a32b2396SPaolo Bonzini     pub unsafe fn new() -> Self {
43*a32b2396SPaolo Bonzini         // SAFETY: requirements relayed to callers of Timer::new
44*a32b2396SPaolo Bonzini         Self(unsafe { Opaque::zeroed() })
45eadb83f9SZhao Liu     }
46eadb83f9SZhao Liu 
47*a32b2396SPaolo 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>(
49*a32b2396SPaolo 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(
74*a32b2396SPaolo 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),
84eadb83f9SZhao Liu                 (opaque as *const T).cast::<c_void>() as *mut c_void,
85eadb83f9SZhao Liu             )
86eadb83f9SZhao Liu         }
87eadb83f9SZhao Liu     }
88eadb83f9SZhao Liu 
modify(&self, expire_time: u64)89eadb83f9SZhao Liu     pub fn modify(&self, expire_time: u64) {
90*a32b2396SPaolo Bonzini         // SAFETY: the only way to obtain a Timer safely is via methods that
91*a32b2396SPaolo 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) {
96*a32b2396SPaolo Bonzini         // SAFETY: the only way to obtain a Timer safely is via methods that
97*a32b2396SPaolo 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 
102*a32b2396SPaolo 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 };
124