xref: /aosp_15_r20/external/crosvm/devices/src/virtio/pvclock.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker //! Virtio version of a linux pvclock clocksource.
6*bb4ee6a4SAndroid Build Coastguard Worker //!
7*bb4ee6a4SAndroid Build Coastguard Worker //! Driver source is here:
8*bb4ee6a4SAndroid Build Coastguard Worker //! <https://android.googlesource.com/kernel/common/+/ebaa2c516811825b141de844cee7a38653058ef5/drivers/virtio/virtio_pvclock.c>
9*bb4ee6a4SAndroid Build Coastguard Worker //!
10*bb4ee6a4SAndroid Build Coastguard Worker //! # Background
11*bb4ee6a4SAndroid Build Coastguard Worker //!
12*bb4ee6a4SAndroid Build Coastguard Worker //! Userland applications often rely on CLOCK_MONOTONIC to be relatively continuous.
13*bb4ee6a4SAndroid Build Coastguard Worker //! Large jumps can signal problems (e.g., triggering Android watchdogs).
14*bb4ee6a4SAndroid Build Coastguard Worker //! This assumption breaks down in virtualized environments, where a VM's suspension isn't
15*bb4ee6a4SAndroid Build Coastguard Worker //! inherently linked to the guest kernel's concept of "suspend".
16*bb4ee6a4SAndroid Build Coastguard Worker //! Since fixing all userland code is impractical, virtio-pvclock allows the VMM and guest kernel
17*bb4ee6a4SAndroid Build Coastguard Worker //! to collaborate on emulating the expected clock behavior around suspend/resume.
18*bb4ee6a4SAndroid Build Coastguard Worker //!
19*bb4ee6a4SAndroid Build Coastguard Worker //! # How it works
20*bb4ee6a4SAndroid Build Coastguard Worker //!
21*bb4ee6a4SAndroid Build Coastguard Worker //! ## Core functions of virtio-pvclock device:
22*bb4ee6a4SAndroid Build Coastguard Worker //!
23*bb4ee6a4SAndroid Build Coastguard Worker //! 1. Adjusts hardware clocksource offsets to make the guest clocks appear suspended when the VM is
24*bb4ee6a4SAndroid Build Coastguard Worker //!    suspended.
25*bb4ee6a4SAndroid Build Coastguard Worker //!   - This is achieved through the pvclock mechanism implemented in x86 KVM used by kvm-clock.
26*bb4ee6a4SAndroid Build Coastguard Worker //! 2. Provides the guest kernel with the duration of VM suspension, allowing the guest to adjust
27*bb4ee6a4SAndroid Build Coastguard Worker //!    its clocks accordingly.
28*bb4ee6a4SAndroid Build Coastguard Worker //!   - Since the offset between the CLOCK_MONOTONIC and CLOCK_BOOTTIME is maintained by the guest
29*bb4ee6a4SAndroid Build Coastguard Worker //!     kernel, applying the adjustment is the guest driver's responsibility.
30*bb4ee6a4SAndroid Build Coastguard Worker //!
31*bb4ee6a4SAndroid Build Coastguard Worker //! ## Expected guest clock behaviors under virtio-pvclock is enabled
32*bb4ee6a4SAndroid Build Coastguard Worker //!
33*bb4ee6a4SAndroid Build Coastguard Worker //! - Monotonicity of CLOCK_MONOTONIC and CLOCK_BOOTTIME is maintained.
34*bb4ee6a4SAndroid Build Coastguard Worker //! - CLOCK_MONOTONIC will not include the time passed during crosvm is suspended from its run mode
35*bb4ee6a4SAndroid Build Coastguard Worker //!   perspective.
36*bb4ee6a4SAndroid Build Coastguard Worker //! - CLOCK_BOOTTIME will be adjusted to include the time passed during crosvm is suspended.
37*bb4ee6a4SAndroid Build Coastguard Worker //!
38*bb4ee6a4SAndroid Build Coastguard Worker //! # Why it is needed
39*bb4ee6a4SAndroid Build Coastguard Worker //!
40*bb4ee6a4SAndroid Build Coastguard Worker //! Because the existing solution does not cover some expectations we need.
41*bb4ee6a4SAndroid Build Coastguard Worker //!
42*bb4ee6a4SAndroid Build Coastguard Worker //! kvm-clock is letting the host to manage the offsets of CLOCK_MONOTONIC.
43*bb4ee6a4SAndroid Build Coastguard Worker //! However, it doesn't address the difference between CLOCK_BOOTTIME and CLOCK_MONOTONIC related
44*bb4ee6a4SAndroid Build Coastguard Worker //! to host's suspend/resume, as it is designed to maintain the CLOCK_REALTIME in sync mainly.
45*bb4ee6a4SAndroid Build Coastguard Worker 
46*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "aarch64")]
47*bb4ee6a4SAndroid Build Coastguard Worker use std::arch::asm;
48*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
49*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::replace;
50*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of;
51*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::AtomicU64;
52*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::atomic::Ordering;
53*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
54*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
55*bb4ee6a4SAndroid Build Coastguard Worker 
56*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
57*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
58*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
59*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
60*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
61*bb4ee6a4SAndroid Build Coastguard Worker use base::info;
62*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
63*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
64*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
65*bb4ee6a4SAndroid Build Coastguard Worker use base::CloseNotifier;
66*bb4ee6a4SAndroid Build Coastguard Worker use base::Error;
67*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
68*bb4ee6a4SAndroid Build Coastguard Worker use base::EventToken;
69*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
70*bb4ee6a4SAndroid Build Coastguard Worker use base::ReadNotifier;
71*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
72*bb4ee6a4SAndroid Build Coastguard Worker use base::WaitContext;
73*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
74*bb4ee6a4SAndroid Build Coastguard Worker use chrono::DateTime;
75*bb4ee6a4SAndroid Build Coastguard Worker use chrono::Utc;
76*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
77*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le64;
78*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
79*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
80*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::PvClockCommand;
81*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::PvClockCommandResponse;
82*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
83*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
84*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemoryError;
85*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
86*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
87*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
88*bb4ee6a4SAndroid Build Coastguard Worker 
89*bb4ee6a4SAndroid Build Coastguard Worker use super::copy_config;
90*bb4ee6a4SAndroid Build Coastguard Worker use super::DeviceType;
91*bb4ee6a4SAndroid Build Coastguard Worker use super::Interrupt;
92*bb4ee6a4SAndroid Build Coastguard Worker use super::Queue;
93*bb4ee6a4SAndroid Build Coastguard Worker use super::VirtioDevice;
94*bb4ee6a4SAndroid Build Coastguard Worker 
95*bb4ee6a4SAndroid Build Coastguard Worker // Pvclock has one virtio queue: set_pvclock_page
96*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 1;
97*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
98*bb4ee6a4SAndroid Build Coastguard Worker 
99*bb4ee6a4SAndroid Build Coastguard Worker // pvclock flag bits
100*bb4ee6a4SAndroid Build Coastguard Worker const PVCLOCK_TSC_STABLE_BIT: u8 = 1;
101*bb4ee6a4SAndroid Build Coastguard Worker const PVCLOCK_GUEST_STOPPED: u8 = 2;
102*bb4ee6a4SAndroid Build Coastguard Worker 
103*bb4ee6a4SAndroid Build Coastguard Worker // The feature bitmap for virtio pvclock
104*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_F_TSC_STABLE: u64 = 0; // TSC is stable
105*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_F_INJECT_SLEEP: u64 = 1; // Inject sleep for suspend
106*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING: u64 = 2; // Use device clocksource rating
107*bb4ee6a4SAndroid Build Coastguard Worker 
108*bb4ee6a4SAndroid Build Coastguard Worker // Status values for a virtio_pvclock request.
109*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_S_OK: u8 = 0;
110*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_S_IOERR: u8 = 1;
111*bb4ee6a4SAndroid Build Coastguard Worker 
112*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PVCLOCK_CLOCKSOURCE_RATING: u32 = 450;
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
read_clock_counter() -> u64115*bb4ee6a4SAndroid Build Coastguard Worker fn read_clock_counter() -> u64 {
116*bb4ee6a4SAndroid Build Coastguard Worker     // SAFETY: rdtsc is unprivileged and have no side effects.
117*bb4ee6a4SAndroid Build Coastguard Worker     unsafe { std::arch::x86_64::_rdtsc() }
118*bb4ee6a4SAndroid Build Coastguard Worker }
119*bb4ee6a4SAndroid Build Coastguard Worker 
120*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "aarch64")]
read_clock_counter() -> u64121*bb4ee6a4SAndroid Build Coastguard Worker fn read_clock_counter() -> u64 {
122*bb4ee6a4SAndroid Build Coastguard Worker     let mut x: u64;
123*bb4ee6a4SAndroid Build Coastguard Worker     // SAFETY: This instruction have no side effect apart from storing the current timestamp counter
124*bb4ee6a4SAndroid Build Coastguard Worker     //         into the specified register.
125*bb4ee6a4SAndroid Build Coastguard Worker     unsafe {
126*bb4ee6a4SAndroid Build Coastguard Worker         asm!("mrs {x}, cntvct_el0",
127*bb4ee6a4SAndroid Build Coastguard Worker             x = out(reg) x,
128*bb4ee6a4SAndroid Build Coastguard Worker         );
129*bb4ee6a4SAndroid Build Coastguard Worker     }
130*bb4ee6a4SAndroid Build Coastguard Worker     x
131*bb4ee6a4SAndroid Build Coastguard Worker }
132*bb4ee6a4SAndroid Build Coastguard Worker 
133*bb4ee6a4SAndroid Build Coastguard Worker /// Calculate a (multiplier, shift) pair for scaled math of clocks.
134*bb4ee6a4SAndroid Build Coastguard Worker /// The values are passed on to `pvclock_scale_delta` in the guest kernel and satisfy the following
135*bb4ee6a4SAndroid Build Coastguard Worker /// (approximate) equality:
136*bb4ee6a4SAndroid Build Coastguard Worker /// `n * scaled_hz / base_hz ~= ((n << shift) * multiplier) >> 32`
137*bb4ee6a4SAndroid Build Coastguard Worker /// The logic here is roughly based on `kvm_get_time_scale` (but simplified as we can use u128).
138*bb4ee6a4SAndroid Build Coastguard Worker /// # Arguments
139*bb4ee6a4SAndroid Build Coastguard Worker /// * `scaled_hz` - Frequency to convert to. When dealing with clocksources, this is NSEC_PER_SEC.
140*bb4ee6a4SAndroid Build Coastguard Worker /// * `base_hz` - Frequency to convert from. When dealing with clocksources, this is the counter
141*bb4ee6a4SAndroid Build Coastguard Worker ///   frequency.
freq_scale_shift(scaled_hz: u64, base_hz: u64) -> (u32, i8)142*bb4ee6a4SAndroid Build Coastguard Worker fn freq_scale_shift(scaled_hz: u64, base_hz: u64) -> (u32, i8) {
143*bb4ee6a4SAndroid Build Coastguard Worker     assert!(scaled_hz > 0 && base_hz > 0);
144*bb4ee6a4SAndroid Build Coastguard Worker     // We treat `multiplier` as a 0.32 fixed-point number by folding the >> 32 into its definition.
145*bb4ee6a4SAndroid Build Coastguard Worker     // With this definition, `multiplier` can be calculated as `(scaled_hz / base_hz) >> shift`
146*bb4ee6a4SAndroid Build Coastguard Worker     // with a corresponding `shift`.
147*bb4ee6a4SAndroid Build Coastguard Worker     //
148*bb4ee6a4SAndroid Build Coastguard Worker     // The value of `shift` should satisfy a few constraints:
149*bb4ee6a4SAndroid Build Coastguard Worker     // 1. `multiplier` needs to be < 1.0 due to the representable range of 0.32 fixed-point (maximum
150*bb4ee6a4SAndroid Build Coastguard Worker     //    (2^32-1)/2^32).
151*bb4ee6a4SAndroid Build Coastguard Worker     // 2. `shift` should be minimized because `pvclock_scale_delta` applies `shift` on the 64-bit
152*bb4ee6a4SAndroid Build Coastguard Worker     //    TSC value before extending to 128-bit and large positive shifts reduce the TSC rollover
153*bb4ee6a4SAndroid Build Coastguard Worker     //    time.
154*bb4ee6a4SAndroid Build Coastguard Worker     //
155*bb4ee6a4SAndroid Build Coastguard Worker     // Minimizing `shift` means maximizing `multiplier`. From the < 1.0 constraint, this is
156*bb4ee6a4SAndroid Build Coastguard Worker     // equivalent to having a multiplier within [0.5, 1.0). The logic below picks a multiplier
157*bb4ee6a4SAndroid Build Coastguard Worker     // satisfying that, while updating `shift` accordingly when we double or halve the multiplier.
158*bb4ee6a4SAndroid Build Coastguard Worker     let mut shift = 0;
159*bb4ee6a4SAndroid Build Coastguard Worker     // Convert to u128 so that overflow handling becomes much easier.
160*bb4ee6a4SAndroid Build Coastguard Worker     let mut scaled_hz = scaled_hz as u128;
161*bb4ee6a4SAndroid Build Coastguard Worker     let mut base_hz = base_hz as u128;
162*bb4ee6a4SAndroid Build Coastguard Worker     if scaled_hz >= base_hz {
163*bb4ee6a4SAndroid Build Coastguard Worker         while scaled_hz >= base_hz {
164*bb4ee6a4SAndroid Build Coastguard Worker             // `multiplier` >= 1.0; iteratively scale it down
165*bb4ee6a4SAndroid Build Coastguard Worker             // scaled_hz is at most 64 bits, so after this loop base_hz is at most 65 bits.
166*bb4ee6a4SAndroid Build Coastguard Worker             base_hz <<= 1;
167*bb4ee6a4SAndroid Build Coastguard Worker             shift += 1;
168*bb4ee6a4SAndroid Build Coastguard Worker         }
169*bb4ee6a4SAndroid Build Coastguard Worker     } else {
170*bb4ee6a4SAndroid Build Coastguard Worker         while base_hz > 2 * scaled_hz {
171*bb4ee6a4SAndroid Build Coastguard Worker             // `multiplier` < 0.5; iteratively scale it up
172*bb4ee6a4SAndroid Build Coastguard Worker             // base_hz is at most 64 bits. If the loop condition passes then scaled_hz is at most 63
173*bb4ee6a4SAndroid Build Coastguard Worker             // bits, otherwise at most 64 bits. Post-loop scaled_hz is at most 64 bits.
174*bb4ee6a4SAndroid Build Coastguard Worker             scaled_hz <<= 1;
175*bb4ee6a4SAndroid Build Coastguard Worker             shift -= 1;
176*bb4ee6a4SAndroid Build Coastguard Worker         }
177*bb4ee6a4SAndroid Build Coastguard Worker     }
178*bb4ee6a4SAndroid Build Coastguard Worker     // From above, we know that the values are at most 65 bits. This provides sufficient headroom
179*bb4ee6a4SAndroid Build Coastguard Worker     // for scaled_hz << 32 below.
180*bb4ee6a4SAndroid Build Coastguard Worker     assert!(base_hz < (1u128 << 65) && scaled_hz < (1u128 << 65));
181*bb4ee6a4SAndroid Build Coastguard Worker     let mult: u32 = ((scaled_hz << 32) / base_hz)
182*bb4ee6a4SAndroid Build Coastguard Worker         .try_into()
183*bb4ee6a4SAndroid Build Coastguard Worker         .expect("should not overflow");
184*bb4ee6a4SAndroid Build Coastguard Worker     (mult, shift)
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker 
187*bb4ee6a4SAndroid Build Coastguard Worker // The config structure being exposed to the guest to tell them how much suspend time should be
188*bb4ee6a4SAndroid Build Coastguard Worker // injected to the guest's CLOCK_BOOTTIME.
189*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, Default, AsBytes, FromZeroes, FromBytes)]
190*bb4ee6a4SAndroid Build Coastguard Worker #[allow(non_camel_case_types)]
191*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
192*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pvclock_config {
193*bb4ee6a4SAndroid Build Coastguard Worker     // Total duration the VM has been paused while the guest kernel is not in the suspended state
194*bb4ee6a4SAndroid Build Coastguard Worker     // (from the power management and timekeeping perspective).
195*bb4ee6a4SAndroid Build Coastguard Worker     suspend_time_ns: Le64,
196*bb4ee6a4SAndroid Build Coastguard Worker     // Device-suggested rating of the pvclock clocksource.
197*bb4ee6a4SAndroid Build Coastguard Worker     clocksource_rating: Le32,
198*bb4ee6a4SAndroid Build Coastguard Worker     padding: u32,
199*bb4ee6a4SAndroid Build Coastguard Worker }
200*bb4ee6a4SAndroid Build Coastguard Worker 
201*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, Default, FromZeroes, FromBytes, AsBytes)]
202*bb4ee6a4SAndroid Build Coastguard Worker #[allow(non_camel_case_types)]
203*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
204*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pvclock_set_pvclock_page_req {
205*bb4ee6a4SAndroid Build Coastguard Worker     // Physical address of pvclock page.
206*bb4ee6a4SAndroid Build Coastguard Worker     pvclock_page_pa: Le64,
207*bb4ee6a4SAndroid Build Coastguard Worker     // Current system time.
208*bb4ee6a4SAndroid Build Coastguard Worker     system_time: Le64,
209*bb4ee6a4SAndroid Build Coastguard Worker     // Current tsc value.
210*bb4ee6a4SAndroid Build Coastguard Worker     tsc_timestamp: Le64,
211*bb4ee6a4SAndroid Build Coastguard Worker     // Status of this request, one of VIRTIO_PVCLOCK_S_*.
212*bb4ee6a4SAndroid Build Coastguard Worker     status: u8,
213*bb4ee6a4SAndroid Build Coastguard Worker     padding: [u8; 7],
214*bb4ee6a4SAndroid Build Coastguard Worker }
215*bb4ee6a4SAndroid Build Coastguard Worker 
216*bb4ee6a4SAndroid Build Coastguard Worker // Data structure for interacting with pvclock shared memory.
217*bb4ee6a4SAndroid Build Coastguard Worker struct PvclockSharedData {
218*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
219*bb4ee6a4SAndroid Build Coastguard Worker     seqlock_addr: GuestAddress,
220*bb4ee6a4SAndroid Build Coastguard Worker     tsc_suspended_delta_addr: GuestAddress,
221*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency_multiplier_addr: GuestAddress,
222*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency_shift_addr: GuestAddress,
223*bb4ee6a4SAndroid Build Coastguard Worker     flags_addr: GuestAddress,
224*bb4ee6a4SAndroid Build Coastguard Worker }
225*bb4ee6a4SAndroid Build Coastguard Worker 
226*bb4ee6a4SAndroid Build Coastguard Worker impl PvclockSharedData {
new(mem: GuestMemory, addr: GuestAddress) -> Self227*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(mem: GuestMemory, addr: GuestAddress) -> Self {
228*bb4ee6a4SAndroid Build Coastguard Worker         PvclockSharedData {
229*bb4ee6a4SAndroid Build Coastguard Worker             mem,
230*bb4ee6a4SAndroid Build Coastguard Worker             // The addresses of the various fields that we need to modify are relative to the
231*bb4ee6a4SAndroid Build Coastguard Worker             // base of the pvclock page. For reference, see the pvclock_vcpu_time_info struct.
232*bb4ee6a4SAndroid Build Coastguard Worker             seqlock_addr: addr,
233*bb4ee6a4SAndroid Build Coastguard Worker             tsc_suspended_delta_addr: addr.unchecked_add(8),
234*bb4ee6a4SAndroid Build Coastguard Worker             tsc_frequency_multiplier_addr: addr.unchecked_add(24),
235*bb4ee6a4SAndroid Build Coastguard Worker             tsc_frequency_shift_addr: addr.unchecked_add(28),
236*bb4ee6a4SAndroid Build Coastguard Worker             flags_addr: addr.unchecked_add(29),
237*bb4ee6a4SAndroid Build Coastguard Worker         }
238*bb4ee6a4SAndroid Build Coastguard Worker     }
239*bb4ee6a4SAndroid Build Coastguard Worker 
240*bb4ee6a4SAndroid Build Coastguard Worker     /// Only the seqlock_addr is needed to re-create this struct at restore
241*bb4ee6a4SAndroid Build Coastguard Worker     /// time, so that is all our snapshot contains.
snapshot(&self) -> GuestAddress242*bb4ee6a4SAndroid Build Coastguard Worker     fn snapshot(&self) -> GuestAddress {
243*bb4ee6a4SAndroid Build Coastguard Worker         self.seqlock_addr
244*bb4ee6a4SAndroid Build Coastguard Worker     }
245*bb4ee6a4SAndroid Build Coastguard Worker 
246*bb4ee6a4SAndroid Build Coastguard Worker     /// Set all fields to zero.
zero_fill(&mut self) -> Result<()>247*bb4ee6a4SAndroid Build Coastguard Worker     pub fn zero_fill(&mut self) -> Result<()> {
248*bb4ee6a4SAndroid Build Coastguard Worker         // The pvclock data structure is 32 bytes long, so we write 32 bytes of 0s
249*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
250*bb4ee6a4SAndroid Build Coastguard Worker             .write_all_at_addr(&[0u8; 32], self.seqlock_addr)
251*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to zero fill the pvclock shared data")
252*bb4ee6a4SAndroid Build Coastguard Worker     }
253*bb4ee6a4SAndroid Build Coastguard Worker 
increment_seqlock(&mut self) -> Result<()>254*bb4ee6a4SAndroid Build Coastguard Worker     pub fn increment_seqlock(&mut self) -> Result<()> {
255*bb4ee6a4SAndroid Build Coastguard Worker         // TODO (b/264931437): reads and writes using read/write_obj_from/at_addr are not
256*bb4ee6a4SAndroid Build Coastguard Worker         //  guaranteed to be atomic. Although this should not be a problem for the seqlock
257*bb4ee6a4SAndroid Build Coastguard Worker         //  or the other fields in the pvclock shared data (whch are protected via the seqlock)
258*bb4ee6a4SAndroid Build Coastguard Worker         //  we might want to update these calls to be as atomic as possible if/when we have
259*bb4ee6a4SAndroid Build Coastguard Worker         //  the ability to do so, just as a general cleanup and to be consistent.
260*bb4ee6a4SAndroid Build Coastguard Worker         let value = self
261*bb4ee6a4SAndroid Build Coastguard Worker             .mem
262*bb4ee6a4SAndroid Build Coastguard Worker             .read_obj_from_addr::<u32>(self.seqlock_addr)
263*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to read seqlock value")?;
264*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
265*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(value.wrapping_add(1), self.seqlock_addr)
266*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to write seqlock value")
267*bb4ee6a4SAndroid Build Coastguard Worker     }
268*bb4ee6a4SAndroid Build Coastguard Worker 
set_tsc_suspended_delta(&mut self, delta: u64) -> Result<()>269*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_tsc_suspended_delta(&mut self, delta: u64) -> Result<()> {
270*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
271*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(delta, self.tsc_suspended_delta_addr)
272*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to write tsc suspended delta")
273*bb4ee6a4SAndroid Build Coastguard Worker     }
274*bb4ee6a4SAndroid Build Coastguard Worker 
set_tsc_frequency(&mut self, frequency: u64) -> Result<()>275*bb4ee6a4SAndroid Build Coastguard Worker     pub fn set_tsc_frequency(&mut self, frequency: u64) -> Result<()> {
276*bb4ee6a4SAndroid Build Coastguard Worker         let (multiplier, shift): (u32, i8) = freq_scale_shift(1_000_000_000, frequency);
277*bb4ee6a4SAndroid Build Coastguard Worker 
278*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
279*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(multiplier, self.tsc_frequency_multiplier_addr)
280*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to write tsc frequency mlutiplier")?;
281*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
282*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(shift, self.tsc_frequency_shift_addr)
283*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to write tsc frequency shift")
284*bb4ee6a4SAndroid Build Coastguard Worker     }
285*bb4ee6a4SAndroid Build Coastguard Worker 
enable_pvclock_flags(&mut self, flags: u8) -> Result<()>286*bb4ee6a4SAndroid Build Coastguard Worker     pub fn enable_pvclock_flags(&mut self, flags: u8) -> Result<()> {
287*bb4ee6a4SAndroid Build Coastguard Worker         let value = self
288*bb4ee6a4SAndroid Build Coastguard Worker             .mem
289*bb4ee6a4SAndroid Build Coastguard Worker             .read_obj_from_addr::<u8>(self.flags_addr)
290*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to read flags")?;
291*bb4ee6a4SAndroid Build Coastguard Worker         self.mem
292*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(value | flags, self.flags_addr)
293*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to write flags")
294*bb4ee6a4SAndroid Build Coastguard Worker     }
295*bb4ee6a4SAndroid Build Coastguard Worker }
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker /// Serializable part of the [PvClock] struct which will be used by the virtio_snapshot / restore.
298*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
299*bb4ee6a4SAndroid Build Coastguard Worker struct PvClockState {
300*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency: u64,
301*bb4ee6a4SAndroid Build Coastguard Worker     /// If the device is sleeping, a [PvClockWorkerSnapshot] that can re-create the worker
302*bb4ee6a4SAndroid Build Coastguard Worker     /// will be stored here. (We can't just store the worker itself as it contains an object
303*bb4ee6a4SAndroid Build Coastguard Worker     /// tree with references to [GuestMemory].)
304*bb4ee6a4SAndroid Build Coastguard Worker     paused_main_worker: Option<PvClockWorkerSnapshot>,
305*bb4ee6a4SAndroid Build Coastguard Worker     /// The total time the vm has been suspended, this is in an `Arc<AtomicU64>>` because it's set
306*bb4ee6a4SAndroid Build Coastguard Worker     /// by the PvClockWorker thread but read by PvClock from the mmio bus in the main thread.
307*bb4ee6a4SAndroid Build Coastguard Worker     total_suspend_ns: Arc<AtomicU64>,
308*bb4ee6a4SAndroid Build Coastguard Worker     features: u64,
309*bb4ee6a4SAndroid Build Coastguard Worker     acked_features: u64,
310*bb4ee6a4SAndroid Build Coastguard Worker }
311*bb4ee6a4SAndroid Build Coastguard Worker 
312*bb4ee6a4SAndroid Build Coastguard Worker /// An enum to keep dynamic state of pvclock workers in a type safe manner.
313*bb4ee6a4SAndroid Build Coastguard Worker enum PvClockWorkerState {
314*bb4ee6a4SAndroid Build Coastguard Worker     /// Idle means no worker is running.
315*bb4ee6a4SAndroid Build Coastguard Worker     /// This tube is for communicating with this device from the crosvm threads.
316*bb4ee6a4SAndroid Build Coastguard Worker     Idle(Tube),
317*bb4ee6a4SAndroid Build Coastguard Worker     /// A stub worker to respond pvclock commands when the device is not activated yet.
318*bb4ee6a4SAndroid Build Coastguard Worker     Stub(WorkerThread<StubWorkerReturn>),
319*bb4ee6a4SAndroid Build Coastguard Worker     /// A main worker to respond pvclock commands while the device is active.
320*bb4ee6a4SAndroid Build Coastguard Worker     Main(WorkerThread<MainWorkerReturn>),
321*bb4ee6a4SAndroid Build Coastguard Worker     /// None is used only for handling transitional state between the states above.
322*bb4ee6a4SAndroid Build Coastguard Worker     None,
323*bb4ee6a4SAndroid Build Coastguard Worker }
324*bb4ee6a4SAndroid Build Coastguard Worker 
325*bb4ee6a4SAndroid Build Coastguard Worker /// A struct that represents virtio-pvclock device.
326*bb4ee6a4SAndroid Build Coastguard Worker pub struct PvClock {
327*bb4ee6a4SAndroid Build Coastguard Worker     state: PvClockState,
328*bb4ee6a4SAndroid Build Coastguard Worker     worker_state: PvClockWorkerState,
329*bb4ee6a4SAndroid Build Coastguard Worker }
330*bb4ee6a4SAndroid Build Coastguard Worker 
331*bb4ee6a4SAndroid Build Coastguard Worker impl PvClock {
new(base_features: u64, tsc_frequency: u64, suspend_tube: Tube) -> Self332*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(base_features: u64, tsc_frequency: u64, suspend_tube: Tube) -> Self {
333*bb4ee6a4SAndroid Build Coastguard Worker         let state = PvClockState {
334*bb4ee6a4SAndroid Build Coastguard Worker             tsc_frequency,
335*bb4ee6a4SAndroid Build Coastguard Worker             paused_main_worker: None,
336*bb4ee6a4SAndroid Build Coastguard Worker             total_suspend_ns: Arc::new(AtomicU64::new(0)),
337*bb4ee6a4SAndroid Build Coastguard Worker             features: base_features
338*bb4ee6a4SAndroid Build Coastguard Worker                 | 1 << VIRTIO_PVCLOCK_F_TSC_STABLE
339*bb4ee6a4SAndroid Build Coastguard Worker                 | 1 << VIRTIO_PVCLOCK_F_INJECT_SLEEP
340*bb4ee6a4SAndroid Build Coastguard Worker                 | 1 << VIRTIO_PVCLOCK_F_CLOCKSOURCE_RATING,
341*bb4ee6a4SAndroid Build Coastguard Worker             acked_features: 0,
342*bb4ee6a4SAndroid Build Coastguard Worker         };
343*bb4ee6a4SAndroid Build Coastguard Worker         PvClock {
344*bb4ee6a4SAndroid Build Coastguard Worker             state,
345*bb4ee6a4SAndroid Build Coastguard Worker             worker_state: PvClockWorkerState::Idle(suspend_tube),
346*bb4ee6a4SAndroid Build Coastguard Worker         }
347*bb4ee6a4SAndroid Build Coastguard Worker     }
348*bb4ee6a4SAndroid Build Coastguard Worker 
get_config(&self) -> virtio_pvclock_config349*bb4ee6a4SAndroid Build Coastguard Worker     fn get_config(&self) -> virtio_pvclock_config {
350*bb4ee6a4SAndroid Build Coastguard Worker         virtio_pvclock_config {
351*bb4ee6a4SAndroid Build Coastguard Worker             suspend_time_ns: self.state.total_suspend_ns.load(Ordering::SeqCst).into(),
352*bb4ee6a4SAndroid Build Coastguard Worker             clocksource_rating: VIRTIO_PVCLOCK_CLOCKSOURCE_RATING.into(),
353*bb4ee6a4SAndroid Build Coastguard Worker             padding: 0,
354*bb4ee6a4SAndroid Build Coastguard Worker         }
355*bb4ee6a4SAndroid Build Coastguard Worker     }
356*bb4ee6a4SAndroid Build Coastguard Worker 
357*bb4ee6a4SAndroid Build Coastguard Worker     /// Use switch_to_*_worker unless needed to keep the state transition consistent
start_main_worker( &mut self, interrupt: Interrupt, pvclock_worker: PvClockWorker, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>358*bb4ee6a4SAndroid Build Coastguard Worker     fn start_main_worker(
359*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
360*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
361*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_worker: PvClockWorker,
362*bb4ee6a4SAndroid Build Coastguard Worker         mut queues: BTreeMap<usize, Queue>,
363*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
364*bb4ee6a4SAndroid Build Coastguard Worker         let last_state = replace(&mut self.worker_state, PvClockWorkerState::None);
365*bb4ee6a4SAndroid Build Coastguard Worker         if let PvClockWorkerState::Idle(suspend_tube) = last_state {
366*bb4ee6a4SAndroid Build Coastguard Worker             if queues.len() != QUEUE_SIZES.len() {
367*bb4ee6a4SAndroid Build Coastguard Worker                 self.worker_state = PvClockWorkerState::Idle(suspend_tube);
368*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(anyhow!(
369*bb4ee6a4SAndroid Build Coastguard Worker                     "expected {} queues, got {}",
370*bb4ee6a4SAndroid Build Coastguard Worker                     QUEUE_SIZES.len(),
371*bb4ee6a4SAndroid Build Coastguard Worker                     queues.len()
372*bb4ee6a4SAndroid Build Coastguard Worker                 ));
373*bb4ee6a4SAndroid Build Coastguard Worker             }
374*bb4ee6a4SAndroid Build Coastguard Worker             let set_pvclock_page_queue = queues.remove(&0).unwrap();
375*bb4ee6a4SAndroid Build Coastguard Worker             self.worker_state = PvClockWorkerState::Main(WorkerThread::start(
376*bb4ee6a4SAndroid Build Coastguard Worker                 "virtio_pvclock".to_string(),
377*bb4ee6a4SAndroid Build Coastguard Worker                 move |kill_evt| {
378*bb4ee6a4SAndroid Build Coastguard Worker                     run_main_worker(
379*bb4ee6a4SAndroid Build Coastguard Worker                         pvclock_worker,
380*bb4ee6a4SAndroid Build Coastguard Worker                         set_pvclock_page_queue,
381*bb4ee6a4SAndroid Build Coastguard Worker                         suspend_tube,
382*bb4ee6a4SAndroid Build Coastguard Worker                         interrupt,
383*bb4ee6a4SAndroid Build Coastguard Worker                         kill_evt,
384*bb4ee6a4SAndroid Build Coastguard Worker                     )
385*bb4ee6a4SAndroid Build Coastguard Worker                 },
386*bb4ee6a4SAndroid Build Coastguard Worker             ));
387*bb4ee6a4SAndroid Build Coastguard Worker         } else {
388*bb4ee6a4SAndroid Build Coastguard Worker             panic!("Invalid state transition");
389*bb4ee6a4SAndroid Build Coastguard Worker         }
390*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
391*bb4ee6a4SAndroid Build Coastguard Worker     }
392*bb4ee6a4SAndroid Build Coastguard Worker 
393*bb4ee6a4SAndroid Build Coastguard Worker     /// Use switch_to_*_worker unless needed to keep the state transition consistent
start_stub_worker(&mut self)394*bb4ee6a4SAndroid Build Coastguard Worker     fn start_stub_worker(&mut self) {
395*bb4ee6a4SAndroid Build Coastguard Worker         let last_state = replace(&mut self.worker_state, PvClockWorkerState::None);
396*bb4ee6a4SAndroid Build Coastguard Worker         self.worker_state = if let PvClockWorkerState::Idle(suspend_tube) = last_state {
397*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::Stub(WorkerThread::start(
398*bb4ee6a4SAndroid Build Coastguard Worker                 "virtio_pvclock_stub".to_string(),
399*bb4ee6a4SAndroid Build Coastguard Worker                 move |kill_evt| run_stub_worker(suspend_tube, kill_evt),
400*bb4ee6a4SAndroid Build Coastguard Worker             ))
401*bb4ee6a4SAndroid Build Coastguard Worker         } else {
402*bb4ee6a4SAndroid Build Coastguard Worker             panic!("Invalid state transition");
403*bb4ee6a4SAndroid Build Coastguard Worker         };
404*bb4ee6a4SAndroid Build Coastguard Worker     }
405*bb4ee6a4SAndroid Build Coastguard Worker 
406*bb4ee6a4SAndroid Build Coastguard Worker     /// Use switch_to_*_worker unless needed to keep the state transition consistent
stop_stub_worker(&mut self)407*bb4ee6a4SAndroid Build Coastguard Worker     fn stop_stub_worker(&mut self) {
408*bb4ee6a4SAndroid Build Coastguard Worker         let last_state = replace(&mut self.worker_state, PvClockWorkerState::None);
409*bb4ee6a4SAndroid Build Coastguard Worker         self.worker_state = if let PvClockWorkerState::Stub(stub_worker_thread) = last_state {
410*bb4ee6a4SAndroid Build Coastguard Worker             let stub_worker_ret = stub_worker_thread.stop();
411*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::Idle(stub_worker_ret.suspend_tube)
412*bb4ee6a4SAndroid Build Coastguard Worker         } else {
413*bb4ee6a4SAndroid Build Coastguard Worker             panic!("Invalid state transition");
414*bb4ee6a4SAndroid Build Coastguard Worker         }
415*bb4ee6a4SAndroid Build Coastguard Worker     }
416*bb4ee6a4SAndroid Build Coastguard Worker 
417*bb4ee6a4SAndroid Build Coastguard Worker     /// Use switch_to_*_worker unless needed to keep the state transition consistent
stop_main_worker(&mut self)418*bb4ee6a4SAndroid Build Coastguard Worker     fn stop_main_worker(&mut self) {
419*bb4ee6a4SAndroid Build Coastguard Worker         let last_state = replace(&mut self.worker_state, PvClockWorkerState::None);
420*bb4ee6a4SAndroid Build Coastguard Worker         if let PvClockWorkerState::Main(main_worker_thread) = last_state {
421*bb4ee6a4SAndroid Build Coastguard Worker             let main_worker_ret = main_worker_thread.stop();
422*bb4ee6a4SAndroid Build Coastguard Worker             self.worker_state = PvClockWorkerState::Idle(main_worker_ret.suspend_tube);
423*bb4ee6a4SAndroid Build Coastguard Worker             let mut queues = BTreeMap::new();
424*bb4ee6a4SAndroid Build Coastguard Worker             queues.insert(0, main_worker_ret.set_pvclock_page_queue);
425*bb4ee6a4SAndroid Build Coastguard Worker             self.state.paused_main_worker = Some(main_worker_ret.worker.into());
426*bb4ee6a4SAndroid Build Coastguard Worker         } else {
427*bb4ee6a4SAndroid Build Coastguard Worker             panic!("Invalid state transition");
428*bb4ee6a4SAndroid Build Coastguard Worker         }
429*bb4ee6a4SAndroid Build Coastguard Worker     }
430*bb4ee6a4SAndroid Build Coastguard Worker 
switch_to_stub_worker(&mut self)431*bb4ee6a4SAndroid Build Coastguard Worker     fn switch_to_stub_worker(&mut self) {
432*bb4ee6a4SAndroid Build Coastguard Worker         self.stop_main_worker();
433*bb4ee6a4SAndroid Build Coastguard Worker         self.start_stub_worker();
434*bb4ee6a4SAndroid Build Coastguard Worker     }
435*bb4ee6a4SAndroid Build Coastguard Worker 
switch_to_main_worker( &mut self, interrupt: Interrupt, pvclock_worker: PvClockWorker, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>436*bb4ee6a4SAndroid Build Coastguard Worker     fn switch_to_main_worker(
437*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
438*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
439*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_worker: PvClockWorker,
440*bb4ee6a4SAndroid Build Coastguard Worker         queues: BTreeMap<usize, Queue>,
441*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
442*bb4ee6a4SAndroid Build Coastguard Worker         self.stop_stub_worker();
443*bb4ee6a4SAndroid Build Coastguard Worker         self.start_main_worker(interrupt, pvclock_worker, queues)
444*bb4ee6a4SAndroid Build Coastguard Worker     }
445*bb4ee6a4SAndroid Build Coastguard Worker }
446*bb4ee6a4SAndroid Build Coastguard Worker 
447*bb4ee6a4SAndroid Build Coastguard Worker /// Represents a moment in time including the TSC counter value at that time.
448*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Clone)]
449*bb4ee6a4SAndroid Build Coastguard Worker struct PvclockInstant {
450*bb4ee6a4SAndroid Build Coastguard Worker     time: DateTime<Utc>,
451*bb4ee6a4SAndroid Build Coastguard Worker     tsc_value: u64,
452*bb4ee6a4SAndroid Build Coastguard Worker }
453*bb4ee6a4SAndroid Build Coastguard Worker 
454*bb4ee6a4SAndroid Build Coastguard Worker /// The unique data retained by [PvClockWorker] which can be used to re-create
455*bb4ee6a4SAndroid Build Coastguard Worker /// an identical worker.
456*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize, Clone)]
457*bb4ee6a4SAndroid Build Coastguard Worker struct PvClockWorkerSnapshot {
458*bb4ee6a4SAndroid Build Coastguard Worker     suspend_time: Option<PvclockInstant>,
459*bb4ee6a4SAndroid Build Coastguard Worker     total_suspend_tsc_delta: u64,
460*bb4ee6a4SAndroid Build Coastguard Worker     pvclock_shared_data_base_address: Option<GuestAddress>,
461*bb4ee6a4SAndroid Build Coastguard Worker }
462*bb4ee6a4SAndroid Build Coastguard Worker 
463*bb4ee6a4SAndroid Build Coastguard Worker impl From<PvClockWorker> for PvClockWorkerSnapshot {
from(worker: PvClockWorker) -> Self464*bb4ee6a4SAndroid Build Coastguard Worker     fn from(worker: PvClockWorker) -> Self {
465*bb4ee6a4SAndroid Build Coastguard Worker         PvClockWorkerSnapshot {
466*bb4ee6a4SAndroid Build Coastguard Worker             suspend_time: worker.suspend_time,
467*bb4ee6a4SAndroid Build Coastguard Worker             total_suspend_tsc_delta: worker.total_suspend_tsc_delta,
468*bb4ee6a4SAndroid Build Coastguard Worker             pvclock_shared_data_base_address: worker
469*bb4ee6a4SAndroid Build Coastguard Worker                 .pvclock_shared_data
470*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|pvclock| pvclock.snapshot()),
471*bb4ee6a4SAndroid Build Coastguard Worker         }
472*bb4ee6a4SAndroid Build Coastguard Worker     }
473*bb4ee6a4SAndroid Build Coastguard Worker }
474*bb4ee6a4SAndroid Build Coastguard Worker 
475*bb4ee6a4SAndroid Build Coastguard Worker /// Worker struct for the virtio-pvclock device.
476*bb4ee6a4SAndroid Build Coastguard Worker ///
477*bb4ee6a4SAndroid Build Coastguard Worker /// Handles virtio requests, storing information about suspend/resume, adjusting the
478*bb4ee6a4SAndroid Build Coastguard Worker /// pvclock data in shared memory, and injecting suspend durations via config
479*bb4ee6a4SAndroid Build Coastguard Worker /// changes.
480*bb4ee6a4SAndroid Build Coastguard Worker struct PvClockWorker {
481*bb4ee6a4SAndroid Build Coastguard Worker     tsc_frequency: u64,
482*bb4ee6a4SAndroid Build Coastguard Worker     // The moment the last suspend occurred.
483*bb4ee6a4SAndroid Build Coastguard Worker     suspend_time: Option<PvclockInstant>,
484*bb4ee6a4SAndroid Build Coastguard Worker     // The total time the vm has been suspended, this is in an Arc<AtomicU64>> because it's set
485*bb4ee6a4SAndroid Build Coastguard Worker     // by the PvClockWorker thread but read by PvClock from the mmio bus in the main thread.
486*bb4ee6a4SAndroid Build Coastguard Worker     total_injected_ns: Arc<AtomicU64>,
487*bb4ee6a4SAndroid Build Coastguard Worker     // The total change in the TSC value over suspensions.
488*bb4ee6a4SAndroid Build Coastguard Worker     total_suspend_tsc_delta: u64,
489*bb4ee6a4SAndroid Build Coastguard Worker     // Pvclock shared data.
490*bb4ee6a4SAndroid Build Coastguard Worker     pvclock_shared_data: Option<PvclockSharedData>,
491*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
492*bb4ee6a4SAndroid Build Coastguard Worker }
493*bb4ee6a4SAndroid Build Coastguard Worker 
494*bb4ee6a4SAndroid Build Coastguard Worker impl PvClockWorker {
new(tsc_frequency: u64, total_injected_ns: Arc<AtomicU64>, mem: GuestMemory) -> Self495*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(tsc_frequency: u64, total_injected_ns: Arc<AtomicU64>, mem: GuestMemory) -> Self {
496*bb4ee6a4SAndroid Build Coastguard Worker         PvClockWorker {
497*bb4ee6a4SAndroid Build Coastguard Worker             tsc_frequency,
498*bb4ee6a4SAndroid Build Coastguard Worker             suspend_time: None,
499*bb4ee6a4SAndroid Build Coastguard Worker             total_injected_ns,
500*bb4ee6a4SAndroid Build Coastguard Worker             total_suspend_tsc_delta: 0,
501*bb4ee6a4SAndroid Build Coastguard Worker             pvclock_shared_data: None,
502*bb4ee6a4SAndroid Build Coastguard Worker             mem,
503*bb4ee6a4SAndroid Build Coastguard Worker         }
504*bb4ee6a4SAndroid Build Coastguard Worker     }
505*bb4ee6a4SAndroid Build Coastguard Worker 
from_snapshot( tsc_frequency: u64, total_injected_ns: Arc<AtomicU64>, snap: PvClockWorkerSnapshot, mem: GuestMemory, ) -> Self506*bb4ee6a4SAndroid Build Coastguard Worker     fn from_snapshot(
507*bb4ee6a4SAndroid Build Coastguard Worker         tsc_frequency: u64,
508*bb4ee6a4SAndroid Build Coastguard Worker         total_injected_ns: Arc<AtomicU64>,
509*bb4ee6a4SAndroid Build Coastguard Worker         snap: PvClockWorkerSnapshot,
510*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
511*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Self {
512*bb4ee6a4SAndroid Build Coastguard Worker         PvClockWorker {
513*bb4ee6a4SAndroid Build Coastguard Worker             tsc_frequency,
514*bb4ee6a4SAndroid Build Coastguard Worker             suspend_time: snap.suspend_time,
515*bb4ee6a4SAndroid Build Coastguard Worker             total_injected_ns,
516*bb4ee6a4SAndroid Build Coastguard Worker             total_suspend_tsc_delta: snap.total_suspend_tsc_delta,
517*bb4ee6a4SAndroid Build Coastguard Worker             pvclock_shared_data: snap
518*bb4ee6a4SAndroid Build Coastguard Worker                 .pvclock_shared_data_base_address
519*bb4ee6a4SAndroid Build Coastguard Worker                 .map(|addr| PvclockSharedData::new(mem.clone(), addr)),
520*bb4ee6a4SAndroid Build Coastguard Worker             mem,
521*bb4ee6a4SAndroid Build Coastguard Worker         }
522*bb4ee6a4SAndroid Build Coastguard Worker     }
523*bb4ee6a4SAndroid Build Coastguard Worker 
524*bb4ee6a4SAndroid Build Coastguard Worker     /// Initialize the pvclock for initial boot. We assume that the systemtime of 0 corresponds
525*bb4ee6a4SAndroid Build Coastguard Worker     /// to the tsc time of 0, so we do not set these. We set the tsc frequency based on the vcpu
526*bb4ee6a4SAndroid Build Coastguard Worker     /// tsc frequency and we set PVCLOCK_TSC_STABLE_BIT in flags to tell the guest that it's
527*bb4ee6a4SAndroid Build Coastguard Worker     /// safe to use vcpu0's pvclock page for use by the vdso. The order of writing the different
528*bb4ee6a4SAndroid Build Coastguard Worker     /// fields doesn't matter at this point, but does matter when updating.
set_pvclock_page(&mut self, addr: u64) -> Result<()>529*bb4ee6a4SAndroid Build Coastguard Worker     fn set_pvclock_page(&mut self, addr: u64) -> Result<()> {
530*bb4ee6a4SAndroid Build Coastguard Worker         if self.pvclock_shared_data.is_some() {
531*bb4ee6a4SAndroid Build Coastguard Worker             return Err(Error::new(libc::EALREADY)).context("pvclock page already set");
532*bb4ee6a4SAndroid Build Coastguard Worker         }
533*bb4ee6a4SAndroid Build Coastguard Worker 
534*bb4ee6a4SAndroid Build Coastguard Worker         let mut shared_data = PvclockSharedData::new(self.mem.clone(), GuestAddress(addr));
535*bb4ee6a4SAndroid Build Coastguard Worker 
536*bb4ee6a4SAndroid Build Coastguard Worker         // set all fields to 0 first
537*bb4ee6a4SAndroid Build Coastguard Worker         shared_data.zero_fill()?;
538*bb4ee6a4SAndroid Build Coastguard Worker 
539*bb4ee6a4SAndroid Build Coastguard Worker         shared_data.set_tsc_frequency(self.tsc_frequency)?;
540*bb4ee6a4SAndroid Build Coastguard Worker         shared_data.enable_pvclock_flags(PVCLOCK_TSC_STABLE_BIT)?;
541*bb4ee6a4SAndroid Build Coastguard Worker 
542*bb4ee6a4SAndroid Build Coastguard Worker         self.pvclock_shared_data = Some(shared_data);
543*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
544*bb4ee6a4SAndroid Build Coastguard Worker     }
545*bb4ee6a4SAndroid Build Coastguard Worker 
suspend(&mut self)546*bb4ee6a4SAndroid Build Coastguard Worker     pub fn suspend(&mut self) {
547*bb4ee6a4SAndroid Build Coastguard Worker         if self.suspend_time.is_some() {
548*bb4ee6a4SAndroid Build Coastguard Worker             warn!("Suspend time already set, ignoring new suspend time");
549*bb4ee6a4SAndroid Build Coastguard Worker             return;
550*bb4ee6a4SAndroid Build Coastguard Worker         }
551*bb4ee6a4SAndroid Build Coastguard Worker         self.suspend_time = Some(PvclockInstant {
552*bb4ee6a4SAndroid Build Coastguard Worker             time: Utc::now(),
553*bb4ee6a4SAndroid Build Coastguard Worker             tsc_value: read_clock_counter(),
554*bb4ee6a4SAndroid Build Coastguard Worker         });
555*bb4ee6a4SAndroid Build Coastguard Worker     }
556*bb4ee6a4SAndroid Build Coastguard Worker 
resume(&mut self) -> Result<u64>557*bb4ee6a4SAndroid Build Coastguard Worker     pub fn resume(&mut self) -> Result<u64> {
558*bb4ee6a4SAndroid Build Coastguard Worker         // First, increment the sequence lock by 1 before writing to the pvclock page.
559*bb4ee6a4SAndroid Build Coastguard Worker         self.increment_pvclock_seqlock()?;
560*bb4ee6a4SAndroid Build Coastguard Worker 
561*bb4ee6a4SAndroid Build Coastguard Worker         // The guest makes sure there are memory barriers in between reads of the seqlock and other
562*bb4ee6a4SAndroid Build Coastguard Worker         // fields, we should make sure there are memory barriers in between writes of seqlock and
563*bb4ee6a4SAndroid Build Coastguard Worker         // writes to other fields.
564*bb4ee6a4SAndroid Build Coastguard Worker         std::sync::atomic::fence(Ordering::SeqCst);
565*bb4ee6a4SAndroid Build Coastguard Worker 
566*bb4ee6a4SAndroid Build Coastguard Worker         // Set the guest_stopped_bit and tsc suspended delta in pvclock struct. We only need to set
567*bb4ee6a4SAndroid Build Coastguard Worker         // the bit, the guest will unset it once the guest has handled the stoppage.
568*bb4ee6a4SAndroid Build Coastguard Worker         // We get the result here because we want to call increment_pvclock_seqlock regardless of
569*bb4ee6a4SAndroid Build Coastguard Worker         // the result of these calls.
570*bb4ee6a4SAndroid Build Coastguard Worker         let result = self
571*bb4ee6a4SAndroid Build Coastguard Worker             .set_guest_stopped_bit()
572*bb4ee6a4SAndroid Build Coastguard Worker             .and_then(|_| self.set_suspended_time());
573*bb4ee6a4SAndroid Build Coastguard Worker 
574*bb4ee6a4SAndroid Build Coastguard Worker         // The guest makes sure there are memory barriers in between reads of the seqlock and other
575*bb4ee6a4SAndroid Build Coastguard Worker         // fields, we should make sure there are memory barriers in between writes of seqlock and
576*bb4ee6a4SAndroid Build Coastguard Worker         // writes to other fields.
577*bb4ee6a4SAndroid Build Coastguard Worker         std::sync::atomic::fence(Ordering::SeqCst);
578*bb4ee6a4SAndroid Build Coastguard Worker 
579*bb4ee6a4SAndroid Build Coastguard Worker         // Do a final increment once changes are done.
580*bb4ee6a4SAndroid Build Coastguard Worker         self.increment_pvclock_seqlock()?;
581*bb4ee6a4SAndroid Build Coastguard Worker 
582*bb4ee6a4SAndroid Build Coastguard Worker         result
583*bb4ee6a4SAndroid Build Coastguard Worker     }
584*bb4ee6a4SAndroid Build Coastguard Worker 
get_suspended_duration(suspend_time: &PvclockInstant) -> Duration585*bb4ee6a4SAndroid Build Coastguard Worker     fn get_suspended_duration(suspend_time: &PvclockInstant) -> Duration {
586*bb4ee6a4SAndroid Build Coastguard Worker         match Utc::now().signed_duration_since(suspend_time.time).to_std() {
587*bb4ee6a4SAndroid Build Coastguard Worker             Ok(duration) => duration,
588*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
589*bb4ee6a4SAndroid Build Coastguard Worker                 error!(
590*bb4ee6a4SAndroid Build Coastguard Worker                     "pvclock found suspend time in the future (was the host \
591*bb4ee6a4SAndroid Build Coastguard Worker                     clock adjusted?). Guest boot/realtime clock may now be \
592*bb4ee6a4SAndroid Build Coastguard Worker                     incorrect. Details: {}",
593*bb4ee6a4SAndroid Build Coastguard Worker                     e
594*bb4ee6a4SAndroid Build Coastguard Worker                 );
595*bb4ee6a4SAndroid Build Coastguard Worker                 Duration::ZERO
596*bb4ee6a4SAndroid Build Coastguard Worker             }
597*bb4ee6a4SAndroid Build Coastguard Worker         }
598*bb4ee6a4SAndroid Build Coastguard Worker     }
599*bb4ee6a4SAndroid Build Coastguard Worker 
set_suspended_time(&mut self) -> Result<u64>600*bb4ee6a4SAndroid Build Coastguard Worker     fn set_suspended_time(&mut self) -> Result<u64> {
601*bb4ee6a4SAndroid Build Coastguard Worker         let (this_suspend_duration, this_suspend_tsc_delta) =
602*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(suspend_time) = self.suspend_time.take() {
603*bb4ee6a4SAndroid Build Coastguard Worker                 (
604*bb4ee6a4SAndroid Build Coastguard Worker                     Self::get_suspended_duration(&suspend_time),
605*bb4ee6a4SAndroid Build Coastguard Worker                     // NB: This calculation may wrap around, as TSC can be reset to zero when
606*bb4ee6a4SAndroid Build Coastguard Worker                     // the device has resumed from the "deep" suspend state (it may not happen for
607*bb4ee6a4SAndroid Build Coastguard Worker                     // s2idle cases). It also happens when the tsc value itself wraps.
608*bb4ee6a4SAndroid Build Coastguard Worker                     read_clock_counter().wrapping_sub(suspend_time.tsc_value),
609*bb4ee6a4SAndroid Build Coastguard Worker                 )
610*bb4ee6a4SAndroid Build Coastguard Worker             } else {
611*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(Error::new(libc::ENOTSUP))
612*bb4ee6a4SAndroid Build Coastguard Worker                     .context("Cannot set suspend time because suspend was never called");
613*bb4ee6a4SAndroid Build Coastguard Worker             };
614*bb4ee6a4SAndroid Build Coastguard Worker 
615*bb4ee6a4SAndroid Build Coastguard Worker         // update the total tsc delta during all suspends
616*bb4ee6a4SAndroid Build Coastguard Worker         // NB: This calculation may wrap around, as the suspend time can be bigger than u64 range.
617*bb4ee6a4SAndroid Build Coastguard Worker         self.total_suspend_tsc_delta = self
618*bb4ee6a4SAndroid Build Coastguard Worker             .total_suspend_tsc_delta
619*bb4ee6a4SAndroid Build Coastguard Worker             .wrapping_add(this_suspend_tsc_delta);
620*bb4ee6a4SAndroid Build Coastguard Worker 
621*bb4ee6a4SAndroid Build Coastguard Worker         // save tsc_suspended_delta to shared memory
622*bb4ee6a4SAndroid Build Coastguard Worker         self.pvclock_shared_data
623*bb4ee6a4SAndroid Build Coastguard Worker             .as_mut()
624*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(
625*bb4ee6a4SAndroid Build Coastguard Worker                 anyhow::Error::new(Error::new(libc::ENODATA)).context("pvclock page is not set"),
626*bb4ee6a4SAndroid Build Coastguard Worker             )?
627*bb4ee6a4SAndroid Build Coastguard Worker             .set_tsc_suspended_delta(self.total_suspend_tsc_delta)?;
628*bb4ee6a4SAndroid Build Coastguard Worker 
629*bb4ee6a4SAndroid Build Coastguard Worker         info!(
630*bb4ee6a4SAndroid Build Coastguard Worker             "set total suspend tsc delta to {}",
631*bb4ee6a4SAndroid Build Coastguard Worker             self.total_suspend_tsc_delta
632*bb4ee6a4SAndroid Build Coastguard Worker         );
633*bb4ee6a4SAndroid Build Coastguard Worker 
634*bb4ee6a4SAndroid Build Coastguard Worker         // update total suspend ns
635*bb4ee6a4SAndroid Build Coastguard Worker         self.total_injected_ns
636*bb4ee6a4SAndroid Build Coastguard Worker             .fetch_add(this_suspend_duration.as_nanos() as u64, Ordering::SeqCst);
637*bb4ee6a4SAndroid Build Coastguard Worker 
638*bb4ee6a4SAndroid Build Coastguard Worker         Ok(self.total_suspend_tsc_delta)
639*bb4ee6a4SAndroid Build Coastguard Worker     }
640*bb4ee6a4SAndroid Build Coastguard Worker 
increment_pvclock_seqlock(&mut self) -> Result<()>641*bb4ee6a4SAndroid Build Coastguard Worker     fn increment_pvclock_seqlock(&mut self) -> Result<()> {
642*bb4ee6a4SAndroid Build Coastguard Worker         self.pvclock_shared_data
643*bb4ee6a4SAndroid Build Coastguard Worker             .as_mut()
644*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(
645*bb4ee6a4SAndroid Build Coastguard Worker                 anyhow::Error::new(Error::new(libc::ENODATA)).context("pvclock page is not set"),
646*bb4ee6a4SAndroid Build Coastguard Worker             )?
647*bb4ee6a4SAndroid Build Coastguard Worker             .increment_seqlock()
648*bb4ee6a4SAndroid Build Coastguard Worker     }
649*bb4ee6a4SAndroid Build Coastguard Worker 
set_guest_stopped_bit(&mut self) -> Result<()>650*bb4ee6a4SAndroid Build Coastguard Worker     fn set_guest_stopped_bit(&mut self) -> Result<()> {
651*bb4ee6a4SAndroid Build Coastguard Worker         self.pvclock_shared_data
652*bb4ee6a4SAndroid Build Coastguard Worker             .as_mut()
653*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(
654*bb4ee6a4SAndroid Build Coastguard Worker                 anyhow::Error::new(Error::new(libc::ENODATA)).context("pvclock page is not set"),
655*bb4ee6a4SAndroid Build Coastguard Worker             )?
656*bb4ee6a4SAndroid Build Coastguard Worker             .enable_pvclock_flags(PVCLOCK_GUEST_STOPPED)
657*bb4ee6a4SAndroid Build Coastguard Worker     }
658*bb4ee6a4SAndroid Build Coastguard Worker }
659*bb4ee6a4SAndroid Build Coastguard Worker 
pvclock_response_error_from_anyhow(error: anyhow::Error) -> base::Error660*bb4ee6a4SAndroid Build Coastguard Worker fn pvclock_response_error_from_anyhow(error: anyhow::Error) -> base::Error {
661*bb4ee6a4SAndroid Build Coastguard Worker     for cause in error.chain() {
662*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(e) = cause.downcast_ref::<base::Error>() {
663*bb4ee6a4SAndroid Build Coastguard Worker             return *e;
664*bb4ee6a4SAndroid Build Coastguard Worker         }
665*bb4ee6a4SAndroid Build Coastguard Worker 
666*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(e) = cause.downcast_ref::<GuestMemoryError>() {
667*bb4ee6a4SAndroid Build Coastguard Worker             return match e {
668*bb4ee6a4SAndroid Build Coastguard Worker                 // Two kinds of GuestMemoryError contain base::Error
669*bb4ee6a4SAndroid Build Coastguard Worker                 GuestMemoryError::MemoryAddSealsFailed(e) => *e,
670*bb4ee6a4SAndroid Build Coastguard Worker                 GuestMemoryError::MemoryCreationFailed(e) => *e,
671*bb4ee6a4SAndroid Build Coastguard Worker                 // Otherwise return EINVAL
672*bb4ee6a4SAndroid Build Coastguard Worker                 _ => Error::new(libc::EINVAL),
673*bb4ee6a4SAndroid Build Coastguard Worker             };
674*bb4ee6a4SAndroid Build Coastguard Worker         }
675*bb4ee6a4SAndroid Build Coastguard Worker     }
676*bb4ee6a4SAndroid Build Coastguard Worker     // Unknown base error
677*bb4ee6a4SAndroid Build Coastguard Worker     Error::new(libc::EFAULT)
678*bb4ee6a4SAndroid Build Coastguard Worker }
679*bb4ee6a4SAndroid Build Coastguard Worker 
680*bb4ee6a4SAndroid Build Coastguard Worker struct StubWorkerReturn {
681*bb4ee6a4SAndroid Build Coastguard Worker     suspend_tube: Tube,
682*bb4ee6a4SAndroid Build Coastguard Worker }
683*bb4ee6a4SAndroid Build Coastguard Worker 
684*bb4ee6a4SAndroid Build Coastguard Worker /// A stub worker to respond any requests when the device is inactive.
run_stub_worker(suspend_tube: Tube, kill_evt: Event) -> StubWorkerReturn685*bb4ee6a4SAndroid Build Coastguard Worker fn run_stub_worker(suspend_tube: Tube, kill_evt: Event) -> StubWorkerReturn {
686*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(EventToken, Debug)]
687*bb4ee6a4SAndroid Build Coastguard Worker     enum Token {
688*bb4ee6a4SAndroid Build Coastguard Worker         SomePvClockRequest,
689*bb4ee6a4SAndroid Build Coastguard Worker         Kill,
690*bb4ee6a4SAndroid Build Coastguard Worker     }
691*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
692*bb4ee6a4SAndroid Build Coastguard Worker         (suspend_tube.get_read_notifier(), Token::SomePvClockRequest),
693*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(b/242743502): Can also close on Tube closure for Unix once CloseNotifier is
694*bb4ee6a4SAndroid Build Coastguard Worker         // implemented for Tube.
695*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
696*bb4ee6a4SAndroid Build Coastguard Worker         (suspend_tube.get_close_notifier(), Token::Kill),
697*bb4ee6a4SAndroid Build Coastguard Worker         (&kill_evt, Token::Kill),
698*bb4ee6a4SAndroid Build Coastguard Worker     ]) {
699*bb4ee6a4SAndroid Build Coastguard Worker         Ok(wait_ctx) => wait_ctx,
700*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
701*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed creating WaitContext: {}", e);
702*bb4ee6a4SAndroid Build Coastguard Worker             return StubWorkerReturn { suspend_tube };
703*bb4ee6a4SAndroid Build Coastguard Worker         }
704*bb4ee6a4SAndroid Build Coastguard Worker     };
705*bb4ee6a4SAndroid Build Coastguard Worker     'wait: loop {
706*bb4ee6a4SAndroid Build Coastguard Worker         let events = match wait_ctx.wait() {
707*bb4ee6a4SAndroid Build Coastguard Worker             Ok(v) => v,
708*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
709*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed polling for events: {}", e);
710*bb4ee6a4SAndroid Build Coastguard Worker                 break;
711*bb4ee6a4SAndroid Build Coastguard Worker             }
712*bb4ee6a4SAndroid Build Coastguard Worker         };
713*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
714*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
715*bb4ee6a4SAndroid Build Coastguard Worker                 Token::SomePvClockRequest => {
716*bb4ee6a4SAndroid Build Coastguard Worker                     match suspend_tube.recv::<PvClockCommand>() {
717*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(req) => req,
718*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => {
719*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to receive request: {}", e);
720*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
721*bb4ee6a4SAndroid Build Coastguard Worker                         }
722*bb4ee6a4SAndroid Build Coastguard Worker                     };
723*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = suspend_tube.send(&PvClockCommandResponse::DeviceInactive) {
724*bb4ee6a4SAndroid Build Coastguard Worker                         error!("error sending PvClockCommandResponse: {}", e);
725*bb4ee6a4SAndroid Build Coastguard Worker                     }
726*bb4ee6a4SAndroid Build Coastguard Worker                 }
727*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Kill => {
728*bb4ee6a4SAndroid Build Coastguard Worker                     break 'wait;
729*bb4ee6a4SAndroid Build Coastguard Worker                 }
730*bb4ee6a4SAndroid Build Coastguard Worker             }
731*bb4ee6a4SAndroid Build Coastguard Worker         }
732*bb4ee6a4SAndroid Build Coastguard Worker     }
733*bb4ee6a4SAndroid Build Coastguard Worker     StubWorkerReturn { suspend_tube }
734*bb4ee6a4SAndroid Build Coastguard Worker }
735*bb4ee6a4SAndroid Build Coastguard Worker 
736*bb4ee6a4SAndroid Build Coastguard Worker struct MainWorkerReturn {
737*bb4ee6a4SAndroid Build Coastguard Worker     worker: PvClockWorker,
738*bb4ee6a4SAndroid Build Coastguard Worker     set_pvclock_page_queue: Queue,
739*bb4ee6a4SAndroid Build Coastguard Worker     suspend_tube: Tube,
740*bb4ee6a4SAndroid Build Coastguard Worker }
741*bb4ee6a4SAndroid Build Coastguard Worker 
742*bb4ee6a4SAndroid Build Coastguard Worker // TODO(b/237300012): asyncify this device.
743*bb4ee6a4SAndroid Build Coastguard Worker /// A worker to process PvClockCommand requests
run_main_worker( mut worker: PvClockWorker, mut set_pvclock_page_queue: Queue, suspend_tube: Tube, interrupt: Interrupt, kill_evt: Event, ) -> MainWorkerReturn744*bb4ee6a4SAndroid Build Coastguard Worker fn run_main_worker(
745*bb4ee6a4SAndroid Build Coastguard Worker     mut worker: PvClockWorker,
746*bb4ee6a4SAndroid Build Coastguard Worker     mut set_pvclock_page_queue: Queue,
747*bb4ee6a4SAndroid Build Coastguard Worker     suspend_tube: Tube,
748*bb4ee6a4SAndroid Build Coastguard Worker     interrupt: Interrupt,
749*bb4ee6a4SAndroid Build Coastguard Worker     kill_evt: Event,
750*bb4ee6a4SAndroid Build Coastguard Worker ) -> MainWorkerReturn {
751*bb4ee6a4SAndroid Build Coastguard Worker     #[derive(EventToken)]
752*bb4ee6a4SAndroid Build Coastguard Worker     enum Token {
753*bb4ee6a4SAndroid Build Coastguard Worker         SetPvClockPageQueue,
754*bb4ee6a4SAndroid Build Coastguard Worker         SuspendResume,
755*bb4ee6a4SAndroid Build Coastguard Worker         InterruptResample,
756*bb4ee6a4SAndroid Build Coastguard Worker         Kill,
757*bb4ee6a4SAndroid Build Coastguard Worker     }
758*bb4ee6a4SAndroid Build Coastguard Worker 
759*bb4ee6a4SAndroid Build Coastguard Worker     let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
760*bb4ee6a4SAndroid Build Coastguard Worker         (set_pvclock_page_queue.event(), Token::SetPvClockPageQueue),
761*bb4ee6a4SAndroid Build Coastguard Worker         (suspend_tube.get_read_notifier(), Token::SuspendResume),
762*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(b/242743502): Can also close on Tube closure for Unix once CloseNotifier is
763*bb4ee6a4SAndroid Build Coastguard Worker         // implemented for Tube.
764*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
765*bb4ee6a4SAndroid Build Coastguard Worker         (suspend_tube.get_close_notifier(), Token::Kill),
766*bb4ee6a4SAndroid Build Coastguard Worker         (&kill_evt, Token::Kill),
767*bb4ee6a4SAndroid Build Coastguard Worker     ]) {
768*bb4ee6a4SAndroid Build Coastguard Worker         Ok(pc) => pc,
769*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
770*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed creating WaitContext: {}", e);
771*bb4ee6a4SAndroid Build Coastguard Worker             return MainWorkerReturn {
772*bb4ee6a4SAndroid Build Coastguard Worker                 suspend_tube,
773*bb4ee6a4SAndroid Build Coastguard Worker                 set_pvclock_page_queue,
774*bb4ee6a4SAndroid Build Coastguard Worker                 worker,
775*bb4ee6a4SAndroid Build Coastguard Worker             };
776*bb4ee6a4SAndroid Build Coastguard Worker         }
777*bb4ee6a4SAndroid Build Coastguard Worker     };
778*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(resample_evt) = interrupt.get_resample_evt() {
779*bb4ee6a4SAndroid Build Coastguard Worker         if wait_ctx
780*bb4ee6a4SAndroid Build Coastguard Worker             .add(resample_evt, Token::InterruptResample)
781*bb4ee6a4SAndroid Build Coastguard Worker             .is_err()
782*bb4ee6a4SAndroid Build Coastguard Worker         {
783*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed creating WaitContext");
784*bb4ee6a4SAndroid Build Coastguard Worker             return MainWorkerReturn {
785*bb4ee6a4SAndroid Build Coastguard Worker                 suspend_tube,
786*bb4ee6a4SAndroid Build Coastguard Worker                 set_pvclock_page_queue,
787*bb4ee6a4SAndroid Build Coastguard Worker                 worker,
788*bb4ee6a4SAndroid Build Coastguard Worker             };
789*bb4ee6a4SAndroid Build Coastguard Worker         }
790*bb4ee6a4SAndroid Build Coastguard Worker     }
791*bb4ee6a4SAndroid Build Coastguard Worker 
792*bb4ee6a4SAndroid Build Coastguard Worker     'wait: loop {
793*bb4ee6a4SAndroid Build Coastguard Worker         let events = match wait_ctx.wait() {
794*bb4ee6a4SAndroid Build Coastguard Worker             Ok(v) => v,
795*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
796*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed polling for events: {}", e);
797*bb4ee6a4SAndroid Build Coastguard Worker                 break;
798*bb4ee6a4SAndroid Build Coastguard Worker             }
799*bb4ee6a4SAndroid Build Coastguard Worker         };
800*bb4ee6a4SAndroid Build Coastguard Worker 
801*bb4ee6a4SAndroid Build Coastguard Worker         for event in events.iter().filter(|e| e.is_readable) {
802*bb4ee6a4SAndroid Build Coastguard Worker             match event.token {
803*bb4ee6a4SAndroid Build Coastguard Worker                 Token::SetPvClockPageQueue => {
804*bb4ee6a4SAndroid Build Coastguard Worker                     let _ = set_pvclock_page_queue.event().wait();
805*bb4ee6a4SAndroid Build Coastguard Worker                     let desc_chain = match set_pvclock_page_queue.pop() {
806*bb4ee6a4SAndroid Build Coastguard Worker                         Some(desc_chain) => desc_chain,
807*bb4ee6a4SAndroid Build Coastguard Worker                         None => {
808*bb4ee6a4SAndroid Build Coastguard Worker                             error!("set_pvclock_page queue was empty");
809*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
810*bb4ee6a4SAndroid Build Coastguard Worker                         }
811*bb4ee6a4SAndroid Build Coastguard Worker                     };
812*bb4ee6a4SAndroid Build Coastguard Worker 
813*bb4ee6a4SAndroid Build Coastguard Worker                     // This device does not follow the virtio spec requirements for device-readable
814*bb4ee6a4SAndroid Build Coastguard Worker                     // vs. device-writable descriptors, so we can't use `Reader`/`Writer`. Pick the
815*bb4ee6a4SAndroid Build Coastguard Worker                     // first descriptor from the chain and assume the whole req structure is
816*bb4ee6a4SAndroid Build Coastguard Worker                     // contained within it.
817*bb4ee6a4SAndroid Build Coastguard Worker                     let desc = desc_chain
818*bb4ee6a4SAndroid Build Coastguard Worker                         .reader
819*bb4ee6a4SAndroid Build Coastguard Worker                         .get_remaining_regions()
820*bb4ee6a4SAndroid Build Coastguard Worker                         .chain(desc_chain.writer.get_remaining_regions())
821*bb4ee6a4SAndroid Build Coastguard Worker                         .next()
822*bb4ee6a4SAndroid Build Coastguard Worker                         .unwrap();
823*bb4ee6a4SAndroid Build Coastguard Worker 
824*bb4ee6a4SAndroid Build Coastguard Worker                     let len = if desc.len < size_of::<virtio_pvclock_set_pvclock_page_req>() {
825*bb4ee6a4SAndroid Build Coastguard Worker                         error!("pvclock descriptor too short");
826*bb4ee6a4SAndroid Build Coastguard Worker                         0
827*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
828*bb4ee6a4SAndroid Build Coastguard Worker                         let addr = GuestAddress(desc.offset);
829*bb4ee6a4SAndroid Build Coastguard Worker                         let mut req: virtio_pvclock_set_pvclock_page_req = match worker
830*bb4ee6a4SAndroid Build Coastguard Worker                             .mem
831*bb4ee6a4SAndroid Build Coastguard Worker                             .read_obj_from_addr(addr)
832*bb4ee6a4SAndroid Build Coastguard Worker                         {
833*bb4ee6a4SAndroid Build Coastguard Worker                             Ok(req) => req,
834*bb4ee6a4SAndroid Build Coastguard Worker                             Err(e) => {
835*bb4ee6a4SAndroid Build Coastguard Worker                                 error!("failed to read request from set_pvclock_page queue: {}", e);
836*bb4ee6a4SAndroid Build Coastguard Worker                                 continue;
837*bb4ee6a4SAndroid Build Coastguard Worker                             }
838*bb4ee6a4SAndroid Build Coastguard Worker                         };
839*bb4ee6a4SAndroid Build Coastguard Worker 
840*bb4ee6a4SAndroid Build Coastguard Worker                         req.status = match worker.set_pvclock_page(req.pvclock_page_pa.into()) {
841*bb4ee6a4SAndroid Build Coastguard Worker                             Err(e) => {
842*bb4ee6a4SAndroid Build Coastguard Worker                                 error!("failed to set pvclock page: {:#}", e);
843*bb4ee6a4SAndroid Build Coastguard Worker                                 VIRTIO_PVCLOCK_S_IOERR
844*bb4ee6a4SAndroid Build Coastguard Worker                             }
845*bb4ee6a4SAndroid Build Coastguard Worker                             Ok(_) => VIRTIO_PVCLOCK_S_OK,
846*bb4ee6a4SAndroid Build Coastguard Worker                         };
847*bb4ee6a4SAndroid Build Coastguard Worker 
848*bb4ee6a4SAndroid Build Coastguard Worker                         if let Err(e) = worker.mem.write_obj_at_addr(req, addr) {
849*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to write set_pvclock_page status: {}", e);
850*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
851*bb4ee6a4SAndroid Build Coastguard Worker                         }
852*bb4ee6a4SAndroid Build Coastguard Worker 
853*bb4ee6a4SAndroid Build Coastguard Worker                         desc.len as u32
854*bb4ee6a4SAndroid Build Coastguard Worker                     };
855*bb4ee6a4SAndroid Build Coastguard Worker 
856*bb4ee6a4SAndroid Build Coastguard Worker                     set_pvclock_page_queue.add_used(desc_chain, len);
857*bb4ee6a4SAndroid Build Coastguard Worker                     set_pvclock_page_queue.trigger_interrupt();
858*bb4ee6a4SAndroid Build Coastguard Worker                 }
859*bb4ee6a4SAndroid Build Coastguard Worker                 Token::SuspendResume => {
860*bb4ee6a4SAndroid Build Coastguard Worker                     let req = match suspend_tube.recv::<PvClockCommand>() {
861*bb4ee6a4SAndroid Build Coastguard Worker                         Ok(req) => req,
862*bb4ee6a4SAndroid Build Coastguard Worker                         Err(e) => {
863*bb4ee6a4SAndroid Build Coastguard Worker                             error!("failed to receive request: {}", e);
864*bb4ee6a4SAndroid Build Coastguard Worker                             continue;
865*bb4ee6a4SAndroid Build Coastguard Worker                         }
866*bb4ee6a4SAndroid Build Coastguard Worker                     };
867*bb4ee6a4SAndroid Build Coastguard Worker 
868*bb4ee6a4SAndroid Build Coastguard Worker                     let resp = match req {
869*bb4ee6a4SAndroid Build Coastguard Worker                         PvClockCommand::Suspend => {
870*bb4ee6a4SAndroid Build Coastguard Worker                             worker.suspend();
871*bb4ee6a4SAndroid Build Coastguard Worker                             PvClockCommandResponse::Ok
872*bb4ee6a4SAndroid Build Coastguard Worker                         }
873*bb4ee6a4SAndroid Build Coastguard Worker                         PvClockCommand::Resume => {
874*bb4ee6a4SAndroid Build Coastguard Worker                             match worker.resume() {
875*bb4ee6a4SAndroid Build Coastguard Worker                                 Ok(total_suspended_ticks) => {
876*bb4ee6a4SAndroid Build Coastguard Worker                                     // signal to the driver that the total_suspend_ns has changed
877*bb4ee6a4SAndroid Build Coastguard Worker                                     interrupt.signal_config_changed();
878*bb4ee6a4SAndroid Build Coastguard Worker                                     PvClockCommandResponse::Resumed {
879*bb4ee6a4SAndroid Build Coastguard Worker                                         total_suspended_ticks,
880*bb4ee6a4SAndroid Build Coastguard Worker                                     }
881*bb4ee6a4SAndroid Build Coastguard Worker                                 }
882*bb4ee6a4SAndroid Build Coastguard Worker                                 Err(e) => {
883*bb4ee6a4SAndroid Build Coastguard Worker                                     error!("Failed to resume pvclock: {:#}", e);
884*bb4ee6a4SAndroid Build Coastguard Worker                                     PvClockCommandResponse::Err(pvclock_response_error_from_anyhow(
885*bb4ee6a4SAndroid Build Coastguard Worker                                         e,
886*bb4ee6a4SAndroid Build Coastguard Worker                                     ))
887*bb4ee6a4SAndroid Build Coastguard Worker                                 }
888*bb4ee6a4SAndroid Build Coastguard Worker                             }
889*bb4ee6a4SAndroid Build Coastguard Worker                         }
890*bb4ee6a4SAndroid Build Coastguard Worker                     };
891*bb4ee6a4SAndroid Build Coastguard Worker 
892*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = suspend_tube.send(&resp) {
893*bb4ee6a4SAndroid Build Coastguard Worker                         error!("error sending PvClockCommandResponse: {}", e);
894*bb4ee6a4SAndroid Build Coastguard Worker                     }
895*bb4ee6a4SAndroid Build Coastguard Worker                 }
896*bb4ee6a4SAndroid Build Coastguard Worker 
897*bb4ee6a4SAndroid Build Coastguard Worker                 Token::InterruptResample => {
898*bb4ee6a4SAndroid Build Coastguard Worker                     interrupt.interrupt_resample();
899*bb4ee6a4SAndroid Build Coastguard Worker                 }
900*bb4ee6a4SAndroid Build Coastguard Worker                 Token::Kill => {
901*bb4ee6a4SAndroid Build Coastguard Worker                     break 'wait;
902*bb4ee6a4SAndroid Build Coastguard Worker                 }
903*bb4ee6a4SAndroid Build Coastguard Worker             }
904*bb4ee6a4SAndroid Build Coastguard Worker         }
905*bb4ee6a4SAndroid Build Coastguard Worker     }
906*bb4ee6a4SAndroid Build Coastguard Worker 
907*bb4ee6a4SAndroid Build Coastguard Worker     MainWorkerReturn {
908*bb4ee6a4SAndroid Build Coastguard Worker         suspend_tube,
909*bb4ee6a4SAndroid Build Coastguard Worker         set_pvclock_page_queue,
910*bb4ee6a4SAndroid Build Coastguard Worker         worker,
911*bb4ee6a4SAndroid Build Coastguard Worker     }
912*bb4ee6a4SAndroid Build Coastguard Worker }
913*bb4ee6a4SAndroid Build Coastguard Worker 
914*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for PvClock {
keep_rds(&self) -> Vec<RawDescriptor>915*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds(&self) -> Vec<RawDescriptor> {
916*bb4ee6a4SAndroid Build Coastguard Worker         if let PvClockWorkerState::Idle(suspend_tube) = &self.worker_state {
917*bb4ee6a4SAndroid Build Coastguard Worker             vec![suspend_tube.as_raw_descriptor()]
918*bb4ee6a4SAndroid Build Coastguard Worker         } else {
919*bb4ee6a4SAndroid Build Coastguard Worker             Vec::new()
920*bb4ee6a4SAndroid Build Coastguard Worker         }
921*bb4ee6a4SAndroid Build Coastguard Worker     }
922*bb4ee6a4SAndroid Build Coastguard Worker 
device_type(&self) -> DeviceType923*bb4ee6a4SAndroid Build Coastguard Worker     fn device_type(&self) -> DeviceType {
924*bb4ee6a4SAndroid Build Coastguard Worker         DeviceType::Pvclock
925*bb4ee6a4SAndroid Build Coastguard Worker     }
926*bb4ee6a4SAndroid Build Coastguard Worker 
queue_max_sizes(&self) -> &[u16]927*bb4ee6a4SAndroid Build Coastguard Worker     fn queue_max_sizes(&self) -> &[u16] {
928*bb4ee6a4SAndroid Build Coastguard Worker         QUEUE_SIZES
929*bb4ee6a4SAndroid Build Coastguard Worker     }
930*bb4ee6a4SAndroid Build Coastguard Worker 
features(&self) -> u64931*bb4ee6a4SAndroid Build Coastguard Worker     fn features(&self) -> u64 {
932*bb4ee6a4SAndroid Build Coastguard Worker         self.state.features
933*bb4ee6a4SAndroid Build Coastguard Worker     }
934*bb4ee6a4SAndroid Build Coastguard Worker 
ack_features(&mut self, mut value: u64)935*bb4ee6a4SAndroid Build Coastguard Worker     fn ack_features(&mut self, mut value: u64) {
936*bb4ee6a4SAndroid Build Coastguard Worker         if value & !self.features() != 0 {
937*bb4ee6a4SAndroid Build Coastguard Worker             warn!("virtio-pvclock got unknown feature ack {:x}", value);
938*bb4ee6a4SAndroid Build Coastguard Worker             value &= self.features();
939*bb4ee6a4SAndroid Build Coastguard Worker         }
940*bb4ee6a4SAndroid Build Coastguard Worker         self.state.acked_features |= value;
941*bb4ee6a4SAndroid Build Coastguard Worker     }
942*bb4ee6a4SAndroid Build Coastguard Worker 
read_config(&self, offset: u64, data: &mut [u8])943*bb4ee6a4SAndroid Build Coastguard Worker     fn read_config(&self, offset: u64, data: &mut [u8]) {
944*bb4ee6a4SAndroid Build Coastguard Worker         copy_config(data, 0, self.get_config().as_bytes(), offset);
945*bb4ee6a4SAndroid Build Coastguard Worker     }
946*bb4ee6a4SAndroid Build Coastguard Worker 
write_config(&mut self, offset: u64, data: &[u8])947*bb4ee6a4SAndroid Build Coastguard Worker     fn write_config(&mut self, offset: u64, data: &[u8]) {
948*bb4ee6a4SAndroid Build Coastguard Worker         // Pvclock device doesn't expect a guest write to config
949*bb4ee6a4SAndroid Build Coastguard Worker         warn!(
950*bb4ee6a4SAndroid Build Coastguard Worker             "Unexpected write to virtio-pvclock config at offset {}: {:?}",
951*bb4ee6a4SAndroid Build Coastguard Worker             offset, data
952*bb4ee6a4SAndroid Build Coastguard Worker         );
953*bb4ee6a4SAndroid Build Coastguard Worker     }
954*bb4ee6a4SAndroid Build Coastguard Worker 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>955*bb4ee6a4SAndroid Build Coastguard Worker     fn activate(
956*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
957*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
958*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
959*bb4ee6a4SAndroid Build Coastguard Worker         queues: BTreeMap<usize, Queue>,
960*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
961*bb4ee6a4SAndroid Build Coastguard Worker         let tsc_frequency = self.state.tsc_frequency;
962*bb4ee6a4SAndroid Build Coastguard Worker         let total_suspend_ns = self.state.total_suspend_ns.clone();
963*bb4ee6a4SAndroid Build Coastguard Worker         let worker = PvClockWorker::new(tsc_frequency, total_suspend_ns, mem);
964*bb4ee6a4SAndroid Build Coastguard Worker         self.switch_to_main_worker(interrupt, worker, queues)
965*bb4ee6a4SAndroid Build Coastguard Worker     }
966*bb4ee6a4SAndroid Build Coastguard Worker 
reset(&mut self) -> Result<()>967*bb4ee6a4SAndroid Build Coastguard Worker     fn reset(&mut self) -> Result<()> {
968*bb4ee6a4SAndroid Build Coastguard Worker         self.switch_to_stub_worker();
969*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
970*bb4ee6a4SAndroid Build Coastguard Worker     }
971*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>972*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
973*bb4ee6a4SAndroid Build Coastguard Worker         let last_state = replace(&mut self.worker_state, PvClockWorkerState::None);
974*bb4ee6a4SAndroid Build Coastguard Worker         match last_state {
975*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::Main(main_worker_thread) => {
976*bb4ee6a4SAndroid Build Coastguard Worker                 let main_worker_ret = main_worker_thread.stop();
977*bb4ee6a4SAndroid Build Coastguard Worker                 let mut queues = BTreeMap::new();
978*bb4ee6a4SAndroid Build Coastguard Worker                 queues.insert(0, main_worker_ret.set_pvclock_page_queue);
979*bb4ee6a4SAndroid Build Coastguard Worker                 self.worker_state = PvClockWorkerState::Idle(main_worker_ret.suspend_tube);
980*bb4ee6a4SAndroid Build Coastguard Worker                 self.state.paused_main_worker = Some(main_worker_ret.worker.into());
981*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(Some(queues))
982*bb4ee6a4SAndroid Build Coastguard Worker             }
983*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::Stub(stub_worker_thread) => {
984*bb4ee6a4SAndroid Build Coastguard Worker                 let stub_ret = stub_worker_thread.stop();
985*bb4ee6a4SAndroid Build Coastguard Worker                 self.worker_state = PvClockWorkerState::Idle(stub_ret.suspend_tube);
986*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(None)
987*bb4ee6a4SAndroid Build Coastguard Worker             }
988*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::Idle(suspend_tube) => {
989*bb4ee6a4SAndroid Build Coastguard Worker                 self.worker_state = PvClockWorkerState::Idle(suspend_tube);
990*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(None)
991*bb4ee6a4SAndroid Build Coastguard Worker             }
992*bb4ee6a4SAndroid Build Coastguard Worker             PvClockWorkerState::None => panic!("invalid state transition"),
993*bb4ee6a4SAndroid Build Coastguard Worker         }
994*bb4ee6a4SAndroid Build Coastguard Worker     }
995*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_wake( &mut self, queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>996*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_wake(
997*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
998*bb4ee6a4SAndroid Build Coastguard Worker         queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
999*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
1000*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((mem, interrupt, queues)) = queues_state {
1001*bb4ee6a4SAndroid Build Coastguard Worker             let worker_snap = self
1002*bb4ee6a4SAndroid Build Coastguard Worker                 .state
1003*bb4ee6a4SAndroid Build Coastguard Worker                 .paused_main_worker
1004*bb4ee6a4SAndroid Build Coastguard Worker                 .take()
1005*bb4ee6a4SAndroid Build Coastguard Worker                 .ok_or(anyhow!("a sleeping pvclock must have a paused worker"))?;
1006*bb4ee6a4SAndroid Build Coastguard Worker             let worker = PvClockWorker::from_snapshot(
1007*bb4ee6a4SAndroid Build Coastguard Worker                 self.state.tsc_frequency,
1008*bb4ee6a4SAndroid Build Coastguard Worker                 self.state.total_suspend_ns.clone(),
1009*bb4ee6a4SAndroid Build Coastguard Worker                 worker_snap,
1010*bb4ee6a4SAndroid Build Coastguard Worker                 mem,
1011*bb4ee6a4SAndroid Build Coastguard Worker             );
1012*bb4ee6a4SAndroid Build Coastguard Worker             // Use unchecked as no worker is running at this point
1013*bb4ee6a4SAndroid Build Coastguard Worker             self.start_main_worker(interrupt, worker, queues)?;
1014*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1015*bb4ee6a4SAndroid Build Coastguard Worker             // If the device wasn't activated, we should bring up the stub worker since that's
1016*bb4ee6a4SAndroid Build Coastguard Worker             // what is supposed to be running for an un-activated device.
1017*bb4ee6a4SAndroid Build Coastguard Worker             self.start_stub_worker();
1018*bb4ee6a4SAndroid Build Coastguard Worker         }
1019*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1020*bb4ee6a4SAndroid Build Coastguard Worker     }
1021*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>1022*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
1023*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::to_value(&self.state).context("failed to serialize PvClockState")
1024*bb4ee6a4SAndroid Build Coastguard Worker     }
1025*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>1026*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
1027*bb4ee6a4SAndroid Build Coastguard Worker         let state: PvClockState = serde_json::from_value(data).context("error deserializing")?;
1028*bb4ee6a4SAndroid Build Coastguard Worker         if state.features != self.features() {
1029*bb4ee6a4SAndroid Build Coastguard Worker             bail!(
1030*bb4ee6a4SAndroid Build Coastguard Worker                 "expected virtio_features to match, but they did not. Live: {:?}, snapshot {:?}",
1031*bb4ee6a4SAndroid Build Coastguard Worker                 self.features(),
1032*bb4ee6a4SAndroid Build Coastguard Worker                 state.features,
1033*bb4ee6a4SAndroid Build Coastguard Worker             );
1034*bb4ee6a4SAndroid Build Coastguard Worker         }
1035*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(b/291346907): we assume that the TSC frequency has NOT changed
1036*bb4ee6a4SAndroid Build Coastguard Worker         // since the snapshot was made. Assuming we have not moved machines,
1037*bb4ee6a4SAndroid Build Coastguard Worker         // this is a reasonable assumption. We don't verify the frequency
1038*bb4ee6a4SAndroid Build Coastguard Worker         // because TSC calibration noisy.
1039*bb4ee6a4SAndroid Build Coastguard Worker         self.state = state;
1040*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1041*bb4ee6a4SAndroid Build Coastguard Worker     }
1042*bb4ee6a4SAndroid Build Coastguard Worker 
on_device_sandboxed(&mut self)1043*bb4ee6a4SAndroid Build Coastguard Worker     fn on_device_sandboxed(&mut self) {
1044*bb4ee6a4SAndroid Build Coastguard Worker         self.start_stub_worker();
1045*bb4ee6a4SAndroid Build Coastguard Worker     }
1046*bb4ee6a4SAndroid Build Coastguard Worker }
1047*bb4ee6a4SAndroid Build Coastguard Worker 
1048*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
1049*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
1050*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
1051*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::QueueConfig;
1052*bb4ee6a4SAndroid Build Coastguard Worker 
1053*bb4ee6a4SAndroid Build Coastguard Worker     const TEST_QUEUE_SIZE: u16 = 2048;
1054*bb4ee6a4SAndroid Build Coastguard Worker 
make_interrupt() -> Interrupt1055*bb4ee6a4SAndroid Build Coastguard Worker     fn make_interrupt() -> Interrupt {
1056*bb4ee6a4SAndroid Build Coastguard Worker         Interrupt::new_for_test()
1057*bb4ee6a4SAndroid Build Coastguard Worker     }
1058*bb4ee6a4SAndroid Build Coastguard Worker 
create_pvclock_device() -> (Tube, PvClock)1059*bb4ee6a4SAndroid Build Coastguard Worker     fn create_pvclock_device() -> (Tube, PvClock) {
1060*bb4ee6a4SAndroid Build Coastguard Worker         let (host_tube, device_tube) = Tube::pair().unwrap();
1061*bb4ee6a4SAndroid Build Coastguard Worker         let mut pvclock_device = PvClock::new(0, 1e9 as u64, device_tube);
1062*bb4ee6a4SAndroid Build Coastguard Worker 
1063*bb4ee6a4SAndroid Build Coastguard Worker         // Simulate the device initialization to start the stub thread.
1064*bb4ee6a4SAndroid Build Coastguard Worker         // In the real case, on_device_sandboxed will be called after the device is sandboxed
1065*bb4ee6a4SAndroid Build Coastguard Worker         // (or at some point during the device initializtion when the sandbox is disabled) to
1066*bb4ee6a4SAndroid Build Coastguard Worker         // allow devices to use multi-threads (as spawning new threads before sandboxing is
1067*bb4ee6a4SAndroid Build Coastguard Worker         // prohibited because of the minijail's restriction).
1068*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device.on_device_sandboxed();
1069*bb4ee6a4SAndroid Build Coastguard Worker 
1070*bb4ee6a4SAndroid Build Coastguard Worker         (host_tube, pvclock_device)
1071*bb4ee6a4SAndroid Build Coastguard Worker     }
1072*bb4ee6a4SAndroid Build Coastguard Worker 
create_sleeping_device() -> (PvClock, GuestMemory, Tube)1073*bb4ee6a4SAndroid Build Coastguard Worker     fn create_sleeping_device() -> (PvClock, GuestMemory, Tube) {
1074*bb4ee6a4SAndroid Build Coastguard Worker         let (_host_tube, mut pvclock_device) = create_pvclock_device();
1075*bb4ee6a4SAndroid Build Coastguard Worker 
1076*bb4ee6a4SAndroid Build Coastguard Worker         // The queue won't actually be used, so passing one that isn't
1077*bb4ee6a4SAndroid Build Coastguard Worker         // fully configured is fine.
1078*bb4ee6a4SAndroid Build Coastguard Worker         let mut fake_queue = QueueConfig::new(TEST_QUEUE_SIZE, 0);
1079*bb4ee6a4SAndroid Build Coastguard Worker         fake_queue.set_ready(true);
1080*bb4ee6a4SAndroid Build Coastguard Worker         let mem = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
1081*bb4ee6a4SAndroid Build Coastguard Worker         let interrupt = make_interrupt();
1082*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device
1083*bb4ee6a4SAndroid Build Coastguard Worker             .activate(
1084*bb4ee6a4SAndroid Build Coastguard Worker                 mem.clone(),
1085*bb4ee6a4SAndroid Build Coastguard Worker                 interrupt.clone(),
1086*bb4ee6a4SAndroid Build Coastguard Worker                 BTreeMap::from([(
1087*bb4ee6a4SAndroid Build Coastguard Worker                     0,
1088*bb4ee6a4SAndroid Build Coastguard Worker                     fake_queue
1089*bb4ee6a4SAndroid Build Coastguard Worker                         .activate(&mem, Event::new().unwrap(), interrupt)
1090*bb4ee6a4SAndroid Build Coastguard Worker                         .unwrap(),
1091*bb4ee6a4SAndroid Build Coastguard Worker                 )]),
1092*bb4ee6a4SAndroid Build Coastguard Worker             )
1093*bb4ee6a4SAndroid Build Coastguard Worker             .expect("activate should succeed");
1094*bb4ee6a4SAndroid Build Coastguard Worker         let queues = pvclock_device
1095*bb4ee6a4SAndroid Build Coastguard Worker             .virtio_sleep()
1096*bb4ee6a4SAndroid Build Coastguard Worker             .expect("sleep should succeed")
1097*bb4ee6a4SAndroid Build Coastguard Worker             .expect("sleep should yield queues");
1098*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(queues.len(), 1);
1099*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1100*bb4ee6a4SAndroid Build Coastguard Worker             queues.get(&0).expect("queue must be present").size(),
1101*bb4ee6a4SAndroid Build Coastguard Worker             TEST_QUEUE_SIZE
1102*bb4ee6a4SAndroid Build Coastguard Worker         );
1103*bb4ee6a4SAndroid Build Coastguard Worker         assert!(pvclock_device.state.paused_main_worker.is_some());
1104*bb4ee6a4SAndroid Build Coastguard Worker         (pvclock_device, mem, _host_tube)
1105*bb4ee6a4SAndroid Build Coastguard Worker     }
1106*bb4ee6a4SAndroid Build Coastguard Worker 
assert_wake_successful(pvclock_device: &mut PvClock, mem: &GuestMemory)1107*bb4ee6a4SAndroid Build Coastguard Worker     fn assert_wake_successful(pvclock_device: &mut PvClock, mem: &GuestMemory) {
1108*bb4ee6a4SAndroid Build Coastguard Worker         // We just create a new queue here, because it isn't actually accessed
1109*bb4ee6a4SAndroid Build Coastguard Worker         // by the device in these tests.
1110*bb4ee6a4SAndroid Build Coastguard Worker         let mut wake_queues = BTreeMap::new();
1111*bb4ee6a4SAndroid Build Coastguard Worker         let mut fake_queue = QueueConfig::new(TEST_QUEUE_SIZE, 0);
1112*bb4ee6a4SAndroid Build Coastguard Worker         let interrupt = make_interrupt();
1113*bb4ee6a4SAndroid Build Coastguard Worker         fake_queue.set_ready(true);
1114*bb4ee6a4SAndroid Build Coastguard Worker         wake_queues.insert(
1115*bb4ee6a4SAndroid Build Coastguard Worker             0,
1116*bb4ee6a4SAndroid Build Coastguard Worker             fake_queue
1117*bb4ee6a4SAndroid Build Coastguard Worker                 .activate(mem, Event::new().unwrap(), interrupt.clone())
1118*bb4ee6a4SAndroid Build Coastguard Worker                 .unwrap(),
1119*bb4ee6a4SAndroid Build Coastguard Worker         );
1120*bb4ee6a4SAndroid Build Coastguard Worker         let queues_state = (mem.clone(), interrupt, wake_queues);
1121*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device
1122*bb4ee6a4SAndroid Build Coastguard Worker             .virtio_wake(Some(queues_state))
1123*bb4ee6a4SAndroid Build Coastguard Worker             .expect("wake should succeed");
1124*bb4ee6a4SAndroid Build Coastguard Worker         assert!(pvclock_device.state.paused_main_worker.is_none());
1125*bb4ee6a4SAndroid Build Coastguard Worker     }
1126*bb4ee6a4SAndroid Build Coastguard Worker 
1127*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_command_response_when_inactive()1128*bb4ee6a4SAndroid Build Coastguard Worker     fn test_command_response_when_inactive() {
1129*bb4ee6a4SAndroid Build Coastguard Worker         let (host_tube, _pvclock_device) = create_pvclock_device();
1130*bb4ee6a4SAndroid Build Coastguard Worker         assert!(host_tube.send(&PvClockCommand::Suspend).is_ok());
1131*bb4ee6a4SAndroid Build Coastguard Worker         let res = host_tube.recv::<PvClockCommandResponse>();
1132*bb4ee6a4SAndroid Build Coastguard Worker         assert!(matches!(res, Ok(PvClockCommandResponse::DeviceInactive)));
1133*bb4ee6a4SAndroid Build Coastguard Worker     }
1134*bb4ee6a4SAndroid Build Coastguard Worker 
1135*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_sleep_wake_smoke()1136*bb4ee6a4SAndroid Build Coastguard Worker     fn test_sleep_wake_smoke() {
1137*bb4ee6a4SAndroid Build Coastguard Worker         let (mut pvclock_device, mem, _tube) = create_sleeping_device();
1138*bb4ee6a4SAndroid Build Coastguard Worker         assert_wake_successful(&mut pvclock_device, &mem);
1139*bb4ee6a4SAndroid Build Coastguard Worker     }
1140*bb4ee6a4SAndroid Build Coastguard Worker 
1141*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_save_restore()1142*bb4ee6a4SAndroid Build Coastguard Worker     fn test_save_restore() {
1143*bb4ee6a4SAndroid Build Coastguard Worker         let (mut pvclock_device, mem, _tube) = create_sleeping_device();
1144*bb4ee6a4SAndroid Build Coastguard Worker         let test_suspend_ns = 9999;
1145*bb4ee6a4SAndroid Build Coastguard Worker 
1146*bb4ee6a4SAndroid Build Coastguard Worker         // Store a test value we can look for later in the test to verify
1147*bb4ee6a4SAndroid Build Coastguard Worker         // we're restoring properties.
1148*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device
1149*bb4ee6a4SAndroid Build Coastguard Worker             .state
1150*bb4ee6a4SAndroid Build Coastguard Worker             .total_suspend_ns
1151*bb4ee6a4SAndroid Build Coastguard Worker             .store(test_suspend_ns, Ordering::SeqCst);
1152*bb4ee6a4SAndroid Build Coastguard Worker 
1153*bb4ee6a4SAndroid Build Coastguard Worker         let snap = pvclock_device.virtio_snapshot().unwrap();
1154*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device
1155*bb4ee6a4SAndroid Build Coastguard Worker             .state
1156*bb4ee6a4SAndroid Build Coastguard Worker             .total_suspend_ns
1157*bb4ee6a4SAndroid Build Coastguard Worker             .store(0, Ordering::SeqCst);
1158*bb4ee6a4SAndroid Build Coastguard Worker         pvclock_device.virtio_restore(snap).unwrap();
1159*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1160*bb4ee6a4SAndroid Build Coastguard Worker             pvclock_device.state.total_suspend_ns.load(Ordering::SeqCst),
1161*bb4ee6a4SAndroid Build Coastguard Worker             test_suspend_ns
1162*bb4ee6a4SAndroid Build Coastguard Worker         );
1163*bb4ee6a4SAndroid Build Coastguard Worker 
1164*bb4ee6a4SAndroid Build Coastguard Worker         assert_wake_successful(&mut pvclock_device, &mem);
1165*bb4ee6a4SAndroid Build Coastguard Worker     }
1166*bb4ee6a4SAndroid Build Coastguard Worker 
1167*bb4ee6a4SAndroid Build Coastguard Worker     /// A simplified clone of `pvclock_scale_delta` from Linux kernel to emulate
1168*bb4ee6a4SAndroid Build Coastguard Worker     /// what the kernel does when converting TSC to ktime.
pvclock_scale_tsc(mult: u32, shift: i8, tsc: u64) -> u641169*bb4ee6a4SAndroid Build Coastguard Worker     fn pvclock_scale_tsc(mult: u32, shift: i8, tsc: u64) -> u64 {
1170*bb4ee6a4SAndroid Build Coastguard Worker         let shifted = if shift < 0 {
1171*bb4ee6a4SAndroid Build Coastguard Worker             tsc >> -shift
1172*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1173*bb4ee6a4SAndroid Build Coastguard Worker             tsc << shift
1174*bb4ee6a4SAndroid Build Coastguard Worker         };
1175*bb4ee6a4SAndroid Build Coastguard Worker         let product = shifted as u128 * mult as u128;
1176*bb4ee6a4SAndroid Build Coastguard Worker         (product >> 32).try_into().expect("should not overflow")
1177*bb4ee6a4SAndroid Build Coastguard Worker     }
1178*bb4ee6a4SAndroid Build Coastguard Worker 
1179*bb4ee6a4SAndroid Build Coastguard Worker     /// Helper function for checking the behavior of `freq_scale_shift`.
check_freq_scale(f: u64, input: u64)1180*bb4ee6a4SAndroid Build Coastguard Worker     fn check_freq_scale(f: u64, input: u64) {
1181*bb4ee6a4SAndroid Build Coastguard Worker         // We only test `scaled_hz` = 1GHz because that is the only value used in the code base.
1182*bb4ee6a4SAndroid Build Coastguard Worker         let (mult, shift) = freq_scale_shift(1_000_000_000, f);
1183*bb4ee6a4SAndroid Build Coastguard Worker 
1184*bb4ee6a4SAndroid Build Coastguard Worker         let scaled = pvclock_scale_tsc(mult, shift, input);
1185*bb4ee6a4SAndroid Build Coastguard Worker 
1186*bb4ee6a4SAndroid Build Coastguard Worker         // Use relative error <= 1e-8 as the target. TSC can be huge so this isn't really a super
1187*bb4ee6a4SAndroid Build Coastguard Worker         // accurate target, and our goal is to simply sanity check the math without adding too many
1188*bb4ee6a4SAndroid Build Coastguard Worker         // requirements about rounding errors.
1189*bb4ee6a4SAndroid Build Coastguard Worker         let expected: u64 = (input as u128 * 1_000_000_000u128 / f as u128) as u64;
1190*bb4ee6a4SAndroid Build Coastguard Worker         let expected_lo: u64 = (input as u128 * 999_999_990u128 / f as u128) as u64;
1191*bb4ee6a4SAndroid Build Coastguard Worker         let expected_hi: u64 = (input as u128 * 1_000_000_010u128 / f as u128) as u64;
1192*bb4ee6a4SAndroid Build Coastguard Worker         assert!(
1193*bb4ee6a4SAndroid Build Coastguard Worker             (expected_lo..=expected_hi).contains(&scaled),
1194*bb4ee6a4SAndroid Build Coastguard Worker             "{scaled} should be close to {expected} (base_hz={f}, mult={mult}, shift={shift})"
1195*bb4ee6a4SAndroid Build Coastguard Worker         );
1196*bb4ee6a4SAndroid Build Coastguard Worker     }
1197*bb4ee6a4SAndroid Build Coastguard Worker 
1198*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_freq_scale_shift_accuracy()1199*bb4ee6a4SAndroid Build Coastguard Worker     fn test_freq_scale_shift_accuracy() {
1200*bb4ee6a4SAndroid Build Coastguard Worker         // Basic check for formula correctness: scaling `scaled_hz` to `base_hz` should yield
1201*bb4ee6a4SAndroid Build Coastguard Worker         // `base_hz`.
1202*bb4ee6a4SAndroid Build Coastguard Worker         for f in (1..=50).map(|n| n * 100_000_000) {
1203*bb4ee6a4SAndroid Build Coastguard Worker             check_freq_scale(f, f);
1204*bb4ee6a4SAndroid Build Coastguard Worker         }
1205*bb4ee6a4SAndroid Build Coastguard Worker     }
1206*bb4ee6a4SAndroid Build Coastguard Worker 
1207*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_freq_scale_shift_overflow_high_freq()1208*bb4ee6a4SAndroid Build Coastguard Worker     fn test_freq_scale_shift_overflow_high_freq() {
1209*bb4ee6a4SAndroid Build Coastguard Worker         // For scale factors < 1.0, test that we can correctly convert the maximum TSC value without
1210*bb4ee6a4SAndroid Build Coastguard Worker         // overflow. We must be able to handle values as large as it realistically can be, as the
1211*bb4ee6a4SAndroid Build Coastguard Worker         // kernel clock breaks if the calculated ktime goes backwards (b/342168920).
1212*bb4ee6a4SAndroid Build Coastguard Worker         for f in (11..=50).map(|n| n * 100_000_000) {
1213*bb4ee6a4SAndroid Build Coastguard Worker             check_freq_scale(f, u64::MAX);
1214*bb4ee6a4SAndroid Build Coastguard Worker         }
1215*bb4ee6a4SAndroid Build Coastguard Worker     }
1216*bb4ee6a4SAndroid Build Coastguard Worker 
1217*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
test_freq_scale_shift_overflow_low_freq()1218*bb4ee6a4SAndroid Build Coastguard Worker     fn test_freq_scale_shift_overflow_low_freq() {
1219*bb4ee6a4SAndroid Build Coastguard Worker         fn prev_power_of_two(n: u64) -> u64 {
1220*bb4ee6a4SAndroid Build Coastguard Worker             assert_ne!(n, 0);
1221*bb4ee6a4SAndroid Build Coastguard Worker             let highest_bit_set = 63 - n.leading_zeros();
1222*bb4ee6a4SAndroid Build Coastguard Worker             1 << highest_bit_set
1223*bb4ee6a4SAndroid Build Coastguard Worker         }
1224*bb4ee6a4SAndroid Build Coastguard Worker         // Same test as above, but for scale factors >= 1.0. The difference is that for scale
1225*bb4ee6a4SAndroid Build Coastguard Worker         // factors >= 1.0 we first round up the factor, then apply a multiplier (< 1.0). We reflect
1226*bb4ee6a4SAndroid Build Coastguard Worker         // this limitation in our tested maximum value.
1227*bb4ee6a4SAndroid Build Coastguard Worker         for f in (1..=10).map(|n| n * 100_000_000) {
1228*bb4ee6a4SAndroid Build Coastguard Worker             // Truncate the remainder since prev_power_of_two rounds down anyway.
1229*bb4ee6a4SAndroid Build Coastguard Worker             let factor = 1_000_000_000 / f;
1230*bb4ee6a4SAndroid Build Coastguard Worker             // This is like (exp2(floor(log2(factor)) + 1)).
1231*bb4ee6a4SAndroid Build Coastguard Worker             let target = u64::MAX / (prev_power_of_two(factor) << 1);
1232*bb4ee6a4SAndroid Build Coastguard Worker             check_freq_scale(f, target);
1233*bb4ee6a4SAndroid Build Coastguard Worker         }
1234*bb4ee6a4SAndroid Build Coastguard Worker     }
1235*bb4ee6a4SAndroid Build Coastguard Worker }
1236