master
rs 141 lines 4.21 KB
Raw
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 common::{callbacks::FnCall, Opaque};
11
12 use crate::bindings::{
13 self, qemu_clock_get_ns, timer_del, timer_expire_time_ns, timer_init_full, timer_mod,
14 timer_mod_ns, QEMUClockType,
15 };
16
17 /// A safe wrapper around [`bindings::QEMUTimer`].
18 #[repr(transparent)]
19 #[derive(Debug, common::Wrapper)]
20 pub struct Timer(Opaque<bindings::QEMUTimer>);
21
22 unsafe impl Send for Timer {}
23 unsafe impl Sync for Timer {}
24
25 #[repr(transparent)]
26 #[derive(common::Wrapper)]
27 pub struct TimerListGroup(Opaque<bindings::QEMUTimerListGroup>);
28
29 unsafe impl Send for TimerListGroup {}
30 unsafe impl Sync for TimerListGroup {}
31
32 impl Timer {
33 pub const MS: u32 = bindings::SCALE_MS;
34 pub const US: u32 = bindings::SCALE_US;
35 pub const NS: u32 = bindings::SCALE_NS;
36
37 /// Create a `Timer` struct without initializing it.
38 ///
39 /// # Safety
40 ///
41 /// The timer must be initialized before it is armed with
42 /// [`modify`](Self::modify).
43 pub const unsafe fn new() -> Self {
44 // SAFETY: requirements relayed to callers of Timer::new
45 Self(unsafe { Opaque::zeroed() })
46 }
47
48 /// Create a new timer with the given attributes.
49 pub fn init_full<T, F>(
50 opaque: Pin<&mut T>,
51 timer_list_group: Option<&TimerListGroup>,
52 clk_type: ClockType,
53 scale: u32,
54 attributes: u32,
55 _cb: F,
56 field: impl FnOnce(&mut T) -> &mut Self,
57 ) where
58 F: for<'a> FnCall<(&'a T,)>,
59 {
60 const { assert!(F::IS_SOME) };
61
62 /// timer expiration callback
63 unsafe extern "C" fn rust_timer_handler<T, F: for<'a> FnCall<(&'a T,)>>(
64 opaque: *mut c_void,
65 ) {
66 // SAFETY: the opaque was passed as a reference to `T`.
67 F::call((unsafe { &*(opaque.cast::<T>()) },))
68 }
69
70 let timer_cb: unsafe extern "C" fn(*mut c_void) = rust_timer_handler::<T, F>;
71
72 // SAFETY: the opaque outlives the timer
73 unsafe {
74 let opaque = Pin::into_inner_unchecked(opaque);
75 let timer = field(opaque).as_mut_ptr();
76 timer_init_full(
77 timer,
78 if let Some(g) = timer_list_group {
79 g as *const TimerListGroup as *mut _
80 } else {
81 ::core::ptr::null_mut()
82 },
83 clk_type.id,
84 scale as c_int,
85 attributes as c_int,
86 Some(timer_cb),
87 (opaque as *mut T).cast::<c_void>(),
88 )
89 }
90 }
91
92 pub fn expire_time_ns(&self) -> Option<i64> {
93 // SAFETY: the only way to obtain a Timer safely is via methods that
94 // take a Pin<&mut Self>, therefore the timer is pinned
95 let ret = unsafe { timer_expire_time_ns(self.as_ptr()) };
96 i64::try_from(ret).ok()
97 }
98
99 pub fn modify_ns(&self, expire_time: u64) {
100 // SAFETY: the only way to obtain a Timer safely is via methods that
101 // take a Pin<&mut Self>, therefore the timer is pinned
102 unsafe { timer_mod_ns(self.as_mut_ptr(), expire_time.try_into().unwrap()) }
103 }
104
105 pub fn modify(&self, expire_time: u64) {
106 // SAFETY: the only way to obtain a Timer safely is via methods that
107 // take a Pin<&mut Self>, therefore the timer is pinned
108 unsafe { timer_mod(self.as_mut_ptr(), expire_time as i64) }
109 }
110
111 pub fn delete(&self) {
112 // SAFETY: the only way to obtain a Timer safely is via methods that
113 // take a Pin<&mut Self>, therefore the timer is pinned
114 unsafe { timer_del(self.as_mut_ptr()) }
115 }
116 }
117
118 // FIXME: use something like PinnedDrop from the pinned_init crate
119 impl Drop for Timer {
120 fn drop(&mut self) {
121 self.delete()
122 }
123 }
124
125 pub struct ClockType {
126 id: QEMUClockType,
127 }
128
129 impl ClockType {
130 pub fn get_ns(&self) -> u64 {
131 // SAFETY: cannot be created outside this module, therefore id
132 // is valid
133 (unsafe { qemu_clock_get_ns(self.id) }) as u64
134 }
135 }
136
137 pub const CLOCK_VIRTUAL: ClockType = ClockType {
138 id: QEMUClockType::QEMU_CLOCK_VIRTUAL,
139 };
140
141 pub const NANOSECONDS_PER_SECOND: u64 = 1000000000;